@sleep2agi/agent-network-dashboard 0.5.3-preview.14 → 0.5.3-preview.140

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.
Files changed (289) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +3 -3
  3. package/.next/diagnostics/route-bundle-stats.json +32 -32
  4. package/.next/fallback-build-manifest.json +3 -3
  5. package/.next/server/app/_global-error.html +1 -1
  6. package/.next/server/app/_global-error.rsc +1 -1
  7. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  8. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  9. package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  10. package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  11. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  12. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  13. package/.next/server/app/_not-found.html +2 -2
  14. package/.next/server/app/_not-found.rsc +12 -12
  15. package/.next/server/app/_not-found.segments/_full.segment.rsc +12 -12
  16. package/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  17. package/.next/server/app/_not-found.segments/_index.segment.rsc +7 -7
  18. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  19. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  20. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  21. package/.next/server/app/admin/page_client-reference-manifest.js +1 -1
  22. package/.next/server/app/admin.html +2 -2
  23. package/.next/server/app/admin.rsc +14 -14
  24. package/.next/server/app/admin.segments/_full.segment.rsc +14 -14
  25. package/.next/server/app/admin.segments/_head.segment.rsc +4 -4
  26. package/.next/server/app/admin.segments/_index.segment.rsc +7 -7
  27. package/.next/server/app/admin.segments/_tree.segment.rsc +2 -2
  28. package/.next/server/app/admin.segments/admin/__PAGE__.segment.rsc +4 -4
  29. package/.next/server/app/admin.segments/admin.segment.rsc +3 -3
  30. package/.next/server/app/index.html +2 -2
  31. package/.next/server/app/index.rsc +14 -14
  32. package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -4
  33. package/.next/server/app/index.segments/_full.segment.rsc +14 -14
  34. package/.next/server/app/index.segments/_head.segment.rsc +4 -4
  35. package/.next/server/app/index.segments/_index.segment.rsc +7 -7
  36. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  37. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  38. package/.next/server/app/login.html +2 -2
  39. package/.next/server/app/login.rsc +14 -14
  40. package/.next/server/app/login.segments/_full.segment.rsc +14 -14
  41. package/.next/server/app/login.segments/_head.segment.rsc +4 -4
  42. package/.next/server/app/login.segments/_index.segment.rsc +7 -7
  43. package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
  44. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +4 -4
  45. package/.next/server/app/login.segments/login.segment.rsc +3 -3
  46. package/.next/server/app/logs/page_client-reference-manifest.js +1 -1
  47. package/.next/server/app/logs.html +2 -2
  48. package/.next/server/app/logs.rsc +14 -14
  49. package/.next/server/app/logs.segments/_full.segment.rsc +14 -14
  50. package/.next/server/app/logs.segments/_head.segment.rsc +4 -4
  51. package/.next/server/app/logs.segments/_index.segment.rsc +7 -7
  52. package/.next/server/app/logs.segments/_tree.segment.rsc +2 -2
  53. package/.next/server/app/logs.segments/logs/__PAGE__.segment.rsc +4 -4
  54. package/.next/server/app/logs.segments/logs.segment.rsc +3 -3
  55. package/.next/server/app/messages/page_client-reference-manifest.js +1 -1
  56. package/.next/server/app/messages.html +2 -2
  57. package/.next/server/app/messages.rsc +14 -14
  58. package/.next/server/app/messages.segments/_full.segment.rsc +14 -14
  59. package/.next/server/app/messages.segments/_head.segment.rsc +4 -4
  60. package/.next/server/app/messages.segments/_index.segment.rsc +7 -7
  61. package/.next/server/app/messages.segments/_tree.segment.rsc +2 -2
  62. package/.next/server/app/messages.segments/messages/__PAGE__.segment.rsc +4 -4
  63. package/.next/server/app/messages.segments/messages.segment.rsc +3 -3
  64. package/.next/server/app/node/page_client-reference-manifest.js +1 -1
  65. package/.next/server/app/node.html +2 -2
  66. package/.next/server/app/node.rsc +14 -14
  67. package/.next/server/app/node.segments/_full.segment.rsc +14 -14
  68. package/.next/server/app/node.segments/_head.segment.rsc +4 -4
  69. package/.next/server/app/node.segments/_index.segment.rsc +7 -7
  70. package/.next/server/app/node.segments/_tree.segment.rsc +2 -2
  71. package/.next/server/app/node.segments/node/__PAGE__.segment.rsc +4 -4
  72. package/.next/server/app/node.segments/node.segment.rsc +3 -3
  73. package/.next/server/app/nodes/page_client-reference-manifest.js +1 -1
  74. package/.next/server/app/nodes.html +2 -2
  75. package/.next/server/app/nodes.rsc +14 -14
  76. package/.next/server/app/nodes.segments/_full.segment.rsc +14 -14
  77. package/.next/server/app/nodes.segments/_head.segment.rsc +4 -4
  78. package/.next/server/app/nodes.segments/_index.segment.rsc +7 -7
  79. package/.next/server/app/nodes.segments/_tree.segment.rsc +2 -2
  80. package/.next/server/app/nodes.segments/nodes/__PAGE__.segment.rsc +4 -4
  81. package/.next/server/app/nodes.segments/nodes.segment.rsc +3 -3
  82. package/.next/server/app/page_client-reference-manifest.js +1 -1
  83. package/.next/server/app/server-logs/page_client-reference-manifest.js +1 -1
  84. package/.next/server/app/server-logs.html +2 -2
  85. package/.next/server/app/server-logs.rsc +14 -14
  86. package/.next/server/app/server-logs.segments/_full.segment.rsc +14 -14
  87. package/.next/server/app/server-logs.segments/_head.segment.rsc +4 -4
  88. package/.next/server/app/server-logs.segments/_index.segment.rsc +7 -7
  89. package/.next/server/app/server-logs.segments/_tree.segment.rsc +2 -2
  90. package/.next/server/app/server-logs.segments/server-logs/__PAGE__.segment.rsc +4 -4
  91. package/.next/server/app/server-logs.segments/server-logs.segment.rsc +3 -3
  92. package/.next/server/app/settings/networks/page_client-reference-manifest.js +1 -1
  93. package/.next/server/app/settings/networks.html +2 -2
  94. package/.next/server/app/settings/networks.rsc +14 -14
  95. package/.next/server/app/settings/networks.segments/_full.segment.rsc +14 -14
  96. package/.next/server/app/settings/networks.segments/_head.segment.rsc +4 -4
  97. package/.next/server/app/settings/networks.segments/_index.segment.rsc +7 -7
  98. package/.next/server/app/settings/networks.segments/_tree.segment.rsc +2 -2
  99. package/.next/server/app/settings/networks.segments/settings/networks/__PAGE__.segment.rsc +4 -4
  100. package/.next/server/app/settings/networks.segments/settings/networks.segment.rsc +3 -3
  101. package/.next/server/app/settings/networks.segments/settings.segment.rsc +3 -3
  102. package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  103. package/.next/server/app/settings/tokens/page_client-reference-manifest.js +1 -1
  104. package/.next/server/app/settings/tokens.html +2 -2
  105. package/.next/server/app/settings/tokens.rsc +14 -14
  106. package/.next/server/app/settings/tokens.segments/_full.segment.rsc +14 -14
  107. package/.next/server/app/settings/tokens.segments/_head.segment.rsc +4 -4
  108. package/.next/server/app/settings/tokens.segments/_index.segment.rsc +7 -7
  109. package/.next/server/app/settings/tokens.segments/_tree.segment.rsc +2 -2
  110. package/.next/server/app/settings/tokens.segments/settings/tokens/__PAGE__.segment.rsc +4 -4
  111. package/.next/server/app/settings/tokens.segments/settings/tokens.segment.rsc +3 -3
  112. package/.next/server/app/settings/tokens.segments/settings.segment.rsc +3 -3
  113. package/.next/server/app/settings.html +2 -2
  114. package/.next/server/app/settings.rsc +14 -14
  115. package/.next/server/app/settings.segments/_full.segment.rsc +14 -14
  116. package/.next/server/app/settings.segments/_head.segment.rsc +4 -4
  117. package/.next/server/app/settings.segments/_index.segment.rsc +7 -7
  118. package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  119. package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +4 -4
  120. package/.next/server/app/settings.segments/settings.segment.rsc +3 -3
  121. package/.next/server/app/tasks/[id]/page_client-reference-manifest.js +1 -1
  122. package/.next/server/app/tasks/page_client-reference-manifest.js +1 -1
  123. package/.next/server/app/tasks.html +2 -2
  124. package/.next/server/app/tasks.rsc +14 -14
  125. package/.next/server/app/tasks.segments/_full.segment.rsc +14 -14
  126. package/.next/server/app/tasks.segments/_head.segment.rsc +4 -4
  127. package/.next/server/app/tasks.segments/_index.segment.rsc +7 -7
  128. package/.next/server/app/tasks.segments/_tree.segment.rsc +2 -2
  129. package/.next/server/app/tasks.segments/tasks/__PAGE__.segment.rsc +4 -4
  130. package/.next/server/app/tasks.segments/tasks.segment.rsc +3 -3
  131. package/.next/server/chunks/ssr/[root-of-the-server]__0sv~g.o._.js +1 -1
  132. package/.next/server/chunks/ssr/[root-of-the-server]__0sv~g.o._.js.map +1 -1
  133. package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js +4 -4
  134. package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js.map +1 -1
  135. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js +1 -1
  136. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js.map +1 -1
  137. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js +1 -1
  138. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js.map +1 -1
  139. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js +1 -1
  140. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js.map +1 -1
  141. package/.next/server/middleware-build-manifest.js +3 -3
  142. package/.next/server/pages/404.html +2 -2
  143. package/.next/server/pages/500.html +1 -1
  144. package/.next/static/chunks/006dxnaf1ojoc.js +1 -0
  145. package/.next/static/chunks/05-~ezd16iskp.css +2 -0
  146. package/.next/static/chunks/069b9-o1a2f0v.js +4 -0
  147. package/.next/static/chunks/{16p3.8p0yi.1p.js → 0bbv-sge~hmdb.js} +1 -1
  148. package/.next/static/chunks/0k930mbg_qx0j.js +1 -0
  149. package/.next/static/chunks/{03a4--7ncekmk.js → 0v4-5tng.uh.7.js} +2 -2
  150. package/.next/trace +2 -2
  151. package/.next/trace-build +1 -1
  152. package/app/components/ServersDrawer.tsx +16 -3
  153. package/app/components/TopoGraph.tsx +3688 -162
  154. package/app/globals.css +58 -7
  155. package/package.json +4 -4
  156. package/scripts/p157-servers-copy-test.mjs +95 -0
  157. package/scripts/topo-active-chrome-hover-text-test.mjs +107 -0
  158. package/scripts/topo-alias-chat-brightness-test.mjs +79 -0
  159. package/scripts/topo-avatar-chat-gate-test.mjs +77 -0
  160. package/scripts/topo-avatar-drop-shadow-test.mjs +86 -0
  161. package/scripts/topo-avatar-fallback-hover-test.mjs +104 -0
  162. package/scripts/topo-avatar-fallback-rotate-test.mjs +92 -0
  163. package/scripts/topo-avatar-rotate-test.mjs +85 -0
  164. package/scripts/topo-avatar-scale-test.mjs +89 -0
  165. package/scripts/topo-badge-chat-gate-test.mjs +74 -0
  166. package/scripts/topo-brand-drop-shadow-test.mjs +71 -0
  167. package/scripts/topo-brand-logo-breath-test.mjs +102 -0
  168. package/scripts/topo-brand-logo-hover-brightness-test.mjs +105 -0
  169. package/scripts/topo-brand-logo-hover-rotate-test.mjs +93 -0
  170. package/scripts/topo-brand-logo-hover-test.mjs +85 -0
  171. package/scripts/topo-card-chat-brightness-test.mjs +86 -0
  172. package/scripts/topo-chat-ring-brightness-test.mjs +80 -0
  173. package/scripts/topo-chip-row-digit-ls-test.mjs +135 -0
  174. package/scripts/topo-chip-row-member-alias-lit-test.mjs +154 -0
  175. package/scripts/topo-chip-row-tier-glow-brightness-test.mjs +99 -0
  176. package/scripts/topo-chip-row-unit-hover-tracking-test.mjs +124 -0
  177. package/scripts/topo-click-ripple-glow-test.mjs +86 -0
  178. package/scripts/topo-cluster-count-attr-test.mjs +80 -0
  179. package/scripts/topo-crescent-breath-test.mjs +104 -0
  180. package/scripts/topo-crescent-recede-test.mjs +111 -0
  181. package/scripts/topo-edge-badge-circle-brightness-test.mjs +82 -0
  182. package/scripts/topo-edge-badge-hover-glow-test.mjs +90 -0
  183. package/scripts/topo-edge-badge-text-brightness-test.mjs +83 -0
  184. package/scripts/topo-edge-chat-gate-test.mjs +71 -0
  185. package/scripts/topo-edge-particle-brightness-test.mjs +82 -0
  186. package/scripts/topo-edge-pill-glow-test.mjs +67 -0
  187. package/scripts/topo-edge-visible-brightness-test.mjs +84 -0
  188. package/scripts/topo-endpoint-ring-brightness-test.mjs +83 -0
  189. package/scripts/topo-filter-pill-glow-test.mjs +90 -0
  190. package/scripts/topo-fleet-density-tier-test.mjs +84 -0
  191. package/scripts/topo-flow-arrow-brightness-test.mjs +82 -0
  192. package/scripts/topo-flow-rail-brightness-test.mjs +80 -0
  193. package/scripts/topo-freshness-chip-fade-test.mjs +105 -0
  194. package/scripts/topo-fullscreen-attr-test.mjs +73 -0
  195. package/scripts/topo-fullscreen-brightness-test.mjs +84 -0
  196. package/scripts/topo-fullscreen-icon-rotate-test.mjs +93 -0
  197. package/scripts/topo-grid-content-bottom-attr-test.mjs +72 -0
  198. package/scripts/topo-group-box-brightness-test.mjs +84 -0
  199. package/scripts/topo-group-chat-gate-test.mjs +77 -0
  200. package/scripts/topo-group-label-brightness-test.mjs +84 -0
  201. package/scripts/topo-group-label-hover-glow-test.mjs +86 -0
  202. package/scripts/topo-group-label-member-alias-hover-test.mjs +125 -0
  203. package/scripts/topo-group-pill-glow-test.mjs +76 -0
  204. package/scripts/topo-group-tint-brightness-test.mjs +82 -0
  205. package/scripts/topo-halo-chat-gate-test.mjs +72 -0
  206. package/scripts/topo-hub-core-brightness-test.mjs +82 -0
  207. package/scripts/topo-hub-digit-brightness-test.mjs +79 -0
  208. package/scripts/topo-hub-digit-ls-test.mjs +119 -0
  209. package/scripts/topo-hub-halo-brightness-test.mjs +80 -0
  210. package/scripts/topo-hub-halo-glow-test.mjs +96 -0
  211. package/scripts/topo-hub-highlight-amplify-test.mjs +139 -0
  212. package/scripts/topo-hub-highlight-brightness-test.mjs +84 -0
  213. package/scripts/topo-hub-highlight-fill-transition-test.mjs +84 -0
  214. package/scripts/topo-hub-highlight-glow-test.mjs +99 -0
  215. package/scripts/topo-hub-highlight-r-test.mjs +112 -0
  216. package/scripts/topo-hub-highlight-recede-test.mjs +144 -0
  217. package/scripts/topo-hub-highlight-theme-fill-test.mjs +83 -0
  218. package/scripts/topo-hub-hover-ring-brightness-test.mjs +79 -0
  219. package/scripts/topo-hub-hover-ring-glow-test.mjs +97 -0
  220. package/scripts/topo-hub-idle-breath-test.mjs +7 -2
  221. package/scripts/topo-hub-recede-test.mjs +124 -0
  222. package/scripts/topo-hub-spoke-brightness-test.mjs +77 -0
  223. package/scripts/topo-hub-spoke-glow-test.mjs +112 -0
  224. package/scripts/topo-label-card-brightness-test.mjs +81 -0
  225. package/scripts/topo-layout-hover-fw-test.mjs +98 -0
  226. package/scripts/topo-layout-toggle-brightness-test.mjs +94 -0
  227. package/scripts/topo-legend-count-brightness-test.mjs +80 -0
  228. package/scripts/topo-legend-count-letter-spacing-test.mjs +108 -0
  229. package/scripts/topo-legend-label-fw-test.mjs +107 -0
  230. package/scripts/topo-legend-pin-ring-brightness-test.mjs +82 -0
  231. package/scripts/topo-legend-row-count-brightness-test.mjs +85 -0
  232. package/scripts/topo-legend-row-label-glow-test.mjs +102 -0
  233. package/scripts/topo-legend-swatch-glow-test.mjs +109 -0
  234. package/scripts/topo-legend-swatch-member-alias-match-test.mjs +139 -0
  235. package/scripts/topo-legend-tint-brightness-test.mjs +83 -0
  236. package/scripts/topo-minimap-hover-glow-test.mjs +109 -0
  237. package/scripts/topo-more-footer-brightness-test.mjs +94 -0
  238. package/scripts/topo-node-alias-brightness-test.mjs +84 -0
  239. package/scripts/topo-node-sub-text-brightness-test.mjs +88 -0
  240. package/scripts/topo-nodesize-brightness-test.mjs +82 -0
  241. package/scripts/topo-nodesize-hover-fw-test.mjs +99 -0
  242. package/scripts/topo-orphan-box-dash-test.mjs +89 -0
  243. package/scripts/topo-orphan-fill-opacity-test.mjs +91 -0
  244. package/scripts/topo-orphan-label-opacity-test.mjs +98 -0
  245. package/scripts/topo-panel-count-hover-ls-test.mjs +87 -0
  246. package/scripts/topo-panel-row-brightness-test.mjs +116 -0
  247. package/scripts/topo-panel-title-brightness-test.mjs +98 -0
  248. package/scripts/topo-panel-title-glow-test.mjs +111 -0
  249. package/scripts/topo-pill-x-rotate-test.mjs +96 -0
  250. package/scripts/topo-pinned-aspect-test.mjs +89 -0
  251. package/scripts/topo-pip-brightness-test.mjs +85 -0
  252. package/scripts/topo-pressure-seg-glow-test.mjs +92 -0
  253. package/scripts/topo-pressure-seg-member-alias-match-test.mjs +133 -0
  254. package/scripts/topo-pressure-seg-motion-test.mjs +101 -0
  255. package/scripts/topo-recent-count-brightness-test.mjs +84 -0
  256. package/scripts/topo-recent-more-fw-test.mjs +126 -0
  257. package/scripts/topo-recent-row-chat-gate-test.mjs +75 -0
  258. package/scripts/topo-recent-row-fw-test.mjs +115 -0
  259. package/scripts/topo-recent-row-text-glow-test.mjs +86 -0
  260. package/scripts/topo-recent-tint-brightness-test.mjs +80 -0
  261. package/scripts/topo-recent-ts-brightness-test.mjs +86 -0
  262. package/scripts/topo-reduced-motion-attr-test.mjs +69 -0
  263. package/scripts/topo-reset-brightness-test.mjs +83 -0
  264. package/scripts/topo-reset-icon-hover-scale-test.mjs +102 -0
  265. package/scripts/topo-runtime-badge-brightness-test.mjs +78 -0
  266. package/scripts/topo-runtime-badge-glow-test.mjs +108 -0
  267. package/scripts/topo-runtime-badge-rotate-test.mjs +85 -0
  268. package/scripts/topo-spoke-chat-gate-test.mjs +72 -0
  269. package/scripts/topo-starfield-hue-test.mjs +109 -0
  270. package/scripts/topo-status-ring-brightness-test.mjs +84 -0
  271. package/scripts/topo-status-ring-chat-gate-test.mjs +72 -0
  272. package/scripts/topo-sub-text-chat-brightness-test.mjs +81 -0
  273. package/scripts/topo-titleblock-h2-hover-fw-test.mjs +109 -0
  274. package/scripts/topo-titleblock-h2-hover-tracking-test.mjs +128 -0
  275. package/scripts/topo-titleblock-kicker-hover-test.mjs +134 -0
  276. package/scripts/topo-vendor-chip-glow-test.mjs +97 -0
  277. package/scripts/topo-vendor-pill-glow-test.mjs +98 -0
  278. package/scripts/topo-watermark-breath-test.mjs +100 -0
  279. package/scripts/topo-watermark-recede-test.mjs +114 -0
  280. package/scripts/topo-zoom-buttons-brightness-test.mjs +94 -0
  281. package/scripts/topo-zoom-level-brightness-test.mjs +83 -0
  282. package/scripts/topo-zoom-level-color-test.mjs +105 -0
  283. package/.next/static/chunks/0ckoz2evm~lvq.js +0 -1
  284. package/.next/static/chunks/0m.1mvl~t.avc.css +0 -2
  285. package/.next/static/chunks/0qf8ynb6zk1~~.js +0 -4
  286. package/.next/static/chunks/10s69w5k6v8cr.js +0 -1
  287. /package/.next/static/{Q8lkSZiF_OETF8cugX0IW → AGbxLByQywWb5JcOo5dTf}/_buildManifest.js +0 -0
  288. /package/.next/static/{Q8lkSZiF_OETF8cugX0IW → AGbxLByQywWb5JcOo5dTf}/_clientMiddlewareManifest.js +0 -0
  289. /package/.next/static/{Q8lkSZiF_OETF8cugX0IW → AGbxLByQywWb5JcOo5dTf}/_ssgManifest.js +0 -0
