blaze-performance-tester 3.1.13 → 3.1.15

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
@@ -85,9 +85,7 @@ var mathUtils = {
85
85
  const sorted = [...arr].sort((a, b) => a - b);
86
86
  const index = Math.ceil(p / 100 * sorted.length) - 1;
87
87
  return sorted[Math.max(0, index)];
88
- },
89
- min: (arr) => arr.length === 0 ? 0 : arr.reduce((min, val) => val < min ? val : min, arr[0]),
90
- max: (arr) => arr.length === 0 ? 0 : arr.reduce((max, val) => val > max ? val : max, arr[0])
88
+ }
91
89
  };
92
90
  async function executeTestPipeline(config) {
93
91
  if (!blazeCore || typeof blazeCore.runCorrelatedTransaction !== "function") {
@@ -141,7 +139,6 @@ function parseArguments(args) {
141
139
  const targetScript = path.resolve(args[0] || ".");
142
140
  const isAgentic = args.includes("--agentic");
143
141
  const isCorrelate = args.includes("--correlate");
144
- const isSeoEnabled = args.includes("--seo");
145
142
  const clusterLogs = !args.includes("--no-cluster-logs");
146
143
  let threads = 10;
147
144
  let durationSec = 10;
@@ -187,7 +184,6 @@ function parseArguments(args) {
187
184
  targetScript,
188
185
  isAgentic,
189
186
  isCorrelate,
190
- isSeoEnabled,
191
187
  clusterLogs,
192
188
  threads,
193
189
  durationSec,
@@ -228,9 +224,6 @@ async function runIntelligentAgenticStressTest(config) {
228
224
  let lastRawRequests = [];
229
225
  let total1xx = 0, total2xx = 0, total3xx = 0, total4xx = 0, total5xx = 0;
230
226
  let globalMetricsAccumulator = { dns: [], tcp: [], tls: [], ttfb: [], latencies: [], bandwidths: [], lcp: [], fid: [], cls: [] };
231
- let totalEconnreset = 0;
232
- let totalEconnrefused = 0;
233
- const globalCodeCounts = { 400: 0, 401: 0, 403: 0, 404: 0, 429: 0, 500: 0, 502: 0, 503: 0, 504: 0 };
234
227
  let currentThreads = Math.min(config.maxThreads, Math.max(5, Math.floor(config.maxThreads * 0.2)));
235
228
  let baseStep = config.stepSize;
236
229
  let isStable = true;
@@ -248,11 +241,6 @@ async function runIntelligentAgenticStressTest(config) {
248
241
  total3xx += metrics.c3xx;
249
242
  total4xx += metrics.c4xx;
250
243
  total5xx += metrics.c5xx;
251
- totalEconnreset += metrics.econnresetCount;
252
- totalEconnrefused += metrics.econnrefusedCount;
253
- Object.keys(globalCodeCounts).forEach((code) => {
254
- globalCodeCounts[code] += metrics.codeCounts[code] || 0;
255
- });
256
244
  globalMetricsAccumulator.dns.push(metrics.avgDnsMs);
257
245
  globalMetricsAccumulator.tcp.push(metrics.avgTcpMs);
258
246
  globalMetricsAccumulator.tls.push(metrics.avgTlsMs);
@@ -266,8 +254,6 @@ async function runIntelligentAgenticStressTest(config) {
266
254
  threads: currentThreads,
267
255
  avgLatency: metrics.avgLatencyMs,
268
256
  p95Latency: metrics.p95LatencyMs,
269
- minLatency: metrics.minLatencyMs,
270
- maxLatency: metrics.maxLatencyMs,
271
257
  errorRate: metrics.errorRate,
272
258
  apdex: metrics.apdexScore,
273
259
  throughput: metrics.requestsPerSecond,
@@ -275,10 +261,7 @@ async function runIntelligentAgenticStressTest(config) {
275
261
  failedRequests: metrics.c4xx + metrics.c5xx,
276
262
  lcp: metrics.lcpMs,
277
263
  fid: metrics.fidMs,
278
- cls: metrics.clsScore,
279
- econnresetRate: metrics.econnresetRate,
280
- econnrefusedCount: metrics.econnrefusedCount,
281
- codeRates: metrics.codeRates
264
+ cls: metrics.clsScore
282
265
  };
283
266
  printMatrixDashboard(metrics, currentThreads);
284
267
  history.push(currentState);
@@ -322,11 +305,6 @@ async function runIntelligentAgenticStressTest(config) {
322
305
  }
323
306
  const totalTestSeconds = history.length * config.durationSec;
324
307
  const vuRampUpVelocity = history.length > 1 && totalTestSeconds > 0 ? (history[history.length - 1].threads - history[0].threads) / totalTestSeconds : config.threads / config.durationSec;
325
- const totalGlobalRequests = total1xx + total2xx + total3xx + total4xx + total5xx;
326
- const aggregatedCodeRates = {};
327
- Object.keys(globalCodeCounts).forEach((code) => {
328
- aggregatedCodeRates[code] = totalGlobalRequests === 0 ? 0 : globalCodeCounts[code] / totalGlobalRequests * 100;
329
- });
330
308
  const finalSummaryCards = {
331
309
  apdex: history[history.length - 1]?.apdex || 0,
332
310
  throughput: history[history.length - 1]?.throughput || 0,
@@ -340,12 +318,7 @@ async function runIntelligentAgenticStressTest(config) {
340
318
  vuRampUpVelocity,
341
319
  lcp: mathUtils.mean(globalMetricsAccumulator.lcp),
342
320
  fid: mathUtils.mean(globalMetricsAccumulator.fid),
343
- cls: mathUtils.mean(globalMetricsAccumulator.cls),
344
- econnresetRate: totalGlobalRequests === 0 ? 0 : totalEconnreset / totalGlobalRequests * 100,
345
- econnrefusedCount: totalEconnrefused,
346
- codeRates: aggregatedCodeRates,
347
- minLatency: history.length === 0 ? 0 : Math.min(...history.map((h) => h.minLatency)),
348
- maxLatency: history.length === 0 ? 0 : Math.max(...history.map((h) => h.maxLatency))
321
+ cls: mathUtils.mean(globalMetricsAccumulator.cls)
349
322
  };
350
323
  generateFinalAgentReport(history);
351
324
  exportHtmlDashboard(history, config, verdictReason, semanticReport, { total1xx, total2xx, total3xx, total4xx, total5xx }, finalSummaryCards, lastRawRequests);
@@ -358,8 +331,6 @@ async function runStandardStressTest(config) {
358
331
  threads: config.threads,
359
332
  avgLatency: metrics.avgLatencyMs,
360
333
  p95Latency: metrics.p95LatencyMs,
361
- minLatency: metrics.minLatencyMs,
362
- maxLatency: metrics.maxLatencyMs,
363
334
  errorRate: metrics.errorRate,
364
335
  apdex: metrics.apdexScore,
365
336
  throughput: metrics.requestsPerSecond,
@@ -367,10 +338,7 @@ async function runStandardStressTest(config) {
367
338
  failedRequests: metrics.c4xx + metrics.c5xx,
368
339
  lcp: metrics.lcpMs,
369
340
  fid: metrics.fidMs,
370
- cls: metrics.clsScore,
371
- econnresetRate: metrics.econnresetRate,
372
- econnrefusedCount: metrics.econnrefusedCount,
373
- codeRates: metrics.codeRates
341
+ cls: metrics.clsScore
374
342
  }];
375
343
  let semanticReport = null;
376
344
  if (config.clusterLogs) {
@@ -392,12 +360,7 @@ async function runStandardStressTest(config) {
392
360
  vuRampUpVelocity: config.threads / config.durationSec,
393
361
  lcp: metrics.lcpMs,
394
362
  fid: metrics.fidMs,
395
- cls: metrics.clsScore,
396
- econnresetRate: metrics.econnresetRate,
397
- econnrefusedCount: metrics.econnrefusedCount,
398
- codeRates: metrics.codeRates,
399
- minLatency: metrics.minLatencyMs,
400
- maxLatency: metrics.maxLatencyMs
363
+ cls: metrics.clsScore
401
364
  };
402
365
  const isPassed = metrics.apdexScore >= config.targetApdex && metrics.errorRate <= config.targetErrorRate;
403
366
  const verdictReason = isPassed ? "Static single-wave baseline checks concluded successfully without triggering health boundaries." : "Static verification loop completed with values exceeding defined quality thresholds.";
@@ -429,29 +392,17 @@ function generateSimulationData(threads, durationSec, maxAllowedLatencyMs) {
429
392
  const isBreached = threads > targetThresholdBreak;
430
393
  const stressFactor = isBreached ? Math.pow(threads / targetThresholdBreak, 1.5) : 1;
431
394
  const errorPool = getFallbackClusterLogs();
432
- const targetFailureCodes = [400, 401, 403, 404, 429, 500, 502, 503, 504];
433
395
  for (let i = 0; i < totalRequests; i++) {
434
- const isError = Math.random() < (isBreached ? 0.08 : 5e-3);
396
+ const isError = Math.random() < (isBreached ? 0.05 : 1e-3);
435
397
  const baseLatency = (25 + Math.random() * 35) * stressFactor;
436
398
  let errorMessage;
437
399
  let statusCode = 200;
438
400
  if (isError) {
439
- const coin = Math.random();
440
- if (coin < 0.25) {
441
- statusCode = 502;
442
- errorMessage = "Error: ECONNRESET socket hang up abruptly by remote host";
443
- } else if (coin < 0.5) {
444
- statusCode = 503;
445
- errorMessage = "Error: ECONNREFUSED 127.0.0.1:8080 - connection rejected by destination target";
446
- } else {
447
- statusCode = targetFailureCodes[Math.floor(Math.random() * targetFailureCodes.length)];
448
- errorMessage = errorPool[Math.floor(Math.random() * errorPool.length)];
449
- }
450
- } else {
451
- if (Math.random() < 0.03) statusCode = 302;
401
+ statusCode = Math.random() > 0.3 ? 500 : 404;
402
+ errorMessage = errorPool[Math.floor(Math.random() * errorPool.length)];
452
403
  }
453
404
  data.push({
454
- durationMs: isError ? baseLatency * 0.1 + 2 : baseLatency + Math.random() * 20,
405
+ durationMs: isError ? baseLatency * 0.1 : baseLatency,
455
406
  timestampMs: startTime + Math.random() * (durationSec * 1e3),
456
407
  dnsTimeMs: 1 + Math.random() * 0.9,
457
408
  tcpTimeMs: 4 + Math.random() * 1.5,
@@ -468,35 +419,18 @@ function processMetricsTelemetry(requests, durationSec, apdexT) {
468
419
  const avgLatencyMs = mathUtils.mean(durations);
469
420
  const stdDevMs = mathUtils.stdDev(durations, avgLatencyMs);
470
421
  const p95LatencyMs = mathUtils.percentile(durations, 95);
471
- const minLatencyMs = mathUtils.min(durations);
472
- const maxLatencyMs = mathUtils.max(durations);
473
422
  const avgDnsMs = mathUtils.mean(requests.map((r) => r.dnsTimeMs || 0));
474
423
  const avgTcpMs = mathUtils.mean(requests.map((r) => r.tcpTimeMs || 0));
475
424
  const avgTlsMs = mathUtils.mean(requests.map((r) => r.tlsTimeMs || 0));
476
425
  const avgTtfbMs = avgDnsMs + avgTcpMs + avgTlsMs + avgLatencyMs * 0.3;
477
426
  let c1xx = 0, c2xx = 0, c3xx = 0, c4xx = 0, c5xx = 0;
478
- let econnresetCount = 0;
479
- let econnrefusedCount = 0;
480
- const codeCounts = { 400: 0, 401: 0, 403: 0, 404: 0, 429: 0, 500: 0, 502: 0, 503: 0, 504: 0 };
481
427
  requests.forEach((r) => {
482
428
  if (r.statusCode >= 100 && r.statusCode < 200) c1xx++;
483
429
  else if (r.statusCode >= 200 && r.statusCode < 300) c2xx++;
484
430
  else if (r.statusCode >= 300 && r.statusCode < 400) c3xx++;
485
431
  else if (r.statusCode >= 400 && r.statusCode < 500) c4xx++;
486
432
  else if (r.statusCode >= 500) c5xx++;
487
- if (r.statusCode in codeCounts) {
488
- codeCounts[r.statusCode]++;
489
- }
490
- if (r.errorMessage) {
491
- if (r.errorMessage.includes("ECONNRESET")) econnresetCount++;
492
- if (r.errorMessage.includes("ECONNREFUSED")) econnrefusedCount++;
493
- }
494
- });
495
- const codeRates = {};
496
- Object.keys(codeCounts).forEach((code) => {
497
- codeRates[code] = totalRequests === 0 ? 0 : codeCounts[code] / totalRequests * 100;
498
433
  });
499
- const econnresetRate = totalRequests === 0 ? 0 : econnresetCount / totalRequests * 100;
500
434
  const errorCount = c4xx + c5xx;
501
435
  const errorRate = totalRequests === 0 ? 0 : errorCount / totalRequests;
502
436
  const satisfied = requests.filter((r) => r.durationMs <= apdexT && r.statusCode < 400).length;
@@ -512,8 +446,6 @@ function processMetricsTelemetry(requests, durationSec, apdexT) {
512
446
  avgLatencyMs,
513
447
  stdDevMs,
514
448
  p95LatencyMs,
515
- minLatencyMs,
516
- maxLatencyMs,
517
449
  errorRate,
518
450
  apdexScore,
519
451
  c1xx,
@@ -528,12 +460,7 @@ function processMetricsTelemetry(requests, durationSec, apdexT) {
528
460
  bandwidthMb,
529
461
  lcpMs,
530
462
  fidMs,
531
- clsScore,
532
- econnresetCount,
533
- econnresetRate,
534
- econnrefusedCount,
535
- codeCounts,
536
- codeRates
463
+ clsScore
537
464
  };
538
465
  }
539
466
  function printMatrixDashboard(m, threads) {
@@ -543,7 +470,7 @@ function printMatrixDashboard(m, threads) {
543
470
  console.log(`-----------------------------------------------------------------------------------------`);
544
471
  console.log(`| ${pad(threads, 7)} | ${pad(m.totalRequests, 9)} | ${pad(m.avgLatencyMs.toFixed(1) + "ms", 11)} | ${pad(m.p95LatencyMs.toFixed(1) + "ms", 11)} | ${pad(m.requestsPerSecond.toFixed(0) + "/s", 10)} | ${pad((m.errorRate * 100).toFixed(2) + "%", 10)} | ${pad(m.apdexScore.toFixed(2), 9)} |`);
545
472
  console.log(`-----------------------------------------------------------------------------------------`);
546
- console.log(`| Network & Floor -> RESET: ${m.econnresetRate.toFixed(1)}% | Min/Max Boundary: ${m.minLatencyMs.toFixed(1)}ms / ${m.maxLatencyMs.toFixed(1)}ms`);
473
+ console.log(`| Simulated Web Vitals Equivalent -> LCP: ${m.lcpMs.toFixed(0)}ms | FID: ${m.fidMs.toFixed(1)}ms | CLS: ${m.clsScore.toFixed(3)} |`);
547
474
  console.log(`-----------------------------------------------------------------------------------------`);
548
475
  }
549
476
  function generateFinalAgentReport(history) {
@@ -566,7 +493,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
566
493
  const activeThreadsData = history.map((h) => h.threads);
567
494
  const ttfTrendData = history.map((h) => h.avgLatency * 1.1);
568
495
  const waveListItems = history.map((h) => {
569
- return `<div class="wave-item">Wave (${h.threads} VUs): Floor ${h.minLatency.toFixed(1)}ms | Ceil ${h.maxLatency.toFixed(1)}ms | P95 ${h.p95Latency.toFixed(1)}ms</div>`;
496
+ return `<div class="wave-item">Wave (${h.threads} VUs): P95 ${h.p95Latency.toFixed(1)}ms, Errors ${(h.errorRate * 100).toFixed(1)}%, LCP ${h.lcp.toFixed(0)}ms</div>`;
570
497
  }).join("");
571
498
  const estimatedMonthlyCost = (cards.throughput * 0.045 * 24 * 30).toFixed(2);
572
499
  const recommendedCpuCores = Math.max(2, Math.ceil(cards.saturationKneePoint / 75));
@@ -582,136 +509,6 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
582
509
  const lcpStat = getLcpStatus(cards.lcp);
583
510
  const fidStat = getFidStatus(cards.fid);
584
511
  const clsStat = getClsStatus(cards.cls);
585
- let seoPredictorPanelHtml = "";
586
- if (config.isSeoEnabled) {
587
- const lcp = cards.lcp;
588
- let seoScore = 100;
589
- let visibilityLossPct = 0;
590
- let trafficDropPct = 0;
591
- let rankDropPositions = 0;
592
- if (lcp > 2500) {
593
- if (lcp <= 4e3) {
594
- const ratio = (lcp - 2500) / 1500;
595
- seoScore = 100 - ratio * 30;
596
- visibilityLossPct = ratio * 14.5;
597
- trafficDropPct = ratio * 18.2;
598
- rankDropPositions = Number((ratio * 1.2).toFixed(1));
599
- } else {
600
- const ratio = Math.min(1, (lcp - 4e3) / 4e3);
601
- seoScore = Math.max(8, 70 - ratio * 62);
602
- visibilityLossPct = 14.5 + ratio * 52;
603
- trafficDropPct = 18.2 + ratio * 58.5;
604
- rankDropPositions = Number((1.2 + ratio * 4.6).toFixed(1));
605
- }
606
- }
607
- let seoColor = "#10b981";
608
- let seoStatus = "EXCELLENT";
609
- if (seoScore < 90) {
610
- seoColor = "#f59e0b";
611
- seoStatus = "NEEDS IMPROVEMENT";
612
- }
613
- if (seoScore < 60) {
614
- seoColor = "#ef4444";
615
- seoStatus = "CRITICAL RISK / PENALIZED";
616
- }
617
- seoPredictorPanelHtml = `
618
- <div class="card" style="margin-top: 2rem; background: #131c2e; border: 1px solid #1e293b;">
619
- <h3 style="color: #38bdf8; font-size: 1.2rem; border-bottom: none; margin-bottom: 0.25rem;">
620
- \u{1F50D} Google SEO Rank & Search Visibility Impact Predictor
621
- </h3>
622
- <div style="color: #94a3b8; font-size: 0.9rem; margin-bottom: 1.5rem;">
623
- Predictive algorithmic simulation modeling response degradation metrics directly against Google Core Web Vitals signal rules.
624
- </div>
625
-
626
- <div style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; flex-wrap: wrap;">
627
- <div style="background: #090d16; padding: 1.25rem; border-radius: 6px; border: 1px solid #1e293b; text-align: center;">
628
- <div style="font-size: 0.75rem; color: #64748b; text-transform: uppercase; font-weight: bold;">Core Web Vitals SEO Score</div>
629
- <div style="font-size: 1.8rem; font-weight: bold; color: ${seoColor}; margin-top: 0.25rem;">
630
- ${seoScore.toFixed(0)}<span style="font-size: 1rem; color: #94a3b8;">/100</span>
631
- </div>
632
- <div style="font-size: 0.75rem; font-weight: bold; margin-top: 0.4rem; color: ${seoColor};">${seoStatus}</div>
633
- </div>
634
-
635
- <div style="background: #090d16; padding: 1.25rem; border-radius: 6px; border: 1px solid #1e293b; text-align: center;">
636
- <div style="font-size: 0.75rem; color: #64748b; text-transform: uppercase; font-weight: bold;">Search Visibility Loss</div>
637
- <div style="font-size: 1.8rem; font-weight: bold; color: ${visibilityLossPct > 0 ? "#ef4444" : "#10b981"}; margin-top: 0.25rem;">
638
- -${visibilityLossPct.toFixed(1)}%
639
- </div>
640
- <div style="font-size: 0.75rem; color: #64748b; margin-top: 0.4rem;">Projected SERP Impression Drop</div>
641
- </div>
642
-
643
- <div style="background: #090d16; padding: 1.25rem; border-radius: 6px; border: 1px solid #1e293b; text-align: center;">
644
- <div style="font-size: 1.8rem; font-weight: bold; color: ${trafficDropPct > 0 ? "#ef4444" : "#10b981"}; margin-top: 0.25rem;">
645
- -${trafficDropPct.toFixed(1)}%
646
- </div>
647
- <div style="font-size: 0.75rem; color: #64748b; margin-top: 0.4rem;">Expected funnel volume drop</div>
648
- </div>
649
-
650
- <div style="background: #090d16; padding: 1.25rem; border-radius: 6px; border: 1px solid #1e293b; text-align: center;">
651
- <div style="font-size: 0.75rem; color: #64748b; text-transform: uppercase; font-weight: bold;">Avg SERP Position Shift</div>
652
- <div style="font-size: 1.8rem; font-weight: bold; color: ${rankDropPositions > 0 ? "#f59e0b" : "#10b981"}; margin-top: 0.25rem;">
653
- ${rankDropPositions > 0 ? `+${rankDropPositions}` : "0.0"}
654
- </div>
655
- <div style="font-size: 0.75rem; color: #64748b; margin-top: 0.4rem;">Rank places dropped down standard index</div>
656
- </div>
657
- </div>
658
-
659
- <div style="margin-top: 1rem; background: #090d16; padding: 1rem; border-radius: 6px; border: 1px solid #1e293b; font-size: 0.85rem; line-height: 1.5; color: #cbd5e1;">
660
- <strong>\u{1F52E} SEO Engine Intelligence Breakdown:</strong>
661
- ${lcp <= 2500 ? "Your simulated Largest Contentful Paint equivalent falls safely within Google's 'Good' range (&le; 2500ms). The parsing layer calculates zero performance-based rank penalties under current system load profiles." : lcp <= 4e3 ? `Warning: Current concurrency load has pushed LCP to ${lcp.toFixed(0)}ms, landing in Google's 'Needs Improvement' window. This response drag risks triggering index rank adjustments, potentially demoting listings down by ~${rankDropPositions} positions and sacrificing around ${trafficDropPct.toFixed(0)}% of organic top-of-funnel users.` : `Critical Signal Breach: Load performance has forced LCP to ${lcp.toFixed(0)}ms, severely violating Google's 'Poor' performance ceiling (&gt; 4000ms). At this level, ranking algorithms actively de-weight domains. Expect structural search visibility erosion up to ${visibilityLossPct.toFixed(0)}% and immediate organic traffic redirection.`}
662
- </div>
663
- </div>`;
664
- }
665
- const connectionDiagnosticsPanelHtml = `
666
- <div class="card" style="margin-top: 2rem; background: #131c2e; border: 1px solid #1e293b;">
667
- <h3 style="color: #38bdf8; font-size: 1.2rem; border-bottom: none; margin-bottom: 0.25rem;">
668
- \u{1F50C} Network Connection & Detailed HTTP Status Diagnostics
669
- </h3>
670
- <div style="color: #94a3b8; font-size: 0.9rem; margin-bottom: 1.5rem;">
671
- Real-time breakdown tracking transport anomalies and precise layer-7 distribution indicators.
672
- </div>
673
-
674
- <div style="display: grid; grid-template-columns: 1fr 2fr; gap: 2rem; flex-wrap: wrap;">
675
- <div style="display: flex; flex-direction: column; gap: 1rem;">
676
- <div style="background: #090d16; padding: 1.25rem; border-radius: 6px; border: 1px solid #1e293b;">
677
- <div style="font-size: 0.75rem; color: #64748b; text-transform: uppercase; font-weight: bold;">ECONNRESET Rate</div>
678
- <div style="font-size: 1.8rem; font-weight: bold; color: ${cards.econnresetRate > 1 ? "#ef4444" : "#10b981"};">
679
- ${cards.econnresetRate.toFixed(2)}<span style="font-size: 1rem; color: #94a3b8;"> %</span>
680
- </div>
681
- <div style="font-size: 0.8rem; color: #64748b; margin-top: 0.25rem;">Abrupt remote host termination frequency</div>
682
- </div>
683
-
684
- <div style="background: #090d16; padding: 1.25rem; border-radius: 6px; border: 1px solid #1e293b;">
685
- <div style="font-size: 0.75rem; color: #64748b; text-transform: uppercase; font-weight: bold;">ECONNREFUSED Count</div>
686
- <div style="font-size: 1.8rem; font-weight: bold; color: ${cards.econnrefusedCount > 0 ? "#f59e0b" : "#10b981"};">
687
- ${cards.econnrefusedCount}<span style="font-size: 1rem; color: #94a3b8;"> drops</span>
688
- </div>
689
- <div style="font-size: 0.8rem; color: #64748b; margin-top: 0.25rem;">Total complete backend port link rejections</div>
690
- </div>
691
- </div>
692
-
693
- <div style="background: #090d16; padding: 1.25rem; border-radius: 6px; border: 1px solid #1e293b;">
694
- <div style="font-size: 0.85rem; font-weight: bold; color: #f8fafc; margin-bottom: 1rem;">Target Response Code Matrix Rates</div>
695
- <div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem;">
696
- ${Object.keys(cards.codeRates).map((code) => {
697
- const percentage = cards.codeRates[code];
698
- let textColor = "#cbd5e1";
699
- if (percentage > 0) {
700
- textColor = code.startsWith("5") ? "#f87171" : "#fde047";
701
- }
702
- return `
703
- <div style="background: #131c2e; padding: 0.75rem; border-radius: 4px; border: 1px solid #1e293b; text-align: center;">
704
- <div style="font-size: 0.8rem; font-weight: bold; color: #94a3b8;">Code ${code}</div>
705
- <div style="font-size: 1.1rem; font-weight: bold; margin-top: 0.25rem; color: ${textColor};">
706
- ${percentage.toFixed(2)}%
707
- </div>
708
- </div>
709
- `;
710
- }).join("")}
711
- </div>
712
- </div>
713
- </div>
714
- </div>`;
715
512
  let logClustersHtml = "";
716
513
  if (semanticReport) {
717
514
  const totalLogCount = semanticReport.clusters.reduce((sum, c) => sum + c.count, 0);
@@ -722,7 +519,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
722
519
  \u{1F9E0} Interactive Remediation Playbooks & Log Classification
723
520
  </h3>
724
521
  <div style="color: #94a3b8; font-size: 0.9rem; margin-bottom: 1.5rem;">
725
- Captured <strong style="color: #f8fafc;">${totalLogCount}</strong> raw failures grouped into <strong style="color: #f8fafc;">${uniquePatternsCount}</strong> unique structural patterns.
522
+ Captured <strong style="color: #f8fafc;">${totalLogCount}</strong> raw failures grouped into <strong style="color: #f8fafc;">${uniquePatternsCount}</strong> unique structural patterns. Expand a playbook to inspect automated remediation strategies and diagnostics confidence ratings.
726
523
  </div>
727
524
 
728
525
  <div style="display: flex; flex-direction: column; gap: 1rem;">
@@ -745,11 +542,11 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
745
542
  let explanation = "High concurrency is causing socket/connection starvation. Increase connection limits or enable pooling keep-alives.";
746
543
  if (c.category === "Authentication_Error") {
747
544
  fixTitle = "Auth Token / JWT Strategy";
748
- fixCode = "// Implement token caching and silent rotation\\napp.use(authMiddleware({ cacheTtl: 300, allowGracePeriod: 60 }));";
545
+ fixCode = "// Implement token caching and silent rotation\napp.use(authMiddleware({ cacheTtl: 300, allowGracePeriod: 60 }));";
749
546
  explanation = "Frequent token verification failures under load. Extend signature verification cache or decouple auth validation check.";
750
547
  } else if (c.category === "Product_Error") {
751
548
  fixTitle = "Application Null-Safety / Guard Fix";
752
- fixCode = "const configId = payload?.config_id ?? defaultConfigurationId;\\nif (!configId) throw new ValidationError('Missing config_id');";
549
+ fixCode = "const configId = payload?.config_id ?? defaultConfigurationId;\nif (!configId) throw new ValidationError('Missing config_id');";
753
550
  explanation = "Runtime reference error for undefined payload field under race condition spikes. Add optional chaining and input contracts.";
754
551
  }
755
552
  const snippetId = `snippet-${idx}`;
@@ -839,8 +636,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
839
636
  .meta { color: #94a3b8; font-size: 0.9rem; margin-top: 0.5rem; }
840
637
 
841
638
  .section-title { font-size: 1.2rem; color: #cbd5e1; font-weight: bold; margin: 2rem 0 1rem 0; padding-bottom: 0.4rem; border-bottom: 1px solid #1e293b; }
842
- .cards-wrapper { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; margin-bottom: 1.5rem; }
843
- @media (max-width: 1024px) { .cards-wrapper { grid-template-columns: repeat(2, 1fr); } }
639
+ .cards-wrapper { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; margin-bottom: 1.5rem; }
844
640
  .metric-card { background: #131c2e; border: 1px solid #1e293b; border-radius: 6px; padding: 1.25rem; position: relative; }
845
641
  .card-title { font-size: 0.75rem; font-weight: 700; color: #64748b; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.5rem; }
846
642
  .card-value { font-size: 1.6rem; font-weight: 700; color: #ffffff; }
@@ -849,7 +645,6 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
849
645
  .card-value.orange { color: #f97316; }
850
646
  .card-value.purple { color: #a855f7; }
851
647
  .card-value.cyan { color: #38bdf8; }
852
- .card-value.red { color: #f87171; }
853
648
  .card-subtext { font-size: 0.8rem; font-weight: 500; margin-left: 0.4rem; display: inline-block; }
854
649
  .card-subtext.green { color: #10b981; }
855
650
  .card-subtext.orange { color: #f97316; }
@@ -897,20 +692,12 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
897
692
  <div class="cards-wrapper">
898
693
  <div class="metric-card">
899
694
  <div class="card-title">Apdex Score (T: ${config.apdexT}ms)</div>
900
- <div class="card-value green">${cards.apdex.toFixed(2)}<span class="card-subtext green">(Verified)</span></div>
695
+ <div class="card-value green">${cards.apdex.toFixed(2)}<span class="card-subtext green">(Target Verified)</span></div>
901
696
  </div>
902
697
  <div class="metric-card">
903
698
  <div class="card-title">Throughput</div>
904
699
  <div class="card-value orange">${cards.throughput.toFixed(1)}<span class="unit">/s</span></div>
905
700
  </div>
906
- <div class="metric-card">
907
- <div class="card-title">Minimum Response Time</div>
908
- <div class="card-value green">${cards.minLatency.toFixed(1)}<span class="unit">ms</span></div>
909
- </div>
910
- <div class="metric-card">
911
- <div class="card-title">Maximum Response Time</div>
912
- <div class="card-value red">${cards.maxLatency.toFixed(1)}<span class="unit">ms</span></div>
913
- </div>
914
701
  <div class="metric-card">
915
702
  <div class="card-title">Network Bandwidth</div>
916
703
  <div class="card-value purple">${cards.bandwidth.toFixed(2)}<span class="unit">MB/s</span></div>
@@ -1017,8 +804,8 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
1017
804
  <th>Throughput</th>
1018
805
  <th>Avg Latency</th>
1019
806
  <th>P95 Latency</th>
1020
- <th>Min / Max Floor</th>
1021
- <th>RESET Rate</th>
807
+ <th>Simulated LCP</th>
808
+ <th>Error Rate</th>
1022
809
  <th>Status</th>
1023
810
  </tr>
1024
811
  </thead>
@@ -1030,16 +817,14 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
1030
817
  <td>${h.throughput.toFixed(0)} req/sec</td>
1031
818
  <td>${h.avgLatency.toFixed(1)} ms</td>
1032
819
  <td>${h.p95Latency.toFixed(1)} ms</td>
1033
- <td><small>${h.minLatency.toFixed(1)}ms / ${h.maxLatency.toFixed(1)}ms</small></td>
1034
- <td>${h.econnresetRate.toFixed(2)}%</td>
820
+ <td>${h.lcp.toFixed(0)} ms</td>
821
+ <td>${(h.errorRate * 100).toFixed(2)}%</td>
1035
822
  <td><span class="badge ${isPassed ? "badge-success" : "badge-fail"}">${isPassed ? "SLO PASS" : "SLO BREACH"}</span></td>
1036
823
  </tr>`;
1037
824
  }).join("")}
1038
825
  </tbody>
1039
826
  </table>
1040
827
  </div>
1041
- ${seoPredictorPanelHtml}
1042
- ${connectionDiagnosticsPanelHtml}
1043
828
  ${liveAdjusterHtml}
1044
829
  ${rightSizingHtml}
1045
830
  ${logClustersHtml}
@@ -1059,6 +844,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
1059
844
  const baseThroughput = ${cards.throughput};
1060
845
  const baseLatency = ${cards.ttfb};
1061
846
 
847
+ // Live Concurrency Adjuster interactive client logic
1062
848
  const slider = document.getElementById('concurrencySlider');
1063
849
  const sliderVal = document.getElementById('sliderValue');
1064
850
  const simThroughput = document.getElementById('simThroughput');
@@ -1143,8 +929,8 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
1143
929
  },
1144
930
  scales: {
1145
931
  x: { grid: { color: '#1e293b' }, ticks: { color: '#64748b' } },
1146
- yThreads: { position: 'left', grid: { color: '#1e293b' }, ticks: { color: '#38bdf8' }, title: { display: true, text: 'VUs / Threads', color: '#38bdf8' } },
1147
- yTtf: { position: 'right', grid: { drawOnChartArea: false }, ticks: { color: '#f43f5e' }, title: { display: true, text: 'TTF Index / Latency ms', color: '#f43f5e' } }
932
+ y_threads: { position: 'left', grid: { color: '#1e293b' }, ticks: { color: '#38bdf8' }, title: { display: true, text: 'VUs / Threads', color: '#38bdf8' } },
933
+ y_ttf: { position: 'right', grid: { drawOnChartArea: false }, ticks: { color: '#f43f5e' }, title: { display: true, text: 'TTF Index / Latency ms', color: '#f43f5e' } }
1148
934
  }
1149
935
  }
1150
936
  });
@@ -1204,6 +990,6 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
1204
990
  function printUsage() {
1205
991
  console.log(`Blaze Core Performance Test CLI Engine
1206
992
  Options:
1207
- --threads <count> | --duration <seconds> | --agentic | --cluster-logs | --correlate | --apdex-t <ms> | --seo`);
993
+ --threads <count> | --duration <seconds> | --agentic | --cluster-logs | --correlate | --apdex-t <ms>`);
1208
994
  }
1209
995
  main().catch(console.error);
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blaze-performance-tester",
3
- "version": "3.1.13",
3
+ "version": "3.1.15",
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",