@railtownai/railtracks-visualizer 0.0.74 → 0.0.75

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/cjs/index.js CHANGED
@@ -13119,7 +13119,7 @@ const createLucideIcon = (iconName, iconNode)=>{
13119
13119
  return Component;
13120
13120
  };
13121
13121
 
13122
- const __iconNode$H = [
13122
+ const __iconNode$G = [
13123
13123
  [
13124
13124
  "path",
13125
13125
  {
@@ -13135,9 +13135,9 @@ const __iconNode$H = [
13135
13135
  }
13136
13136
  ]
13137
13137
  ];
13138
- const ArrowLeft = createLucideIcon("arrow-left", __iconNode$H);
13138
+ const ArrowLeft = createLucideIcon("arrow-left", __iconNode$G);
13139
13139
 
13140
- const __iconNode$G = [
13140
+ const __iconNode$F = [
13141
13141
  [
13142
13142
  "path",
13143
13143
  {
@@ -13153,9 +13153,9 @@ const __iconNode$G = [
13153
13153
  }
13154
13154
  ]
13155
13155
  ];
13156
- const ArrowRight = createLucideIcon("arrow-right", __iconNode$G);
13156
+ const ArrowRight = createLucideIcon("arrow-right", __iconNode$F);
13157
13157
 
13158
- const __iconNode$F = [
13158
+ const __iconNode$E = [
13159
13159
  [
13160
13160
  "circle",
13161
13161
  {
@@ -13175,9 +13175,9 @@ const __iconNode$F = [
13175
13175
  }
13176
13176
  ]
13177
13177
  ];
13178
- const Blend = createLucideIcon("blend", __iconNode$F);
13178
+ const Blend = createLucideIcon("blend", __iconNode$E);
13179
13179
 
13180
- const __iconNode$E = [
13180
+ const __iconNode$D = [
13181
13181
  [
13182
13182
  "path",
13183
13183
  {
@@ -13225,9 +13225,9 @@ const __iconNode$E = [
13225
13225
  }
13226
13226
  ]
13227
13227
  ];
13228
- const Bot = createLucideIcon("bot", __iconNode$E);
13228
+ const Bot = createLucideIcon("bot", __iconNode$D);
13229
13229
 
13230
- const __iconNode$D = [
13230
+ const __iconNode$C = [
13231
13231
  [
13232
13232
  "path",
13233
13233
  {
@@ -13261,9 +13261,9 @@ const __iconNode$D = [
13261
13261
  }
13262
13262
  ]
13263
13263
  ];
13264
- const Calendar = createLucideIcon("calendar", __iconNode$D);
13264
+ const Calendar = createLucideIcon("calendar", __iconNode$C);
13265
13265
 
13266
- const __iconNode$C = [
13266
+ const __iconNode$B = [
13267
13267
  [
13268
13268
  "path",
13269
13269
  {
@@ -13320,9 +13320,9 @@ const __iconNode$C = [
13320
13320
  }
13321
13321
  ]
13322
13322
  ];
13323
- const ChartNetwork = createLucideIcon("chart-network", __iconNode$C);
13323
+ const ChartNetwork = createLucideIcon("chart-network", __iconNode$B);
13324
13324
 
13325
- const __iconNode$B = [
13325
+ const __iconNode$A = [
13326
13326
  [
13327
13327
  "path",
13328
13328
  {
@@ -13331,9 +13331,9 @@ const __iconNode$B = [
13331
13331
  }
13332
13332
  ]
13333
13333
  ];
13334
- const ChevronDown = createLucideIcon("chevron-down", __iconNode$B);
13334
+ const ChevronDown = createLucideIcon("chevron-down", __iconNode$A);
13335
13335
 
13336
- const __iconNode$A = [
13336
+ const __iconNode$z = [
13337
13337
  [
13338
13338
  "path",
13339
13339
  {
@@ -13342,9 +13342,9 @@ const __iconNode$A = [
13342
13342
  }
13343
13343
  ]
13344
13344
  ];
13345
- const ChevronRight = createLucideIcon("chevron-right", __iconNode$A);
13345
+ const ChevronRight = createLucideIcon("chevron-right", __iconNode$z);
13346
13346
 
13347
- const __iconNode$z = [
13347
+ const __iconNode$y = [
13348
13348
  [
13349
13349
  "path",
13350
13350
  {
@@ -13360,9 +13360,9 @@ const __iconNode$z = [
13360
13360
  }
13361
13361
  ]
13362
13362
  ];
13363
- const ChevronsDown = createLucideIcon("chevrons-down", __iconNode$z);
13363
+ const ChevronsDown = createLucideIcon("chevrons-down", __iconNode$y);
13364
13364
 
13365
- const __iconNode$y = [
13365
+ const __iconNode$x = [
13366
13366
  [
13367
13367
  "path",
13368
13368
  {
@@ -13378,9 +13378,9 @@ const __iconNode$y = [
13378
13378
  }
13379
13379
  ]
13380
13380
  ];
13381
- const ChevronsUp = createLucideIcon("chevrons-up", __iconNode$y);
13381
+ const ChevronsUp = createLucideIcon("chevrons-up", __iconNode$x);
13382
13382
 
13383
- const __iconNode$x = [
13383
+ const __iconNode$w = [
13384
13384
  [
13385
13385
  "circle",
13386
13386
  {
@@ -13411,9 +13411,9 @@ const __iconNode$x = [
13411
13411
  }
13412
13412
  ]
13413
13413
  ];
13414
- const CircleAlert = createLucideIcon("circle-alert", __iconNode$x);
13414
+ const CircleAlert = createLucideIcon("circle-alert", __iconNode$w);
13415
13415
 
13416
- const __iconNode$w = [
13416
+ const __iconNode$v = [
13417
13417
  [
13418
13418
  "path",
13419
13419
  {
@@ -13429,9 +13429,9 @@ const __iconNode$w = [
13429
13429
  }
13430
13430
  ]
13431
13431
  ];
13432
- const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$w);
13432
+ const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$v);
13433
13433
 
13434
- const __iconNode$v = [
13434
+ const __iconNode$u = [
13435
13435
  [
13436
13436
  "circle",
13437
13437
  {
@@ -13449,9 +13449,9 @@ const __iconNode$v = [
13449
13449
  }
13450
13450
  ]
13451
13451
  ];
13452
- const CircleCheck = createLucideIcon("circle-check", __iconNode$v);
13452
+ const CircleCheck = createLucideIcon("circle-check", __iconNode$u);
13453
13453
 
13454
- const __iconNode$u = [
13454
+ const __iconNode$t = [
13455
13455
  [
13456
13456
  "circle",
13457
13457
  {
@@ -13476,27 +13476,7 @@ const __iconNode$u = [
13476
13476
  }
13477
13477
  ]
13478
13478
  ];
13479
- const CircleDollarSign = createLucideIcon("circle-dollar-sign", __iconNode$u);
13480
-
13481
- const __iconNode$t = [
13482
- [
13483
- "circle",
13484
- {
13485
- cx: "12",
13486
- cy: "12",
13487
- r: "10",
13488
- key: "1mglay"
13489
- }
13490
- ],
13491
- [
13492
- "path",
13493
- {
13494
- d: "M8 12h8",
13495
- key: "1wcyev"
13496
- }
13497
- ]
13498
- ];
13499
- const CircleMinus = createLucideIcon("circle-minus", __iconNode$t);
13479
+ const CircleDollarSign = createLucideIcon("circle-dollar-sign", __iconNode$t);
13500
13480
 
13501
13481
  const __iconNode$s = [
13502
13482
  [
@@ -121068,11 +121048,14 @@ const STATUS_ICON_SIZE = 12;
121068
121048
  partial: Blend,
121069
121049
  unclassified: null
121070
121050
  };
121071
- /** Short word shown on the collapsed accordion row. */ const STATUS_CHIP_LABEL = {
121051
+ /**
121052
+ * Short word shown on the collapsed accordion row. Unclassified carries none, for the same reason
121053
+ * it carries no icon: the chip would state a verdict the category does not have.
121054
+ */ const STATUS_CHIP_LABEL = {
121072
121055
  pass: "Pass",
121073
121056
  fail: "Fail",
121074
121057
  partial: "Partial",
121075
- unclassified: "Unclassified"
121058
+ unclassified: null
121076
121059
  };
121077
121060
  /** The neutral outlined treatment: unclassified categories, not-gated metrics, and zero counts. */ function outlinedPalette(theme) {
121078
121061
  return {
@@ -121107,10 +121090,11 @@ function statusPalette(theme, status) {
121107
121090
  }
121108
121091
  }
121109
121092
  /**
121110
- * Failure rate, formatted the way the notification formats it: an exact 0%/100% only when exact,
121111
- * so a single failure out of two hundred does not round down to a clean "0% failed".
121112
- */ function formatFailureRate(failureCount, scoredCount) {
121113
- const exact = failureCount * 100 / scoredCount;
121093
+ * Pass rate the share of scored runs that did *not* fail, so it reads with the ratio beside it
121094
+ * rather than against it. An exact 0%/100% only when exact, so a single failure out of two hundred
121095
+ * does not round up to a clean "100% passed".
121096
+ */ function formatPassRate(failureCount, scoredCount) {
121097
+ const exact = (scoredCount - failureCount) * 100 / scoredCount;
121114
121098
  const rounded = Math.round(exact);
121115
121099
  if (rounded === 0 && exact > 0) return "<1%";
121116
121100
  if (rounded === 100 && exact < 100) return ">99%";
@@ -121202,22 +121186,28 @@ const NodeRow$1 = ({ node, metricName, onAgentNodeClick, onOpenVisualizer })=>{
121202
121186
  }, "Reasoning · ", metricName), node.reasoning));
121203
121187
  };
121204
121188
  /**
121205
- * The metric's verdict, beside its name. The ratio's leading number is what did *not* fail,
121206
- * which folds partials in with the passes the same reading the notification prints.
121189
+ * The metric's verdict, beside its name: the status icon, then the pass ratio and rate. The ratio's
121190
+ * leading number is what did *not* fail, which folds partials in with the passes, and the percentage
121191
+ * is that same number as a share — the complement of the failure rate the notification prints.
121192
+ *
121193
+ * The verdict is carried by the icon and its colour alone; spelling it out beside a ratio that
121194
+ * already says the same thing only crowded the header. It stays in the tooltip and the accessible
121195
+ * name so nothing is lost to a reader who cannot resolve the icon.
121196
+ *
121197
+ * Renders nothing for a metric that is not gated, or that has nothing scored yet. Neither has a
121198
+ * ratio to state, and a placeholder pill standing in for the absent verdict only invited the
121199
+ * definitional zero failures of a not-gated metric to be read as an earned pass.
121207
121200
  */ const VerdictPill = ({ metric })=>{
121208
121201
  const { theme } = useTheme$1();
121209
121202
  const { verdict, scoredCount, failureCount } = metric;
121210
- const palette = verdict === "failed" ? statusPalette(theme, "fail") : verdict === "passed" ? statusPalette(theme, "pass") : outlinedPalette(theme);
121211
- const VerdictIcon = verdict === "failed" ? CircleX : verdict === "passed" ? CircleCheck : CircleMinus;
121212
- const text = verdict === "failed" ? "Failed" : verdict === "passed" ? "Passed" : "Not gated";
121213
- // Nothing scored yet, and a passing metric, both show the pill without a failure percentage.
121214
- let rate;
121215
- if (scoredCount > 0 && verdict === "failed") {
121216
- rate = `${scoredCount - failureCount}/${scoredCount} · ${formatFailureRate(failureCount, scoredCount)}`;
121217
- } else if (scoredCount > 0 && verdict === "passed") {
121218
- rate = `${scoredCount}/${scoredCount}`;
121219
- }
121203
+ if (verdict === "notGated" || scoredCount === 0) return null;
121204
+ const failed = verdict === "failed";
121205
+ const palette = statusPalette(theme, failed ? "fail" : "pass");
121206
+ const VerdictIcon = failed ? CircleX : CircleCheck;
121207
+ const verdictLabel = failed ? "Failed" : "Passed";
121208
+ const rate = `${scoredCount - failureCount}/${scoredCount} · ${formatPassRate(failureCount, scoredCount)}`;
121220
121209
  return /*#__PURE__*/ React.createElement("span", {
121210
+ title: verdictLabel,
121221
121211
  style: {
121222
121212
  display: "inline-flex",
121223
121213
  alignItems: "center",
@@ -121225,32 +121215,25 @@ const NodeRow$1 = ({ node, metricName, onAgentNodeClick, onOpenVisualizer })=>{
121225
121215
  padding: "3px 9px",
121226
121216
  borderRadius: 6,
121227
121217
  fontSize: 11.5,
121228
- fontWeight: 700,
121229
- letterSpacing: 0.6,
121230
- textTransform: "uppercase",
121218
+ letterSpacing: 0.2,
121231
121219
  background: palette.bg,
121232
121220
  color: palette.color,
121233
121221
  border: `1px solid ${palette.border}`
121234
121222
  }
121235
121223
  }, /*#__PURE__*/ React.createElement(VerdictIcon, {
121236
121224
  size: STATUS_ICON_SIZE,
121237
- "aria-hidden": true,
121225
+ role: "img",
121226
+ "aria-label": verdictLabel,
121238
121227
  style: {
121239
121228
  flexShrink: 0
121240
121229
  }
121241
- }), text, rate && /*#__PURE__*/ React.createElement("span", {
121242
- style: {
121243
- fontWeight: 400,
121244
- letterSpacing: 0.2,
121245
- opacity: 0.9,
121246
- textTransform: "none"
121247
- }
121248
- }, rate));
121230
+ }), rate);
121249
121231
  };
121250
121232
  const LabelPanelHeader = ({ label })=>{
121251
121233
  const { theme } = useTheme$1();
121252
121234
  const isEmpty = label.count === 0;
121253
121235
  const palette = statusPalette(theme, label.status);
121236
+ const chipLabel = STATUS_CHIP_LABEL[label.status];
121254
121237
  // A zero-count row keeps its status colour but reads as inactive, matching its disabled state.
121255
121238
  const dotColor = label.status === "unclassified" ? theme.colors.mutedForeground : palette.color;
121256
121239
  return /*#__PURE__*/ React.createElement("div", {
@@ -121274,7 +121257,7 @@ const LabelPanelHeader = ({ label })=>{
121274
121257
  fontWeight: 600,
121275
121258
  color: palette.color
121276
121259
  }
121277
- }, label.labelName), /*#__PURE__*/ React.createElement("span", {
121260
+ }, label.labelName), chipLabel && /*#__PURE__*/ React.createElement("span", {
121278
121261
  style: {
121279
121262
  fontSize: 10,
121280
121263
  letterSpacing: 0.8,
@@ -121286,7 +121269,7 @@ const LabelPanelHeader = ({ label })=>{
121286
121269
  color: palette.color,
121287
121270
  border: `1px solid ${palette.border}`
121288
121271
  }
121289
- }, STATUS_CHIP_LABEL[label.status]), /*#__PURE__*/ React.createElement("span", {
121272
+ }, chipLabel), /*#__PURE__*/ React.createElement("span", {
121290
121273
  style: {
121291
121274
  marginLeft: "auto",
121292
121275
  fontSize: 12,
package/dist/esm/index.js CHANGED
@@ -13098,7 +13098,7 @@ const createLucideIcon = (iconName, iconNode)=>{
13098
13098
  return Component;
13099
13099
  };
13100
13100
 
13101
- const __iconNode$H = [
13101
+ const __iconNode$G = [
13102
13102
  [
13103
13103
  "path",
13104
13104
  {
@@ -13114,9 +13114,9 @@ const __iconNode$H = [
13114
13114
  }
13115
13115
  ]
13116
13116
  ];
13117
- const ArrowLeft = createLucideIcon("arrow-left", __iconNode$H);
13117
+ const ArrowLeft = createLucideIcon("arrow-left", __iconNode$G);
13118
13118
 
13119
- const __iconNode$G = [
13119
+ const __iconNode$F = [
13120
13120
  [
13121
13121
  "path",
13122
13122
  {
@@ -13132,9 +13132,9 @@ const __iconNode$G = [
13132
13132
  }
13133
13133
  ]
13134
13134
  ];
13135
- const ArrowRight = createLucideIcon("arrow-right", __iconNode$G);
13135
+ const ArrowRight = createLucideIcon("arrow-right", __iconNode$F);
13136
13136
 
13137
- const __iconNode$F = [
13137
+ const __iconNode$E = [
13138
13138
  [
13139
13139
  "circle",
13140
13140
  {
@@ -13154,9 +13154,9 @@ const __iconNode$F = [
13154
13154
  }
13155
13155
  ]
13156
13156
  ];
13157
- const Blend = createLucideIcon("blend", __iconNode$F);
13157
+ const Blend = createLucideIcon("blend", __iconNode$E);
13158
13158
 
13159
- const __iconNode$E = [
13159
+ const __iconNode$D = [
13160
13160
  [
13161
13161
  "path",
13162
13162
  {
@@ -13204,9 +13204,9 @@ const __iconNode$E = [
13204
13204
  }
13205
13205
  ]
13206
13206
  ];
13207
- const Bot = createLucideIcon("bot", __iconNode$E);
13207
+ const Bot = createLucideIcon("bot", __iconNode$D);
13208
13208
 
13209
- const __iconNode$D = [
13209
+ const __iconNode$C = [
13210
13210
  [
13211
13211
  "path",
13212
13212
  {
@@ -13240,9 +13240,9 @@ const __iconNode$D = [
13240
13240
  }
13241
13241
  ]
13242
13242
  ];
13243
- const Calendar = createLucideIcon("calendar", __iconNode$D);
13243
+ const Calendar = createLucideIcon("calendar", __iconNode$C);
13244
13244
 
13245
- const __iconNode$C = [
13245
+ const __iconNode$B = [
13246
13246
  [
13247
13247
  "path",
13248
13248
  {
@@ -13299,9 +13299,9 @@ const __iconNode$C = [
13299
13299
  }
13300
13300
  ]
13301
13301
  ];
13302
- const ChartNetwork = createLucideIcon("chart-network", __iconNode$C);
13302
+ const ChartNetwork = createLucideIcon("chart-network", __iconNode$B);
13303
13303
 
13304
- const __iconNode$B = [
13304
+ const __iconNode$A = [
13305
13305
  [
13306
13306
  "path",
13307
13307
  {
@@ -13310,9 +13310,9 @@ const __iconNode$B = [
13310
13310
  }
13311
13311
  ]
13312
13312
  ];
13313
- const ChevronDown = createLucideIcon("chevron-down", __iconNode$B);
13313
+ const ChevronDown = createLucideIcon("chevron-down", __iconNode$A);
13314
13314
 
13315
- const __iconNode$A = [
13315
+ const __iconNode$z = [
13316
13316
  [
13317
13317
  "path",
13318
13318
  {
@@ -13321,9 +13321,9 @@ const __iconNode$A = [
13321
13321
  }
13322
13322
  ]
13323
13323
  ];
13324
- const ChevronRight = createLucideIcon("chevron-right", __iconNode$A);
13324
+ const ChevronRight = createLucideIcon("chevron-right", __iconNode$z);
13325
13325
 
13326
- const __iconNode$z = [
13326
+ const __iconNode$y = [
13327
13327
  [
13328
13328
  "path",
13329
13329
  {
@@ -13339,9 +13339,9 @@ const __iconNode$z = [
13339
13339
  }
13340
13340
  ]
13341
13341
  ];
13342
- const ChevronsDown = createLucideIcon("chevrons-down", __iconNode$z);
13342
+ const ChevronsDown = createLucideIcon("chevrons-down", __iconNode$y);
13343
13343
 
13344
- const __iconNode$y = [
13344
+ const __iconNode$x = [
13345
13345
  [
13346
13346
  "path",
13347
13347
  {
@@ -13357,9 +13357,9 @@ const __iconNode$y = [
13357
13357
  }
13358
13358
  ]
13359
13359
  ];
13360
- const ChevronsUp = createLucideIcon("chevrons-up", __iconNode$y);
13360
+ const ChevronsUp = createLucideIcon("chevrons-up", __iconNode$x);
13361
13361
 
13362
- const __iconNode$x = [
13362
+ const __iconNode$w = [
13363
13363
  [
13364
13364
  "circle",
13365
13365
  {
@@ -13390,9 +13390,9 @@ const __iconNode$x = [
13390
13390
  }
13391
13391
  ]
13392
13392
  ];
13393
- const CircleAlert = createLucideIcon("circle-alert", __iconNode$x);
13393
+ const CircleAlert = createLucideIcon("circle-alert", __iconNode$w);
13394
13394
 
13395
- const __iconNode$w = [
13395
+ const __iconNode$v = [
13396
13396
  [
13397
13397
  "path",
13398
13398
  {
@@ -13408,9 +13408,9 @@ const __iconNode$w = [
13408
13408
  }
13409
13409
  ]
13410
13410
  ];
13411
- const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$w);
13411
+ const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$v);
13412
13412
 
13413
- const __iconNode$v = [
13413
+ const __iconNode$u = [
13414
13414
  [
13415
13415
  "circle",
13416
13416
  {
@@ -13428,9 +13428,9 @@ const __iconNode$v = [
13428
13428
  }
13429
13429
  ]
13430
13430
  ];
13431
- const CircleCheck = createLucideIcon("circle-check", __iconNode$v);
13431
+ const CircleCheck = createLucideIcon("circle-check", __iconNode$u);
13432
13432
 
13433
- const __iconNode$u = [
13433
+ const __iconNode$t = [
13434
13434
  [
13435
13435
  "circle",
13436
13436
  {
@@ -13455,27 +13455,7 @@ const __iconNode$u = [
13455
13455
  }
13456
13456
  ]
13457
13457
  ];
13458
- const CircleDollarSign = createLucideIcon("circle-dollar-sign", __iconNode$u);
13459
-
13460
- const __iconNode$t = [
13461
- [
13462
- "circle",
13463
- {
13464
- cx: "12",
13465
- cy: "12",
13466
- r: "10",
13467
- key: "1mglay"
13468
- }
13469
- ],
13470
- [
13471
- "path",
13472
- {
13473
- d: "M8 12h8",
13474
- key: "1wcyev"
13475
- }
13476
- ]
13477
- ];
13478
- const CircleMinus = createLucideIcon("circle-minus", __iconNode$t);
13458
+ const CircleDollarSign = createLucideIcon("circle-dollar-sign", __iconNode$t);
13479
13459
 
13480
13460
  const __iconNode$s = [
13481
13461
  [
@@ -121047,11 +121027,14 @@ const STATUS_ICON_SIZE = 12;
121047
121027
  partial: Blend,
121048
121028
  unclassified: null
121049
121029
  };
121050
- /** Short word shown on the collapsed accordion row. */ const STATUS_CHIP_LABEL = {
121030
+ /**
121031
+ * Short word shown on the collapsed accordion row. Unclassified carries none, for the same reason
121032
+ * it carries no icon: the chip would state a verdict the category does not have.
121033
+ */ const STATUS_CHIP_LABEL = {
121051
121034
  pass: "Pass",
121052
121035
  fail: "Fail",
121053
121036
  partial: "Partial",
121054
- unclassified: "Unclassified"
121037
+ unclassified: null
121055
121038
  };
121056
121039
  /** The neutral outlined treatment: unclassified categories, not-gated metrics, and zero counts. */ function outlinedPalette(theme) {
121057
121040
  return {
@@ -121086,10 +121069,11 @@ function statusPalette(theme, status) {
121086
121069
  }
121087
121070
  }
121088
121071
  /**
121089
- * Failure rate, formatted the way the notification formats it: an exact 0%/100% only when exact,
121090
- * so a single failure out of two hundred does not round down to a clean "0% failed".
121091
- */ function formatFailureRate(failureCount, scoredCount) {
121092
- const exact = failureCount * 100 / scoredCount;
121072
+ * Pass rate the share of scored runs that did *not* fail, so it reads with the ratio beside it
121073
+ * rather than against it. An exact 0%/100% only when exact, so a single failure out of two hundred
121074
+ * does not round up to a clean "100% passed".
121075
+ */ function formatPassRate(failureCount, scoredCount) {
121076
+ const exact = (scoredCount - failureCount) * 100 / scoredCount;
121093
121077
  const rounded = Math.round(exact);
121094
121078
  if (rounded === 0 && exact > 0) return "<1%";
121095
121079
  if (rounded === 100 && exact < 100) return ">99%";
@@ -121181,22 +121165,28 @@ const NodeRow$1 = ({ node, metricName, onAgentNodeClick, onOpenVisualizer })=>{
121181
121165
  }, "Reasoning · ", metricName), node.reasoning));
121182
121166
  };
121183
121167
  /**
121184
- * The metric's verdict, beside its name. The ratio's leading number is what did *not* fail,
121185
- * which folds partials in with the passes the same reading the notification prints.
121168
+ * The metric's verdict, beside its name: the status icon, then the pass ratio and rate. The ratio's
121169
+ * leading number is what did *not* fail, which folds partials in with the passes, and the percentage
121170
+ * is that same number as a share — the complement of the failure rate the notification prints.
121171
+ *
121172
+ * The verdict is carried by the icon and its colour alone; spelling it out beside a ratio that
121173
+ * already says the same thing only crowded the header. It stays in the tooltip and the accessible
121174
+ * name so nothing is lost to a reader who cannot resolve the icon.
121175
+ *
121176
+ * Renders nothing for a metric that is not gated, or that has nothing scored yet. Neither has a
121177
+ * ratio to state, and a placeholder pill standing in for the absent verdict only invited the
121178
+ * definitional zero failures of a not-gated metric to be read as an earned pass.
121186
121179
  */ const VerdictPill = ({ metric })=>{
121187
121180
  const { theme } = useTheme$1();
121188
121181
  const { verdict, scoredCount, failureCount } = metric;
121189
- const palette = verdict === "failed" ? statusPalette(theme, "fail") : verdict === "passed" ? statusPalette(theme, "pass") : outlinedPalette(theme);
121190
- const VerdictIcon = verdict === "failed" ? CircleX : verdict === "passed" ? CircleCheck : CircleMinus;
121191
- const text = verdict === "failed" ? "Failed" : verdict === "passed" ? "Passed" : "Not gated";
121192
- // Nothing scored yet, and a passing metric, both show the pill without a failure percentage.
121193
- let rate;
121194
- if (scoredCount > 0 && verdict === "failed") {
121195
- rate = `${scoredCount - failureCount}/${scoredCount} · ${formatFailureRate(failureCount, scoredCount)}`;
121196
- } else if (scoredCount > 0 && verdict === "passed") {
121197
- rate = `${scoredCount}/${scoredCount}`;
121198
- }
121182
+ if (verdict === "notGated" || scoredCount === 0) return null;
121183
+ const failed = verdict === "failed";
121184
+ const palette = statusPalette(theme, failed ? "fail" : "pass");
121185
+ const VerdictIcon = failed ? CircleX : CircleCheck;
121186
+ const verdictLabel = failed ? "Failed" : "Passed";
121187
+ const rate = `${scoredCount - failureCount}/${scoredCount} · ${formatPassRate(failureCount, scoredCount)}`;
121199
121188
  return /*#__PURE__*/ React__default.createElement("span", {
121189
+ title: verdictLabel,
121200
121190
  style: {
121201
121191
  display: "inline-flex",
121202
121192
  alignItems: "center",
@@ -121204,32 +121194,25 @@ const NodeRow$1 = ({ node, metricName, onAgentNodeClick, onOpenVisualizer })=>{
121204
121194
  padding: "3px 9px",
121205
121195
  borderRadius: 6,
121206
121196
  fontSize: 11.5,
121207
- fontWeight: 700,
121208
- letterSpacing: 0.6,
121209
- textTransform: "uppercase",
121197
+ letterSpacing: 0.2,
121210
121198
  background: palette.bg,
121211
121199
  color: palette.color,
121212
121200
  border: `1px solid ${palette.border}`
121213
121201
  }
121214
121202
  }, /*#__PURE__*/ React__default.createElement(VerdictIcon, {
121215
121203
  size: STATUS_ICON_SIZE,
121216
- "aria-hidden": true,
121204
+ role: "img",
121205
+ "aria-label": verdictLabel,
121217
121206
  style: {
121218
121207
  flexShrink: 0
121219
121208
  }
121220
- }), text, rate && /*#__PURE__*/ React__default.createElement("span", {
121221
- style: {
121222
- fontWeight: 400,
121223
- letterSpacing: 0.2,
121224
- opacity: 0.9,
121225
- textTransform: "none"
121226
- }
121227
- }, rate));
121209
+ }), rate);
121228
121210
  };
121229
121211
  const LabelPanelHeader = ({ label })=>{
121230
121212
  const { theme } = useTheme$1();
121231
121213
  const isEmpty = label.count === 0;
121232
121214
  const palette = statusPalette(theme, label.status);
121215
+ const chipLabel = STATUS_CHIP_LABEL[label.status];
121233
121216
  // A zero-count row keeps its status colour but reads as inactive, matching its disabled state.
121234
121217
  const dotColor = label.status === "unclassified" ? theme.colors.mutedForeground : palette.color;
121235
121218
  return /*#__PURE__*/ React__default.createElement("div", {
@@ -121253,7 +121236,7 @@ const LabelPanelHeader = ({ label })=>{
121253
121236
  fontWeight: 600,
121254
121237
  color: palette.color
121255
121238
  }
121256
- }, label.labelName), /*#__PURE__*/ React__default.createElement("span", {
121239
+ }, label.labelName), chipLabel && /*#__PURE__*/ React__default.createElement("span", {
121257
121240
  style: {
121258
121241
  fontSize: 10,
121259
121242
  letterSpacing: 0.8,
@@ -121265,7 +121248,7 @@ const LabelPanelHeader = ({ label })=>{
121265
121248
  color: palette.color,
121266
121249
  border: `1px solid ${palette.border}`
121267
121250
  }
121268
- }, STATUS_CHIP_LABEL[label.status]), /*#__PURE__*/ React__default.createElement("span", {
121251
+ }, chipLabel), /*#__PURE__*/ React__default.createElement("span", {
121269
121252
  style: {
121270
121253
  marginLeft: "auto",
121271
121254
  fontSize: 12,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@railtownai/railtracks-visualizer",
3
- "version": "0.0.74",
3
+ "version": "0.0.75",
4
4
  "license": "MIT",
5
5
  "author": "Railtown AI",
6
6
  "description": "A visualizer for Railtracks agentic flows",