@@ -0,0 +1,111 @@
1
+ /* Round 550 verification: panel-title texts (recent + legend) gain
2
+ * pal.legendAccent drop-shadow on active state. 14th + 15th anchors
3
+ * in drop-shadow family (counted as R550 + sibling).
4
+ *
5
+ * Source-canonical for the LIVE state probe (DOM filter readback via
6
+ * SVG is reliable here — text element, no shared-gate IIFE). Pin
7
+ * trigger: click a status legend row to set pinnedStatus → glow on
8
+ * legend-panel title. activeEdgeKey would require flow data — for
9
+ * recent-panel just source-side regex confirms the wiring.
10
+ *
11
+ * Test phases:
12
+ * 1. rest: both panel titles' computed filter = 'none'
13
+ * 2. legend title — click pressure-bar working seg to pin → filter
14
+ * contains drop-shadow with the cyan accent
15
+ * 3. source regex confirms both texts wired with the filter
16
+ * conditional + transition list extension
17
+ */
18
+ import { chromium } from 'playwright';
19
+ import { readFileSync } from 'node:fs';
20
+
21
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
22
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
23
+
24
+ const browser = await chromium.launch({ headless: true });
25
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
26
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
27
+ await ctx.addInitScript(() => {
28
+ try {
29
+ localStorage.setItem('anet-theme', 'cyber');
30
+ localStorage.setItem('anet-topo-layout', 'ring');
31
+ sessionStorage.setItem('anet_v3_auth', '1');
32
+ } catch {}
33
+ });
34
+ await ctx.route('**/api/hub/status*', async (route) => {
35
+ const r = await route.fetch();
36
+ const b = await r.json();
37
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
38
+ const mk = (alias, status) => ({
39
+ alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
40
+ network_id: nid, project_dir: null,
41
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
42
+ });
43
+ await route.fulfill({ response: r, json: { ...b, sessions: [
44
+ mk('a·1', 'working'), mk('a·2', 'idle'), mk('a·3', 'offline'),
45
+ ] } });
46
+ });
47
+ // Provide one message so flowLinks > 0 → recent-panel renders.
48
+ // buildFlowLinks reads from_alias/to_alias/content/created_at (banked R520).
49
+ await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [
50
+ { from_alias: 'a·1', to_alias: 'a·2', content: 'hi', created_at: fresh },
51
+ ] } }));
52
+ await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
53
+ const page = await ctx.newPage();
54
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
55
+ await page.waitForSelector('[data-legend-panel-title]', { timeout: 15000 });
56
+ await page.waitForTimeout(500);
57
+
58
+ // Phase 1: rest filters
59
+ const restLegend = await page.evaluate(() => {
60
+ const el = document.querySelector('[data-legend-panel-title]');
61
+ if (!el) return null;
62
+ const cs = getComputedStyle(el);
63
+ return { filter: cs.filter, glowAttr: el.getAttribute('data-legend-panel-title-glow') };
64
+ });
65
+ const restRecent = await page.evaluate(() => {
66
+ const el = document.querySelector('[data-recent-panel-title]');
67
+ if (!el) return null;
68
+ const cs = getComputedStyle(el);
69
+ return { filter: cs.filter, glowAttr: el.getAttribute('data-recent-panel-title-glow') };
70
+ });
71
+
72
+ // Phase 2: click pressure-bar working seg to pin → triggers
73
+ // pinnedStatus='working' → legend title should glow.
74
+ await page.click('[data-pressure-seg="working"]');
75
+ await page.waitForTimeout(400);
76
+ const pinnedLegend = await page.evaluate(() => {
77
+ const el = document.querySelector('[data-legend-panel-title]');
78
+ if (!el) return null;
79
+ const cs = getComputedStyle(el);
80
+ return { filter: cs.filter, glowAttr: el.getAttribute('data-legend-panel-title-glow') };
81
+ });
82
+
83
+ await browser.close();
84
+
85
+ const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
86
+ const sourceRecentFilter =
87
+ /filter: activeEdgeKey \? `drop-shadow\(0 0 2px \$\{pal\.legendAccent\}80\)` : undefined/.test(src);
88
+ const sourceLegendFilter =
89
+ /filter: pinnedStatus \? `drop-shadow\(0 0 2px \$\{pal\.legendAccent\}80\)` : undefined/.test(src);
90
+ const sourceRecentTransition =
91
+ /transition: 'fill 200ms ease-out, letter-spacing 200ms ease-out, font-weight 200ms ease-out, filter 200ms ease-out'/.test(src);
92
+
93
+ const results = {
94
+ rest_legend_filter_none: restLegend?.filter === 'none',
95
+ rest_recent_filter_none: restRecent?.filter === 'none',
96
+ rest_legend_glow_attr_false: restLegend?.glowAttr === 'false',
97
+ rest_recent_glow_attr_false: restRecent?.glowAttr === 'false',
98
+ pinned_legend_glow_attr: pinnedLegend?.glowAttr === 'true',
99
+ // Computed filter contains drop-shadow with rgb/rgba (hex+alpha resolves to rgba)
100
+ pinned_legend_filter_set: /drop-shadow\(/.test(pinnedLegend?.filter || ''),
101
+ source_recent_filter: sourceRecentFilter,
102
+ source_legend_filter: sourceLegendFilter,
103
+ source_recent_transition: sourceRecentTransition,
104
+ };
105
+ const ok = Object.values(results).every(Boolean);
106
+ console.log(`${ok ? '✅' : '❌'} R550 panel-title pin-gated drop-shadow (14th + 15th anchors):`,
107
+ JSON.stringify(results, null, 2),
108
+ '\n rest legend:', JSON.stringify(restLegend),
109
+ '\n rest recent:', JSON.stringify(restRecent),
110
+ '\n pinned legend:', JSON.stringify(pinnedLegend));
111
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,96 @@
1
+ /* Round 547 verification: pill × close buttons gain hover:rotate-12 alongside
2
+ * existing hover:scale-110 (R356) + hover:opacity-70. 4 sibling buttons
3
+ * (status / group / vendor / edge) edited via replace_all.
4
+ *
5
+ * Test phases:
6
+ * 1. trigger a pin to render a pill (click pressure-bar working seg)
7
+ * 2. inspect the pill's × button — rest transform=none
8
+ * 3. hover the × button — computed transform contains rotate(12deg)
9
+ * AND scale(1.1)
10
+ * 4. source-side regex confirms hover:rotate-12 in all 4 className
11
+ * strings via replace_all
12
+ */
13
+ import { chromium } from 'playwright';
14
+ import { readFileSync } from 'node:fs';
15
+
16
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
17
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
18
+
19
+ const browser = await chromium.launch({ headless: true });
20
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
21
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
22
+ await ctx.addInitScript(() => {
23
+ try {
24
+ localStorage.setItem('anet-theme', 'cyber');
25
+ localStorage.setItem('anet-topo-layout', 'ring');
26
+ sessionStorage.setItem('anet_v3_auth', '1');
27
+ } catch {}
28
+ });
29
+ await ctx.route('**/api/hub/status*', async (route) => {
30
+ const r = await route.fetch();
31
+ const b = await r.json();
32
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
33
+ const mk = (alias, status) => ({
34
+ alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
35
+ network_id: nid, project_dir: null,
36
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
37
+ });
38
+ await route.fulfill({ response: r, json: { ...b, sessions: [
39
+ mk('a·1', 'working'), mk('a·2', 'idle'), mk('a·3', 'offline'),
40
+ ] } });
41
+ });
42
+ await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
43
+ await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
44
+ const page = await ctx.newPage();
45
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
46
+ await page.waitForSelector('[data-pressure-seg="working"]', { timeout: 15000 });
47
+ await page.waitForTimeout(500);
48
+
49
+ // Phase 1: trigger pin
50
+ await page.click('[data-pressure-seg="working"]');
51
+ await page.waitForTimeout(400);
52
+
53
+ // Phase 2: rest read on the × button (find via aria-label).
54
+ // Tailwind 4 uses individual CSS `scale` / `rotate` properties (NOT
55
+ // transform: scale(...) rotate(...)). Probe both — banked pattern note.
56
+ const xSel = 'button[aria-label="Clear working filter"]';
57
+ await page.waitForSelector(xSel, { timeout: 5000 });
58
+ const rest = await page.evaluate((sel) => {
59
+ const el = document.querySelector(sel);
60
+ if (!el) return null;
61
+ const cs = getComputedStyle(el);
62
+ return { transform: cs.transform, scale: cs.scale, rotate: cs.rotate };
63
+ }, xSel);
64
+
65
+ // Phase 3: hover the × button
66
+ await page.hover(xSel);
67
+ await page.waitForTimeout(400);
68
+ const hover = await page.evaluate((sel) => {
69
+ const el = document.querySelector(sel);
70
+ if (!el) return null;
71
+ const cs = getComputedStyle(el);
72
+ return { transform: cs.transform, scale: cs.scale, rotate: cs.rotate };
73
+ }, xSel);
74
+
75
+ await browser.close();
76
+
77
+ // Source regex — confirm className across all 4 instances
78
+ const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
79
+ const occurrences = (src.match(/className="ml-0\.5 leading-none hover:opacity-70 transition-transform duration-200 ease-out hover:scale-110 hover:rotate-12 transform-gpu"/g) || []).length;
80
+
81
+ // Tailwind 4 emits individual `scale: ...` and `rotate: ...` CSS
82
+ // properties (not combined transform). Probe each axis separately.
83
+ const results = {
84
+ rest_scale_none: rest?.scale === 'none' || rest?.scale === '1' || rest?.scale === '1 1',
85
+ rest_rotate_none: rest?.rotate === 'none' || rest?.rotate === '0deg',
86
+ hover_scale_110: /\b1\.1\b/.test(hover?.scale || ''),
87
+ hover_rotate_12: /\b12deg\b/.test(hover?.rotate || ''),
88
+ source_4_occurrences: occurrences === 4,
89
+ };
90
+ const ok = Object.values(results).every(Boolean);
91
+ console.log(`${ok ? '✅' : '❌'} R547 pill × hover-rotate:`,
92
+ JSON.stringify(results, null, 2),
93
+ '\n rest:', JSON.stringify(rest),
94
+ '\n hover:', JSON.stringify(hover),
95
+ '\n source occurrences:', occurrences);
96
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,89 @@
1
+ /* Round 504 verification: root svg surfaces `data-topo-pinned-aspect`
2
+ * categorical attribute. Sibling to R488's `data-topo-hovered-alias`
3
+ * (hover identity); R504 is the pin axis identity. Reflects WHICH
4
+ * pin state is active — paired with R467's any-pinned boolean.
5
+ *
6
+ * Tier values:
7
+ * none, status, group, vendor, edge, multi
8
+ *
9
+ * Test scenarios — seed pins via localStorage to reach each tier
10
+ * deterministically.
11
+ */
12
+ import { chromium } from 'playwright';
13
+ import { readFileSync } from 'node:fs';
14
+
15
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
16
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
17
+
18
+ async function probe({ pins }) {
19
+ const browser = await chromium.launch({ headless: true });
20
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
21
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
22
+ await ctx.addInitScript((p) => {
23
+ try {
24
+ localStorage.setItem('anet-theme', 'cyber');
25
+ localStorage.setItem('anet-topo-layout', 'ring');
26
+ sessionStorage.setItem('anet_v3_auth', '1');
27
+ // Pins persist via sessionStorage (not localStorage) — verified
28
+ // by grep of TopoGraph.tsx useState initializers at lines
29
+ // 1033/1148/1187. pinnedEdgeKey starts null (no persistence;
30
+ // edge pin only reachable via click, skipped in this test).
31
+ if (p.status) sessionStorage.setItem('anet-topo-pinned-status', p.status);
32
+ if (p.group) sessionStorage.setItem('anet-topo-pinned-group', p.group);
33
+ if (p.vendor) sessionStorage.setItem('anet-topo-pinned-vendor', p.vendor);
34
+ } catch {}
35
+ }, pins);
36
+ await ctx.route('**/api/hub/status*', async (route) => {
37
+ const r = await route.fetch();
38
+ const b = await r.json();
39
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
40
+ const mk = (alias, status) => ({
41
+ alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
42
+ network_id: nid, project_dir: null,
43
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
44
+ });
45
+ await route.fulfill({ response: r, json: { ...b, sessions: [
46
+ mk('alpha·1', 'working'),
47
+ mk('alpha·2', 'idle'),
48
+ ] } });
49
+ });
50
+ await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
51
+ await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
52
+ const page = await ctx.newPage();
53
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
54
+ await page.waitForSelector('svg[data-topo-pinned-aspect]', { timeout: 15000 });
55
+ await page.waitForTimeout(2800); // settle for localStorage-restore useEffect
56
+ const aspect = await page.evaluate(() => {
57
+ return document.querySelector('svg[viewBox="0 0 1000 680"]')?.getAttribute('data-topo-pinned-aspect');
58
+ });
59
+ await browser.close();
60
+ return aspect;
61
+ }
62
+
63
+ const none = await probe({ pins: {} });
64
+ const status = await probe({ pins: { status: 'working' } });
65
+ // Note: 'alpha' for group depends on actual alias-prefix derivation; valid
66
+ // because we seeded alpha·1 + alpha·2 (both have prefix 'alpha·')
67
+ const group = await probe({ pins: { group: 'alpha·' } });
68
+ // vendor uses initial letter — Anthropic = 'A' (from vendorIdentity.ts line 69)
69
+ // claude-opus-4 model resolves to Anthropic vendor; stale-purge keeps 'A' valid
70
+ const vendor = await probe({ pins: { vendor: 'A' } });
71
+ // edge needs from→to format; skip — edge pin keys are complex
72
+ // Multi: status + group together
73
+ const multi = await probe({ pins: { status: 'working', group: 'alpha·' } });
74
+
75
+ const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
76
+ const sourceWired = /data-topo-pinned-aspect=\{\(\(\) => \{[\s\S]*?aspects\.push\('status'\)[\s\S]*?aspects\.push\('group'\)[\s\S]*?aspects\.push\('vendor'\)[\s\S]*?aspects\.push\('edge'\)/.test(src);
77
+
78
+ const results = {
79
+ none_resolves: none === 'none',
80
+ status_resolves: status === 'status',
81
+ group_resolves: group === 'group',
82
+ vendor_resolves: vendor === 'vendor',
83
+ multi_resolves: multi === 'multi',
84
+ source_wired: sourceWired,
85
+ };
86
+ const ok = Object.values(results).every(Boolean);
87
+ console.log(`${ok ? '✅' : '❌'} R504 pinned-aspect:`, JSON.stringify(results),
88
+ '\n raw:', { none, status, group, vendor, multi });
89
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,85 @@
1
+ /* Round 606 — recent-row freshness pip stacks brightness(1.15)
2
+ * onto R478 freshness-gated drop-shadow. Same alpha > 0.7 gate
3
+ * so both filter effects activate together for fresh signals.
4
+ *
5
+ * Test phases:
6
+ * 1. mock 1 fresh message (~10s old, alpha > 0.7) → pip renders
7
+ * with glow + brightness filter
8
+ * 2. computed filter contains BOTH drop-shadow AND brightness
9
+ * 3. brightness-attr = '1.15' on fresh signal
10
+ * 4. source: stacked filter conditional + data-attr
11
+ */
12
+ import { chromium } from 'playwright';
13
+ import { readFileSync } from 'node:fs';
14
+
15
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
16
+ // 10 seconds ago → freshness alpha ≈ 1.0 (well above 0.7 gate)
17
+ const fresh = new Date(Date.now() - 10 * 1000).toISOString();
18
+
19
+ const browser = await chromium.launch({ headless: true });
20
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
21
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
22
+ await ctx.addInitScript(() => {
23
+ try {
24
+ localStorage.setItem('anet-theme', 'cyber');
25
+ localStorage.setItem('anet-topo-layout', 'ring');
26
+ sessionStorage.setItem('anet_v3_auth', '1');
27
+ } catch {}
28
+ });
29
+ await ctx.route('**/api/hub/status*', async (route) => {
30
+ const r = await route.fetch();
31
+ const b = await r.json();
32
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
33
+ const mk = (alias) => ({
34
+ alias, status: 'idle', model: 'claude-opus-4', runtime: 'claude-code-cli',
35
+ network_id: nid, project_dir: null,
36
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
37
+ });
38
+ await route.fulfill({ response: r, json: { ...b, sessions: [mk('a·1'), mk('a·2')] } });
39
+ });
40
+ await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [
41
+ { from_alias: 'a·1', to_alias: 'a·2', content: 'fresh hi', created_at: fresh },
42
+ ] } }));
43
+ await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
44
+ const page = await ctx.newPage();
45
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
46
+ await page.waitForSelector('[data-recent-row-freshness-brightness]', { timeout: 15000, state: 'attached' });
47
+ await page.waitForTimeout(500);
48
+
49
+ const fresh_state = await page.evaluate(() => {
50
+ const el = document.querySelector('[data-recent-row-freshness-brightness]');
51
+ if (!el) return null;
52
+ const cs = getComputedStyle(el);
53
+ return {
54
+ filter: cs.filter,
55
+ transitionProperty: cs.transitionProperty,
56
+ brightnessAttr: el.getAttribute('data-recent-row-freshness-brightness'),
57
+ glowAttr: el.getAttribute('data-recent-row-freshness-glow'),
58
+ alphaAttr: el.getAttribute('data-recent-row-freshness-alpha'),
59
+ opacity: cs.opacity,
60
+ };
61
+ });
62
+
63
+ await browser.close();
64
+
65
+ const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
66
+ const sourceFilter = /filter: alpha > 0\.7\s*\?\s*`drop-shadow\(0 0 3px \$\{pal\.legendAccent\}80\) brightness\(1\.15\)`\s*:\s*undefined/.test(src);
67
+ const sourceAttr = /data-recent-row-freshness-brightness=\{alpha > 0\.7 \? '1\.15' : '1'\}/.test(src);
68
+
69
+ const results = {
70
+ pip_present: !!fresh_state,
71
+ // Fresh signal: alpha ≈ 1.0 > 0.7 → both drop-shadow AND brightness in filter
72
+ fresh_filter_has_drop_shadow: /drop-shadow/.test(fresh_state?.filter || ''),
73
+ fresh_filter_has_brightness: /brightness/.test(fresh_state?.filter || ''),
74
+ fresh_brightness_115: fresh_state?.brightnessAttr === '1.15',
75
+ fresh_glow_true: fresh_state?.glowAttr === 'true',
76
+ fresh_alpha_above_0_7: parseFloat(fresh_state?.alphaAttr || '0') > 0.7,
77
+ transition_has_filter: /filter/.test(fresh_state?.transitionProperty || ''),
78
+ source_filter: sourceFilter,
79
+ source_attr: sourceAttr,
80
+ };
81
+ const ok = Object.values(results).every(Boolean);
82
+ console.log(`${ok ? '✅' : '❌'} R606 freshness-pip stacked brightness (freshness-gated 4-axis):`,
83
+ JSON.stringify(results, null, 2),
84
+ `\n fresh: ${JSON.stringify(fresh_state)}`);
85
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,92 @@
1
+ /* Round 542 verification: pressure-bar segments gain drop-shadow tier-
2
+ * color glow on hover, stacked with R210 brightness(1.2). Chip-row
3
+ * tier-color glow sub-family 3rd anchor.
4
+ *
5
+ * Test phases:
6
+ * 1. rest: filter='none', data-pressure-seg-hovered='false'
7
+ * 2. hover the working seg: filter contains 'brightness(1.2)'
8
+ * AND 'drop-shadow(...)' with the working tier color (cyber
9
+ * #22c55e = rgb(34, 197, 94))
10
+ * 3. source-side regex confirms stacked filter syntax with hex+alpha
11
+ */
12
+ import { chromium } from 'playwright';
13
+ import { readFileSync } from 'node:fs';
14
+
15
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
16
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
17
+
18
+ const browser = await chromium.launch({ headless: true });
19
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
20
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
21
+ await ctx.addInitScript(() => {
22
+ try {
23
+ localStorage.setItem('anet-theme', 'cyber');
24
+ localStorage.setItem('anet-topo-layout', 'ring');
25
+ sessionStorage.setItem('anet_v3_auth', '1');
26
+ } catch {}
27
+ });
28
+ await ctx.route('**/api/hub/status*', async (route) => {
29
+ const r = await route.fetch();
30
+ const b = await r.json();
31
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
32
+ const mk = (alias, status) => ({
33
+ alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
34
+ network_id: nid, project_dir: null,
35
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
36
+ });
37
+ await route.fulfill({ response: r, json: { ...b, sessions: [
38
+ mk('a·1', 'working'), mk('a·2', 'idle'), mk('a·3', 'offline'),
39
+ ] } });
40
+ });
41
+ await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
42
+ await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
43
+ const page = await ctx.newPage();
44
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
45
+ await page.waitForSelector('[data-pressure-seg="working"]', { timeout: 15000 });
46
+ await page.waitForTimeout(800);
47
+
48
+ const sel = '[data-pressure-seg="working"]';
49
+
50
+ const restRead = async () => page.evaluate((sel) => {
51
+ const el = document.querySelector(sel);
52
+ if (!el) return null;
53
+ const cs = getComputedStyle(el);
54
+ return {
55
+ hovered: el.getAttribute('data-pressure-seg-hovered'),
56
+ filter: cs.filter,
57
+ inlineFilter: el.style.filter,
58
+ };
59
+ }, sel);
60
+
61
+ // Phase 1: rest
62
+ const rest = await restRead();
63
+
64
+ // Phase 2: hover working seg
65
+ await page.hover(sel);
66
+ await page.waitForTimeout(400);
67
+ const hover = await restRead();
68
+
69
+ await browser.close();
70
+
71
+ // Source regex
72
+ const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
73
+ const sourceFilter =
74
+ /filter: hoveredStatus === key \? `brightness\(1\.2\) drop-shadow\(0 0 2px \$\{color\}99\)` : undefined,/.test(src);
75
+
76
+ const results = {
77
+ rest_hovered_false: rest?.hovered === 'false',
78
+ rest_filter_none: rest?.filter === 'none' || rest?.filter === '',
79
+ hover_hovered_true: hover?.hovered === 'true',
80
+ hover_brightness: /brightness\(1\.2\)/.test(hover?.filter || ''),
81
+ hover_drop_shadow: /drop-shadow/.test(hover?.filter || ''),
82
+ // Cyber working color #22c55e → rgb(34, 197, 94) — accept any of the
83
+ // computed color() forms.
84
+ hover_working_color: /rgba?\(34,?\s*197,?\s*94/.test(hover?.filter || ''), // R537 banked: rgba? not rgb (hex+alpha → rgba)
85
+ source_filter: sourceFilter,
86
+ };
87
+ const ok = Object.values(results).every(Boolean);
88
+ console.log(`${ok ? '✅' : '❌'} R542 pressure-seg tier-color glow:`,
89
+ JSON.stringify(results, null, 2),
90
+ '\n rest:', JSON.stringify(rest),
91
+ '\n hover:', JSON.stringify(hover));
92
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,133 @@
1
+ /* Round 563 verification: pressure-bar segment lights up (R210
2
+ * brightness + R542 drop-shadow) when operator hovers a node alias
3
+ * whose status matches the segment's tier. 6th anchor in
4
+ * inspection-overrides-encoding family.
5
+ *
6
+ * Mock: alpha·1 (working) + alpha·2 (idle) + alpha·3 (offline).
7
+ * Hover alpha·1 → 'working' segment lights up; idle + offline rest.
8
+ *
9
+ * Test phases:
10
+ * 1. rest: all 3 segments filter='none', lit='false'
11
+ * 2. hover alpha·1 (working) → working seg filter contains
12
+ * brightness(1.2) and drop-shadow with green hex; idle +
13
+ * offline stay at rest
14
+ * 3. hover alpha·2 (idle) → idle seg lit
15
+ * 4. hover alpha·3 (offline) → offline seg lit
16
+ * 5. source-side regex confirms wiring
17
+ */
18
+ import { chromium } from 'playwright';
19
+ import { readFileSync } from 'node:fs';
20
+
21
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
22
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
23
+
24
+ const browser = await chromium.launch({ headless: true });
25
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
26
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
27
+ await ctx.addInitScript(() => {
28
+ try {
29
+ localStorage.setItem('anet-theme', 'cyber');
30
+ localStorage.setItem('anet-topo-layout', 'ring');
31
+ sessionStorage.setItem('anet_v3_auth', '1');
32
+ } catch {}
33
+ });
34
+ await ctx.route('**/api/hub/status*', async (route) => {
35
+ const r = await route.fetch();
36
+ const b = await r.json();
37
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
38
+ const mk = (alias, status) => ({
39
+ alias, status, model: 'claude-opus-4', runtime: 'claude-code-cli',
40
+ network_id: nid, project_dir: null,
41
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
42
+ });
43
+ await route.fulfill({ response: r, json: { ...b, sessions: [
44
+ mk('alpha·1', 'working'),
45
+ mk('alpha·2', 'idle'),
46
+ mk('alpha·3', 'offline'),
47
+ ] } });
48
+ });
49
+ await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
50
+ await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
51
+ const page = await ctx.newPage();
52
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
53
+ await page.waitForSelector('[data-pressure-seg="working"]', { timeout: 15000 });
54
+ await page.waitForTimeout(500);
55
+
56
+ const probeSeg = (key) => page.evaluate((k) => {
57
+ const el = document.querySelector(`[data-pressure-seg="${k}"]`);
58
+ if (!el) return null;
59
+ const cs = getComputedStyle(el);
60
+ return {
61
+ filter: cs.filter,
62
+ matching: el.getAttribute('data-pressure-seg-member-alias-matching') === 'true',
63
+ lit: el.getAttribute('data-pressure-seg-lit') === 'true',
64
+ hovered: el.getAttribute('data-pressure-seg-hovered') === 'true',
65
+ };
66
+ }, key);
67
+
68
+ const restWorking = await probeSeg('working');
69
+ const restIdle = await probeSeg('idle');
70
+ const restOffline = await probeSeg('offline');
71
+
72
+ // Hover working node
73
+ await page.hover('g[data-node="alpha·1"]');
74
+ await page.waitForTimeout(400);
75
+ const hoverWorkingW = await probeSeg('working');
76
+ const hoverWorkingI = await probeSeg('idle');
77
+ const hoverWorkingO = await probeSeg('offline');
78
+
79
+ await page.mouse.move(0, 0);
80
+ await page.waitForTimeout(300);
81
+ await page.hover('g[data-node="alpha·2"]');
82
+ await page.waitForTimeout(400);
83
+ const hoverIdleI = await probeSeg('idle');
84
+
85
+ await page.mouse.move(0, 0);
86
+ await page.waitForTimeout(300);
87
+ await page.hover('g[data-node="alpha·3"]');
88
+ await page.waitForTimeout(400);
89
+ const hoverOfflineO = await probeSeg('offline');
90
+
91
+ await browser.close();
92
+
93
+ const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
94
+ const sourceTierKey = /const hoveredAliasTierKey: 'working' \| 'idle' \| 'offline' \| null/.test(src);
95
+ const sourceMatching = /const isMemberAliasMatching = hoveredAliasTierKey === key;/.test(src);
96
+ const sourceLit = /const isSegLit = hoveredStatus === key \|\| isMemberAliasMatching;/.test(src);
97
+ const sourceFilter = /filter: isSegLit \? `brightness\(1\.2\) drop-shadow\(0 0 2px \$\{color\}99\)` : undefined/.test(src);
98
+ const sourceAttr = /data-pressure-seg-member-alias-matching=/.test(src);
99
+
100
+ const results = {
101
+ rest_working_filter_none: restWorking?.filter === 'none',
102
+ rest_working_lit_false: restWorking?.lit === false,
103
+ rest_idle_filter_none: restIdle?.filter === 'none',
104
+ rest_offline_filter_none: restOffline?.filter === 'none',
105
+ // Hover working node → working seg lit
106
+ hover_working_w_lit: hoverWorkingW?.lit === true,
107
+ hover_working_w_matching: hoverWorkingW?.matching === true,
108
+ hover_working_w_brightness: /brightness\(1\.2\)/.test(hoverWorkingW?.filter || ''),
109
+ hover_working_w_dropshadow: /drop-shadow\(/.test(hoverWorkingW?.filter || ''),
110
+ // idle + offline segments stay at rest
111
+ hover_working_i_lit_false: hoverWorkingI?.lit === false,
112
+ hover_working_o_lit_false: hoverWorkingO?.lit === false,
113
+ // Hover idle node → idle seg lit
114
+ hover_idle_i_lit: hoverIdleI?.lit === true,
115
+ hover_idle_i_matching: hoverIdleI?.matching === true,
116
+ // Hover offline node → offline seg lit
117
+ hover_offline_o_lit: hoverOfflineO?.lit === true,
118
+ hover_offline_o_matching: hoverOfflineO?.matching === true,
119
+ // Source
120
+ source_tier_key: sourceTierKey,
121
+ source_matching: sourceMatching,
122
+ source_lit: sourceLit,
123
+ source_filter: sourceFilter,
124
+ source_attr: sourceAttr,
125
+ };
126
+ const ok = Object.values(results).every(Boolean);
127
+ console.log(`${ok ? '✅' : '❌'} R563 pressure-seg inspection-overrides-encoding (6th anchor):`,
128
+ JSON.stringify(results, null, 2),
129
+ '\n rest working:', JSON.stringify(restWorking),
130
+ '\n hover alpha·1 (working) → working:', JSON.stringify(hoverWorkingW),
131
+ '\n hover alpha·2 (idle) → idle:', JSON.stringify(hoverIdleI),
132
+ '\n hover alpha·3 (offline) → offline:', JSON.stringify(hoverOfflineO));
133
+ process.exit(ok ? 0 : 1);