@sleep2agi/agent-network-dashboard 0.5.3 → 0.5.4

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 (484) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +2 -0
  3. package/.next/build-manifest.json +3 -3
  4. package/.next/diagnostics/route-bundle-stats.json +35 -35
  5. package/.next/fallback-build-manifest.json +3 -3
  6. package/.next/prerender-manifest.json +29 -0
  7. package/.next/routes-manifest.json +12 -0
  8. package/.next/server/app/_global-error.html +1 -1
  9. package/.next/server/app/_global-error.rsc +2 -2
  10. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  11. package/.next/server/app/_global-error.segments/_full.segment.rsc +2 -2
  12. package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  13. package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  14. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  15. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  16. package/.next/server/app/_not-found.html +2 -2
  17. package/.next/server/app/_not-found.rsc +13 -13
  18. package/.next/server/app/_not-found.segments/_full.segment.rsc +13 -13
  19. package/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  20. package/.next/server/app/_not-found.segments/_index.segment.rsc +7 -7
  21. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  22. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  23. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  24. package/.next/server/app/admin/page_client-reference-manifest.js +1 -1
  25. package/.next/server/app/admin.html +2 -2
  26. package/.next/server/app/admin.rsc +15 -15
  27. package/.next/server/app/admin.segments/_full.segment.rsc +15 -15
  28. package/.next/server/app/admin.segments/_head.segment.rsc +4 -4
  29. package/.next/server/app/admin.segments/_index.segment.rsc +7 -7
  30. package/.next/server/app/admin.segments/_tree.segment.rsc +2 -2
  31. package/.next/server/app/admin.segments/admin/__PAGE__.segment.rsc +4 -4
  32. package/.next/server/app/admin.segments/admin.segment.rsc +3 -3
  33. package/.next/server/app/api/hub/upload/route/app-paths-manifest.json +3 -0
  34. package/.next/server/app/api/hub/upload/route/build-manifest.json +9 -0
  35. package/.next/server/app/api/hub/upload/route/server-reference-manifest.json +4 -0
  36. package/.next/server/app/api/hub/upload/route.js +7 -0
  37. package/.next/server/app/api/hub/upload/route.js.map +5 -0
  38. package/.next/server/app/api/hub/upload/route.js.nft.json +1 -0
  39. package/.next/server/app/api/hub/upload/route_client-reference-manifest.js +3 -0
  40. package/.next/server/app/index.html +2 -2
  41. package/.next/server/app/index.rsc +15 -15
  42. package/.next/server/app/index.segments/__PAGE__.segment.rsc +4 -4
  43. package/.next/server/app/index.segments/_full.segment.rsc +15 -15
  44. package/.next/server/app/index.segments/_head.segment.rsc +4 -4
  45. package/.next/server/app/index.segments/_index.segment.rsc +7 -7
  46. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  47. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  48. package/.next/server/app/login.html +2 -2
  49. package/.next/server/app/login.rsc +15 -15
  50. package/.next/server/app/login.segments/_full.segment.rsc +15 -15
  51. package/.next/server/app/login.segments/_head.segment.rsc +4 -4
  52. package/.next/server/app/login.segments/_index.segment.rsc +7 -7
  53. package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
  54. package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +4 -4
  55. package/.next/server/app/login.segments/login.segment.rsc +3 -3
  56. package/.next/server/app/logs/page_client-reference-manifest.js +1 -1
  57. package/.next/server/app/logs.html +2 -2
  58. package/.next/server/app/logs.rsc +15 -15
  59. package/.next/server/app/logs.segments/_full.segment.rsc +15 -15
  60. package/.next/server/app/logs.segments/_head.segment.rsc +4 -4
  61. package/.next/server/app/logs.segments/_index.segment.rsc +7 -7
  62. package/.next/server/app/logs.segments/_tree.segment.rsc +2 -2
  63. package/.next/server/app/logs.segments/logs/__PAGE__.segment.rsc +4 -4
  64. package/.next/server/app/logs.segments/logs.segment.rsc +3 -3
  65. package/.next/server/app/manifest.webmanifest/route/app-paths-manifest.json +3 -0
  66. package/.next/server/app/manifest.webmanifest/route/build-manifest.json +9 -0
  67. package/.next/server/app/manifest.webmanifest/route/server-reference-manifest.json +4 -0
  68. package/.next/server/app/manifest.webmanifest/route.js +8 -0
  69. package/.next/server/app/manifest.webmanifest/route.js.map +5 -0
  70. package/.next/server/app/manifest.webmanifest/route.js.nft.json +1 -0
  71. package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +3 -0
  72. package/.next/server/app/manifest.webmanifest.body +1 -0
  73. package/.next/server/app/manifest.webmanifest.meta +1 -0
  74. package/.next/server/app/messages/page_client-reference-manifest.js +1 -1
  75. package/.next/server/app/messages.html +2 -2
  76. package/.next/server/app/messages.rsc +15 -15
  77. package/.next/server/app/messages.segments/_full.segment.rsc +15 -15
  78. package/.next/server/app/messages.segments/_head.segment.rsc +4 -4
  79. package/.next/server/app/messages.segments/_index.segment.rsc +7 -7
  80. package/.next/server/app/messages.segments/_tree.segment.rsc +2 -2
  81. package/.next/server/app/messages.segments/messages/__PAGE__.segment.rsc +4 -4
  82. package/.next/server/app/messages.segments/messages.segment.rsc +3 -3
  83. package/.next/server/app/node/page_client-reference-manifest.js +1 -1
  84. package/.next/server/app/node.html +2 -2
  85. package/.next/server/app/node.rsc +15 -15
  86. package/.next/server/app/node.segments/_full.segment.rsc +15 -15
  87. package/.next/server/app/node.segments/_head.segment.rsc +4 -4
  88. package/.next/server/app/node.segments/_index.segment.rsc +7 -7
  89. package/.next/server/app/node.segments/_tree.segment.rsc +2 -2
  90. package/.next/server/app/node.segments/node/__PAGE__.segment.rsc +4 -4
  91. package/.next/server/app/node.segments/node.segment.rsc +3 -3
  92. package/.next/server/app/nodes/page_client-reference-manifest.js +1 -1
  93. package/.next/server/app/nodes.html +2 -2
  94. package/.next/server/app/nodes.rsc +15 -15
  95. package/.next/server/app/nodes.segments/_full.segment.rsc +15 -15
  96. package/.next/server/app/nodes.segments/_head.segment.rsc +4 -4
  97. package/.next/server/app/nodes.segments/_index.segment.rsc +7 -7
  98. package/.next/server/app/nodes.segments/_tree.segment.rsc +2 -2
  99. package/.next/server/app/nodes.segments/nodes/__PAGE__.segment.rsc +4 -4
  100. package/.next/server/app/nodes.segments/nodes.segment.rsc +3 -3
  101. package/.next/server/app/page_client-reference-manifest.js +1 -1
  102. package/.next/server/app/server-logs/page_client-reference-manifest.js +1 -1
  103. package/.next/server/app/server-logs.html +2 -2
  104. package/.next/server/app/server-logs.rsc +15 -15
  105. package/.next/server/app/server-logs.segments/_full.segment.rsc +15 -15
  106. package/.next/server/app/server-logs.segments/_head.segment.rsc +4 -4
  107. package/.next/server/app/server-logs.segments/_index.segment.rsc +7 -7
  108. package/.next/server/app/server-logs.segments/_tree.segment.rsc +2 -2
  109. package/.next/server/app/server-logs.segments/server-logs/__PAGE__.segment.rsc +4 -4
  110. package/.next/server/app/server-logs.segments/server-logs.segment.rsc +3 -3
  111. package/.next/server/app/settings/networks/page_client-reference-manifest.js +1 -1
  112. package/.next/server/app/settings/networks.html +2 -2
  113. package/.next/server/app/settings/networks.rsc +15 -15
  114. package/.next/server/app/settings/networks.segments/_full.segment.rsc +15 -15
  115. package/.next/server/app/settings/networks.segments/_head.segment.rsc +4 -4
  116. package/.next/server/app/settings/networks.segments/_index.segment.rsc +7 -7
  117. package/.next/server/app/settings/networks.segments/_tree.segment.rsc +2 -2
  118. package/.next/server/app/settings/networks.segments/settings/networks/__PAGE__.segment.rsc +4 -4
  119. package/.next/server/app/settings/networks.segments/settings/networks.segment.rsc +3 -3
  120. package/.next/server/app/settings/networks.segments/settings.segment.rsc +3 -3
  121. package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  122. package/.next/server/app/settings/tokens/page_client-reference-manifest.js +1 -1
  123. package/.next/server/app/settings/tokens.html +2 -2
  124. package/.next/server/app/settings/tokens.rsc +15 -15
  125. package/.next/server/app/settings/tokens.segments/_full.segment.rsc +15 -15
  126. package/.next/server/app/settings/tokens.segments/_head.segment.rsc +4 -4
  127. package/.next/server/app/settings/tokens.segments/_index.segment.rsc +7 -7
  128. package/.next/server/app/settings/tokens.segments/_tree.segment.rsc +2 -2
  129. package/.next/server/app/settings/tokens.segments/settings/tokens/__PAGE__.segment.rsc +4 -4
  130. package/.next/server/app/settings/tokens.segments/settings/tokens.segment.rsc +3 -3
  131. package/.next/server/app/settings/tokens.segments/settings.segment.rsc +3 -3
  132. package/.next/server/app/settings.html +2 -2
  133. package/.next/server/app/settings.rsc +15 -15
  134. package/.next/server/app/settings.segments/_full.segment.rsc +15 -15
  135. package/.next/server/app/settings.segments/_head.segment.rsc +4 -4
  136. package/.next/server/app/settings.segments/_index.segment.rsc +7 -7
  137. package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  138. package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +4 -4
  139. package/.next/server/app/settings.segments/settings.segment.rsc +3 -3
  140. package/.next/server/app/tasks/[id]/page_client-reference-manifest.js +1 -1
  141. package/.next/server/app/tasks/page_client-reference-manifest.js +1 -1
  142. package/.next/server/app/tasks.html +2 -2
  143. package/.next/server/app/tasks.rsc +15 -15
  144. package/.next/server/app/tasks.segments/_full.segment.rsc +15 -15
  145. package/.next/server/app/tasks.segments/_head.segment.rsc +4 -4
  146. package/.next/server/app/tasks.segments/_index.segment.rsc +7 -7
  147. package/.next/server/app/tasks.segments/_tree.segment.rsc +2 -2
  148. package/.next/server/app/tasks.segments/tasks/__PAGE__.segment.rsc +4 -4
  149. package/.next/server/app/tasks.segments/tasks.segment.rsc +3 -3
  150. package/.next/server/app-paths-manifest.json +2 -0
  151. package/.next/server/chunks/00jm_next_dist_0ju_ux9._.js +18 -0
  152. package/.next/server/chunks/00jm_next_dist_0ju_ux9._.js.map +1 -0
  153. package/.next/server/chunks/0ykm__next-internal_server_app_api_hub_upload_route_actions_03_eqnf.js +3 -0
  154. package/.next/server/chunks/0ykm__next-internal_server_app_manifest_webmanifest_route_actions_0m16rb8.js +3 -0
  155. package/.next/server/chunks/0ykm__next-internal_server_app_manifest_webmanifest_route_actions_0m16rb8.js.map +1 -0
  156. package/.next/server/chunks/{[externals]__11vad82._.js → [externals]__036g1.i._.js} +2 -2
  157. package/.next/server/chunks/[externals]__036g1.i._.js.map +1 -0
  158. package/.next/server/chunks/[root-of-the-server]__0-8_f0o._.js +3 -0
  159. package/.next/server/chunks/[root-of-the-server]__0-8_f0o._.js.map +1 -0
  160. package/.next/server/chunks/{[root-of-the-server]__08uyvdq._.js → [root-of-the-server]__0jndzts._.js} +2 -2
  161. package/.next/server/chunks/{[root-of-the-server]__08uyvdq._.js.map → [root-of-the-server]__0jndzts._.js.map} +1 -1
  162. package/.next/server/chunks/[root-of-the-server]__0mxw4vb._.js +1 -1
  163. package/.next/server/chunks/[root-of-the-server]__0mxw4vb._.js.map +1 -1
  164. package/.next/server/chunks/[root-of-the-server]__0tx8s8i._.js +1 -1
  165. package/.next/server/chunks/[root-of-the-server]__0tx8s8i._.js.map +1 -1
  166. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0..ddwm.js +1 -1
  167. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0..ddwm.js.map +1 -1
  168. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_02bxi6j.js +1 -1
  169. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_02bxi6j.js.map +1 -1
  170. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_05oassd.js +1 -1
  171. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_05oassd.js.map +1 -1
  172. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_05vxtby.js +1 -1
  173. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_05vxtby.js.map +1 -1
  174. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_05~eml4.js +1 -1
  175. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_05~eml4.js.map +1 -1
  176. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0_-g_q2.js +1 -1
  177. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0_-g_q2.js.map +1 -1
  178. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0_ec0xu.js +1 -1
  179. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0_ec0xu.js.map +1 -1
  180. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0czb6wz.js +1 -1
  181. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0czb6wz.js.map +1 -1
  182. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0e-cn.p.js +1 -1
  183. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0e-cn.p.js.map +1 -1
  184. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0k8_sr8.js +1 -1
  185. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0k8_sr8.js.map +1 -1
  186. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0lt_3bw.js +1 -1
  187. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0lt_3bw.js.map +1 -1
  188. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0uyh3yt.js +1 -1
  189. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0uyh3yt.js.map +1 -1
  190. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0v-a2ps.js +1 -1
  191. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_0v-a2ps.js.map +1 -1
  192. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_12.4r9~.js +1 -1
  193. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_12.4r9~.js.map +1 -1
  194. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_13mqkay.js +1 -1
  195. package/.next/server/chunks/ssr/00jm_next_dist_esm_build_templates_app-page_13mqkay.js.map +1 -1
  196. package/.next/server/chunks/ssr/[root-of-the-server]__030vg4n._.js +4 -1
  197. package/.next/server/chunks/ssr/[root-of-the-server]__030vg4n._.js.map +1 -1
  198. package/.next/server/chunks/ssr/[root-of-the-server]__0sv~g.o._.js +1 -1
  199. package/.next/server/chunks/ssr/[root-of-the-server]__0sv~g.o._.js.map +1 -1
  200. package/.next/server/chunks/ssr/[root-of-the-server]__0u5aqkk._.js +1 -1
  201. package/.next/server/chunks/ssr/[root-of-the-server]__0u5aqkk._.js.map +1 -1
  202. package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js +4 -4
  203. package/.next/server/chunks/ssr/agent-network-dashboard_09kk21a._.js.map +1 -1
  204. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js +1 -1
  205. package/.next/server/chunks/ssr/agent-network-dashboard_app_01jhlxz._.js.map +1 -1
  206. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js +1 -1
  207. package/.next/server/chunks/ssr/agent-network-dashboard_app_09d29my._.js.map +1 -1
  208. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js +1 -1
  209. package/.next/server/chunks/ssr/agent-network-dashboard_app_components_0mvyi-4._.js.map +1 -1
  210. package/.next/server/middleware-build-manifest.js +3 -3
  211. package/.next/server/middleware.js +2 -2
  212. package/.next/server/middleware.js.nft.json +1 -1
  213. package/.next/server/pages/404.html +2 -2
  214. package/.next/server/pages/500.html +1 -1
  215. package/.next/static/chunks/{07~8sx3_5uiox.js → 04wjx7vbxusw5.js} +4 -1
  216. package/.next/static/chunks/089t1exs6apb8.js +4 -0
  217. package/.next/static/chunks/{0ph1in3421~o-.js → 09e8kxo30n5cf.js} +1 -1
  218. package/.next/static/chunks/{0v4-5tng.uh.7.js → 0k-c1chkvf78s.js} +2 -2
  219. package/.next/static/chunks/0v2~nlpk-cx6v.css +2 -0
  220. package/.next/static/chunks/0xsye-9kffdi0.js +1 -0
  221. package/.next/static/chunks/0~rx_~akeylmq.js +1 -0
  222. package/.next/trace +2 -2
  223. package/.next/trace-build +1 -1
  224. package/.next/types/routes.d.ts +2 -1
  225. package/.next/types/validator.ts +9 -0
  226. package/app/api/hub/send/route.ts +11 -2
  227. package/app/api/hub/servers/route.ts +3 -29
  228. package/app/api/hub/upload/route.ts +83 -0
  229. package/app/components/AppShell.tsx +3 -1
  230. package/app/components/MobileNav.tsx +45 -0
  231. package/app/components/TaskChatPanel.tsx +130 -6
  232. package/app/components/TopoGraph.tsx +6686 -248
  233. package/app/globals.css +897 -7
  234. package/app/layout.tsx +6 -0
  235. package/app/lib/serverDedupe.ts +122 -0
  236. package/app/lib/vendorIdentity.ts +74 -56
  237. package/app/manifest.ts +23 -0
  238. package/package.json +4 -4
  239. package/public/vendors/claude.svg +7 -8
  240. package/public/vendors/minimax.svg +8 -9
  241. package/public/vendors/openai.svg +8 -10
  242. package/scripts/p157-rc2-dedup-test.mjs +110 -0
  243. package/scripts/topo-a11y-titles-catalog-test.mjs +132 -0
  244. package/scripts/topo-active-chrome-hover-text-test.mjs +107 -0
  245. package/scripts/topo-active-links-chip-halo-layers-test.mjs +81 -0
  246. package/scripts/topo-alias-chat-brightness-test.mjs +79 -0
  247. package/scripts/topo-alias-text-halo-layers-test.mjs +98 -0
  248. package/scripts/topo-animation-temporal-modes-catalog-test.mjs +144 -0
  249. package/scripts/topo-avatar-chat-gate-test.mjs +77 -0
  250. package/scripts/topo-avatar-drop-shadow-test.mjs +86 -0
  251. package/scripts/topo-avatar-fallback-hover-test.mjs +104 -0
  252. package/scripts/topo-avatar-fallback-rotate-test.mjs +92 -0
  253. package/scripts/topo-avatar-rotate-test.mjs +85 -0
  254. package/scripts/topo-avatar-scale-test.mjs +89 -0
  255. package/scripts/topo-badge-chat-gate-test.mjs +74 -0
  256. package/scripts/topo-brand-drop-shadow-test.mjs +71 -0
  257. package/scripts/topo-brand-logo-breath-test.mjs +102 -0
  258. package/scripts/topo-brand-logo-halo-layers-test.mjs +85 -0
  259. package/scripts/topo-brand-logo-hover-brightness-test.mjs +105 -0
  260. package/scripts/topo-brand-logo-hover-rotate-test.mjs +93 -0
  261. package/scripts/topo-brand-logo-hover-test.mjs +85 -0
  262. package/scripts/topo-canvas-desc-a11y-test.mjs +87 -0
  263. package/scripts/topo-canvas-entrance-animation-test.mjs +117 -0
  264. package/scripts/topo-canvas-scan-beam-diagonal-test.mjs +148 -0
  265. package/scripts/topo-canvas-scan-beam-test.mjs +109 -0
  266. package/scripts/topo-canvas-scan-beam-vertical-test.mjs +123 -0
  267. package/scripts/topo-card-chat-brightness-test.mjs +86 -0
  268. package/scripts/topo-chat-ring-breath-curve-test.mjs +114 -0
  269. package/scripts/topo-chat-ring-brightness-test.mjs +80 -0
  270. package/scripts/topo-chat-ring-halo-layers-test.mjs +100 -0
  271. package/scripts/topo-chat-ring-r-breath-test.mjs +121 -0
  272. package/scripts/topo-chat-ring-status-halo-test.mjs +106 -0
  273. package/scripts/topo-chat-ring-sw-breath-test.mjs +123 -0
  274. package/scripts/topo-chip-pin-halo-test.mjs +85 -0
  275. package/scripts/topo-chip-row-digit-ls-test.mjs +135 -0
  276. package/scripts/topo-chip-row-member-alias-lit-test.mjs +154 -0
  277. package/scripts/topo-chip-row-tier-glow-brightness-test.mjs +99 -0
  278. package/scripts/topo-chip-row-unit-hover-tracking-test.mjs +124 -0
  279. package/scripts/topo-chrome-control-halo-layers-test.mjs +22 -0
  280. package/scripts/topo-chrome-fullscreen-breath-test.mjs +121 -0
  281. package/scripts/topo-chrome-layout-trailer-breath-test.mjs +86 -0
  282. package/scripts/topo-chrome-nodesize-trailer-breath-test.mjs +86 -0
  283. package/scripts/topo-chrome-reset-breath-test.mjs +115 -0
  284. package/scripts/topo-chrome-strip-entrance-animation-test.mjs +115 -0
  285. package/scripts/topo-chrome-wrapper-halo-test.mjs +83 -0
  286. package/scripts/topo-chrome-zoom-wrapper-breath-test.mjs +85 -0
  287. package/scripts/topo-click-ripple-glow-test.mjs +86 -0
  288. package/scripts/topo-click-ripple-halo-layers-test.mjs +79 -0
  289. package/scripts/topo-click-ripple-sw-test.mjs +110 -0
  290. package/scripts/topo-cluster-count-attr-test.mjs +80 -0
  291. package/scripts/topo-crescent-breath-test.mjs +104 -0
  292. package/scripts/topo-crescent-envelope-breath-test.mjs +103 -0
  293. package/scripts/topo-crescent-recede-test.mjs +111 -0
  294. package/scripts/topo-dense-alias-chat-halo-test.mjs +73 -0
  295. package/scripts/topo-dense-alias-halo-layers-test.mjs +80 -0
  296. package/scripts/topo-dual-axis-surfaces-catalog-test.mjs +94 -0
  297. package/scripts/topo-edge-badge-circle-brightness-test.mjs +82 -0
  298. package/scripts/topo-edge-badge-circle-hot-pulse-test.mjs +100 -0
  299. package/scripts/topo-edge-badge-digit-halo-layers-test.mjs +107 -0
  300. package/scripts/topo-edge-badge-endpoint-gate-test.mjs +94 -0
  301. package/scripts/topo-edge-badge-halo-layers-test.mjs +85 -0
  302. package/scripts/topo-edge-badge-hot-pulse-test.mjs +92 -0
  303. package/scripts/topo-edge-badge-hover-glow-test.mjs +90 -0
  304. package/scripts/topo-edge-badge-text-brightness-test.mjs +83 -0
  305. package/scripts/topo-edge-chat-gate-test.mjs +71 -0
  306. package/scripts/topo-edge-flow-rail-halo-layers-test.mjs +89 -0
  307. package/scripts/topo-edge-particle-brightness-test.mjs +82 -0
  308. package/scripts/topo-edge-particle-halo-layers-test.mjs +91 -0
  309. package/scripts/topo-edge-pill-glow-test.mjs +67 -0
  310. package/scripts/topo-edge-pin-halo-test.mjs +99 -0
  311. package/scripts/topo-edge-visible-brightness-test.mjs +84 -0
  312. package/scripts/topo-edge-visible-halo-layers-test.mjs +87 -0
  313. package/scripts/topo-endpoint-ring-brightness-test.mjs +83 -0
  314. package/scripts/topo-endpoint-ring-flow-halo-test.mjs +107 -0
  315. package/scripts/topo-endpoint-ring-halo-layers-test.mjs +100 -0
  316. package/scripts/topo-filter-pill-glow-test.mjs +90 -0
  317. package/scripts/topo-filter-pill-halo-layers-test.mjs +27 -0
  318. package/scripts/topo-flow-arrow-brightness-test.mjs +82 -0
  319. package/scripts/topo-flow-rail-brightness-test.mjs +80 -0
  320. package/scripts/topo-fullscreen-attr-test.mjs +73 -0
  321. package/scripts/topo-fullscreen-brightness-test.mjs +84 -0
  322. package/scripts/topo-fullscreen-icon-rotate-test.mjs +93 -0
  323. package/scripts/topo-grid-content-bottom-attr-test.mjs +72 -0
  324. package/scripts/topo-group-box-brightness-test.mjs +84 -0
  325. package/scripts/topo-group-box-halo-layers-test.mjs +91 -0
  326. package/scripts/topo-group-chat-gate-test.mjs +77 -0
  327. package/scripts/topo-group-label-brightness-test.mjs +84 -0
  328. package/scripts/topo-group-label-halo-layers-test.mjs +78 -0
  329. package/scripts/topo-group-label-hover-glow-test.mjs +86 -0
  330. package/scripts/topo-group-label-member-alias-hover-test.mjs +125 -0
  331. package/scripts/topo-group-pill-glow-test.mjs +76 -0
  332. package/scripts/topo-group-tint-brightness-test.mjs +82 -0
  333. package/scripts/topo-h2-dual-axis-breath-test.mjs +92 -0
  334. package/scripts/topo-h2-triple-axis-breath-test.mjs +142 -0
  335. package/scripts/topo-halo-chat-gate-test.mjs +72 -0
  336. package/scripts/topo-hover-detail-halo-test.mjs +76 -0
  337. package/scripts/topo-hub-a11y-title-test.mjs +95 -0
  338. package/scripts/topo-hub-core-brightness-test.mjs +82 -0
  339. package/scripts/topo-hub-core-halo-layers-test.mjs +81 -0
  340. package/scripts/topo-hub-digit-brightness-test.mjs +79 -0
  341. package/scripts/topo-hub-digit-halo-layers-test.mjs +76 -0
  342. package/scripts/topo-hub-digit-ls-test.mjs +119 -0
  343. package/scripts/topo-hub-halo-brightness-test.mjs +80 -0
  344. package/scripts/topo-hub-halo-glow-test.mjs +96 -0
  345. package/scripts/topo-hub-halo-halo-layers-test.mjs +76 -0
  346. package/scripts/topo-hub-highlight-brightness-test.mjs +84 -0
  347. package/scripts/topo-hub-highlight-glow-test.mjs +99 -0
  348. package/scripts/topo-hub-highlight-halo-layers-test.mjs +78 -0
  349. package/scripts/topo-hub-highlight-r-test.mjs +112 -0
  350. package/scripts/topo-hub-hover-ring-brightness-test.mjs +79 -0
  351. package/scripts/topo-hub-hover-ring-glow-test.mjs +97 -0
  352. package/scripts/topo-hub-hover-ring-halo-layers-test.mjs +71 -0
  353. package/scripts/topo-hub-spoke-brightness-test.mjs +77 -0
  354. package/scripts/topo-hub-spoke-glow-test.mjs +112 -0
  355. package/scripts/topo-hub-spoke-halo-layers-test.mjs +97 -0
  356. package/scripts/topo-hub-spoke-self-filter-test.mjs +119 -0
  357. package/scripts/topo-kicker-breath-test.mjs +100 -0
  358. package/scripts/topo-kicker-dual-axis-breath-test.mjs +81 -0
  359. package/scripts/topo-kicker-halo-layers-test.mjs +82 -0
  360. package/scripts/topo-kicker-triple-axis-breath-test.mjs +124 -0
  361. package/scripts/topo-label-card-brightness-test.mjs +81 -0
  362. package/scripts/topo-layout-hover-fw-test.mjs +98 -0
  363. package/scripts/topo-layout-toggle-brightness-test.mjs +94 -0
  364. package/scripts/topo-layout-toggle-halo-layers-test.mjs +95 -0
  365. package/scripts/topo-legend-count-brightness-test.mjs +80 -0
  366. package/scripts/topo-legend-count-halo-layers-test.mjs +79 -0
  367. package/scripts/topo-legend-count-letter-spacing-test.mjs +108 -0
  368. package/scripts/topo-legend-label-fw-test.mjs +107 -0
  369. package/scripts/topo-legend-panel-title-breath-test.mjs +86 -0
  370. package/scripts/topo-legend-pin-ring-brightness-test.mjs +82 -0
  371. package/scripts/topo-legend-pin-ring-halo-layers-test.mjs +71 -0
  372. package/scripts/topo-legend-row-count-brightness-test.mjs +85 -0
  373. package/scripts/topo-legend-row-label-glow-test.mjs +102 -0
  374. package/scripts/topo-legend-swatch-glow-test.mjs +109 -0
  375. package/scripts/topo-legend-swatch-member-alias-match-test.mjs +139 -0
  376. package/scripts/topo-legend-tint-brightness-test.mjs +83 -0
  377. package/scripts/topo-legend-trio-halo-layers-test.mjs +22 -0
  378. package/scripts/topo-live-lanes.mjs +48 -0
  379. package/scripts/topo-minimap-container-halo-test.mjs +82 -0
  380. package/scripts/topo-minimap-dot-chat-gate-test.mjs +81 -0
  381. package/scripts/topo-minimap-hover-glow-test.mjs +109 -0
  382. package/scripts/topo-minimap-viewport-brightness-test.mjs +84 -0
  383. package/scripts/topo-minimap-viewport-halo-layers-test.mjs +24 -0
  384. package/scripts/topo-more-footer-brightness-test.mjs +94 -0
  385. package/scripts/topo-node-alias-brightness-test.mjs +84 -0
  386. package/scripts/topo-node-avatar-halo-layers-test.mjs +25 -0
  387. package/scripts/topo-node-hover-ring-halo-layers-test.mjs +70 -0
  388. package/scripts/topo-node-label-card-halo-test.mjs +76 -0
  389. package/scripts/topo-node-sub-text-brightness-test.mjs +88 -0
  390. package/scripts/topo-nodesize-brightness-test.mjs +82 -0
  391. package/scripts/topo-nodesize-halo-layers-test.mjs +89 -0
  392. package/scripts/topo-nodesize-hover-fw-test.mjs +99 -0
  393. package/scripts/topo-orphan-label-opacity-test.mjs +98 -0
  394. package/scripts/topo-overlap-test.mjs +22 -8
  395. package/scripts/topo-panel-count-halo-layers-test.mjs +91 -0
  396. package/scripts/topo-panel-count-hover-ls-test.mjs +87 -0
  397. package/scripts/topo-panel-rect-halo-test.mjs +90 -0
  398. package/scripts/topo-panel-row-brightness-test.mjs +116 -0
  399. package/scripts/topo-panel-title-brightness-test.mjs +98 -0
  400. package/scripts/topo-panel-title-glow-test.mjs +111 -0
  401. package/scripts/topo-panel-titles-dual-axis-breath-test.mjs +94 -0
  402. package/scripts/topo-panel-titles-halo-layers-test.mjs +23 -0
  403. package/scripts/topo-panel-titles-triple-axis-breath-test.mjs +161 -0
  404. package/scripts/topo-pill-x-rotate-test.mjs +96 -0
  405. package/scripts/topo-pip-brightness-test.mjs +85 -0
  406. package/scripts/topo-pressure-bar-halo-layers-test.mjs +19 -0
  407. package/scripts/topo-pressure-seg-glow-test.mjs +92 -0
  408. package/scripts/topo-pressure-seg-member-alias-match-test.mjs +133 -0
  409. package/scripts/topo-pressure-seg-motion-test.mjs +101 -0
  410. package/scripts/topo-r717-scan-beam-pair-pattern-test.mjs +100 -0
  411. package/scripts/topo-r717-triple-axis-pair-pattern-test.mjs +113 -0
  412. package/scripts/topo-r717-triple-axis-tier-pattern-test.mjs +117 -0
  413. package/scripts/topo-recent-count-brightness-test.mjs +84 -0
  414. package/scripts/topo-recent-more-fw-test.mjs +126 -0
  415. package/scripts/topo-recent-more-halo-layers-test.mjs +90 -0
  416. package/scripts/topo-recent-panel-hot-pulse-test.mjs +105 -0
  417. package/scripts/topo-recent-panel-title-breath-test.mjs +91 -0
  418. package/scripts/topo-recent-pip-halo-layers-test.mjs +82 -0
  419. package/scripts/topo-recent-row-chat-gate-test.mjs +75 -0
  420. package/scripts/topo-recent-row-content-lift-test.mjs +140 -0
  421. package/scripts/topo-recent-row-fw-test.mjs +115 -0
  422. package/scripts/topo-recent-row-text-glow-test.mjs +86 -0
  423. package/scripts/topo-recent-row-text-halo-layers-test.mjs +67 -0
  424. package/scripts/topo-recent-tint-brightness-test.mjs +80 -0
  425. package/scripts/topo-recent-ts-brightness-test.mjs +86 -0
  426. package/scripts/topo-reduced-motion-attr-test.mjs +69 -0
  427. package/scripts/topo-reset-brightness-test.mjs +83 -0
  428. package/scripts/topo-reset-icon-hover-scale-test.mjs +102 -0
  429. package/scripts/topo-respiratory-axis-count-stats-test.mjs +154 -0
  430. package/scripts/topo-respiratory-patterns-catalog-test.mjs +112 -0
  431. package/scripts/topo-respiratory-rolodex-test.mjs +83 -0
  432. package/scripts/topo-respiratory-tiers-catalog-test.mjs +119 -0
  433. package/scripts/topo-respiratory-triple-axis-surfaces-catalog-test.mjs +127 -0
  434. package/scripts/topo-runtime-badge-brightness-test.mjs +78 -0
  435. package/scripts/topo-runtime-badge-glow-test.mjs +108 -0
  436. package/scripts/topo-runtime-badge-halo-layers-test.mjs +87 -0
  437. package/scripts/topo-runtime-badge-rotate-test.mjs +85 -0
  438. package/scripts/topo-section-title-breath-test.mjs +83 -0
  439. package/scripts/topo-section-title-halo-layers-test.mjs +88 -0
  440. package/scripts/topo-spoke-chat-gate-test.mjs +72 -0
  441. package/scripts/topo-starfield-hue-test.mjs +109 -0
  442. package/scripts/topo-status-pin-pill-halo-layers-test.mjs +17 -0
  443. package/scripts/topo-status-ring-brightness-test.mjs +84 -0
  444. package/scripts/topo-status-ring-chat-gate-test.mjs +72 -0
  445. package/scripts/topo-status-ring-halo-layers-test.mjs +105 -0
  446. package/scripts/topo-status-ring-status-halo-test.mjs +110 -0
  447. package/scripts/topo-sub-text-chat-brightness-test.mjs +81 -0
  448. package/scripts/topo-svg-title-a11y-r731-test.mjs +93 -0
  449. package/scripts/topo-svg-title-a11y-test.mjs +88 -0
  450. package/scripts/topo-title-block-entrance-animation-test.mjs +127 -0
  451. package/scripts/topo-title-block-envelope-breath-test.mjs +87 -0
  452. package/scripts/topo-titleblock-h2-hover-fw-test.mjs +109 -0
  453. package/scripts/topo-titleblock-h2-hover-tracking-test.mjs +128 -0
  454. package/scripts/topo-titleblock-kicker-hover-test.mjs +134 -0
  455. package/scripts/topo-tree-diag.mjs +95 -0
  456. package/scripts/topo-vendor-chip-glow-test.mjs +97 -0
  457. package/scripts/topo-vendor-chip-halo-layers-test.mjs +18 -0
  458. package/scripts/topo-vendor-chip-pin-halo-test.mjs +88 -0
  459. package/scripts/topo-vendor-count-suffix-halo-layers-test.mjs +79 -0
  460. package/scripts/topo-vendor-distribution-wrapper-halo-test.mjs +93 -0
  461. package/scripts/topo-vendor-letter-halo-layers-test.mjs +93 -0
  462. package/scripts/topo-vendor-pill-glow-test.mjs +98 -0
  463. package/scripts/topo-watermark-breath-test.mjs +100 -0
  464. package/scripts/topo-watermark-dual-axis-breath-test.mjs +88 -0
  465. package/scripts/topo-watermark-envelope-breath-test.mjs +88 -0
  466. package/scripts/topo-watermark-recede-test.mjs +114 -0
  467. package/scripts/topo-watermark-triple-axis-breath-test.mjs +129 -0
  468. package/scripts/topo-working-online-chip-halo-layers-test.mjs +94 -0
  469. package/scripts/topo-zoom-buttons-brightness-test.mjs +94 -0
  470. package/scripts/topo-zoom-in-out-halo-layers-test.mjs +97 -0
  471. package/scripts/topo-zoom-level-breath-test.mjs +87 -0
  472. package/scripts/topo-zoom-level-brightness-test.mjs +83 -0
  473. package/scripts/topo-zoom-level-color-test.mjs +105 -0
  474. package/scripts/topo-zoom-level-dual-axis-breath-test.mjs +83 -0
  475. package/scripts/topo-zoom-level-halo-layers-test.mjs +78 -0
  476. package/scripts/topo-zoom-level-triple-axis-breath-test.mjs +148 -0
  477. package/.next/static/chunks/0fuba20p57-zo.js +0 -1
  478. package/.next/static/chunks/0m.1mvl~t.avc.css +0 -2
  479. package/.next/static/chunks/10cj-86disers.js +0 -1
  480. package/.next/static/chunks/158h2g7f-nxbt.js +0 -4
  481. /package/.next/server/chunks/{[externals]__11vad82._.js.map → 0ykm__next-internal_server_app_api_hub_upload_route_actions_03_eqnf.js.map} +0 -0
  482. /package/.next/static/{tQ1EtcEiS7ikgAoAyZWm7 → xq88BMF7fMUHWh10yaKTn}/_buildManifest.js +0 -0
  483. /package/.next/static/{tQ1EtcEiS7ikgAoAyZWm7 → xq88BMF7fMUHWh10yaKTn}/_clientMiddlewareManifest.js +0 -0
  484. /package/.next/static/{tQ1EtcEiS7ikgAoAyZWm7 → xq88BMF7fMUHWh10yaKTn}/_ssgManifest.js +0 -0
@@ -0,0 +1,117 @@
1
+ /* Round 740 — one-time canvas entrance animation. Plays on first
2
+ * paint, then the canvas sits at scale(1) opacity(1) for the rest of
3
+ * the session. Distinct from breath (infinite rest-axis) and ambient
4
+ * (infinite sweep-axis) — R740 is ONE-SHOT.
5
+ *
6
+ * Assertions:
7
+ * - .anet-topo-canvas-entrance class on root <svg> (reducedMotion off)
8
+ * - data-topo-canvas-entrance="true" attribute
9
+ * - CSS @keyframes 0% scale(0.99) opacity 0.8 → 100% scale(1) opacity 1
10
+ * - .anet-topo-canvas-entrance binds 600ms ease-out animation
11
+ * - CSS animation NOT infinite (no `infinite` keyword) — one-shot
12
+ * - transform-origin: 50% 50%
13
+ * - prefers-reduced-motion guard present
14
+ * - Animation completes within ~1s (test waits 1.2s after mount,
15
+ * then verifies computed transform is identity matrix)
16
+ * - Existing canvas className tokens (w-full h-auto block) preserved
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) => ({
39
+ alias, status: 'idle', 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: [mk('a·1'), mk('a·2')] } });
44
+ });
45
+ await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
46
+ await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
47
+ const page = await ctx.newPage();
48
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
49
+ await page.waitForSelector('[data-topo-canvas-aria]', { timeout: 15000, state: 'attached' });
50
+
51
+ /* Wait past the 600ms animation duration so computed transform settles
52
+ * to the final state (scale(1)). */
53
+ await page.waitForTimeout(1200);
54
+
55
+ const state = await page.evaluate(() => {
56
+ const svg = document.querySelector('[data-topo-canvas-aria]');
57
+ if (!svg) return null;
58
+ const cs = getComputedStyle(svg);
59
+ return {
60
+ has_entrance_class: svg.classList.contains('anet-topo-canvas-entrance'),
61
+ entrance_attr: svg.getAttribute('data-topo-canvas-entrance'),
62
+ class_attr: svg.getAttribute('class'),
63
+ anim_name: cs.animationName,
64
+ anim_duration: cs.animationDuration,
65
+ anim_iteration: cs.animationIterationCount,
66
+ transform_origin: cs.transformOrigin,
67
+ computed_transform: cs.transform,
68
+ computed_opacity: cs.opacity,
69
+ };
70
+ });
71
+
72
+ await browser.close();
73
+
74
+ const cssSrc = readFileSync('/home/vansin/agent-network-dashboard/app/globals.css', 'utf8');
75
+ const cssKfStart = /@keyframes anet-topo-canvas-entrance-kf\s*\{[\s\S]*?0%\s*\{[\s\S]*?transform:\s*scale\(0\.99\)[\s\S]*?opacity:\s*0\.8/.test(cssSrc);
76
+ const cssKfEnd = /@keyframes anet-topo-canvas-entrance-kf\s*\{[\s\S]*?100%\s*\{[\s\S]*?transform:\s*scale\(1\)[\s\S]*?opacity:\s*1/.test(cssSrc);
77
+ const cssClassBound = /\.anet-topo-canvas-entrance\s*\{[\s\S]*?animation:\s*anet-topo-canvas-entrance-kf\s+600ms\s+ease-out/.test(cssSrc);
78
+ /* The CSS source regex was too broad (matched `infinite` in OTHER
79
+ * class blocks past this one). Verify one-shot directly via the
80
+ * runtime computed animation-iteration-count — this is the property
81
+ * that actually determines whether the animation replays. */
82
+ const runtimeOneShot = state?.anim_iteration === '1';
83
+ const cssTransformOrigin = /\.anet-topo-canvas-entrance\s*\{[\s\S]*?transform-origin:\s*50%\s+50%/.test(cssSrc);
84
+ const cssReducedMotion = /@media\s*\(prefers-reduced-motion:\s*reduce\)\s*\{[\s\S]*?\.anet-topo-canvas-entrance\s*\{\s*animation:\s*none/.test(cssSrc);
85
+
86
+ /* After 1.2s the animation should have completed; computed transform
87
+ * should be identity-matrix (scale 1). matrix(1, 0, 0, 1, 0, 0) === 'none'
88
+ * in some browsers; accept either. */
89
+ const transformSettled = state?.computed_transform === 'none'
90
+ || state?.computed_transform === 'matrix(1, 0, 0, 1, 0, 0)';
91
+
92
+ const opacitySettled = parseFloat(state?.computed_opacity ?? '0') > 0.99;
93
+
94
+ const classKept = typeof state?.class_attr === 'string'
95
+ && state.class_attr.includes('w-full')
96
+ && state.class_attr.includes('h-auto')
97
+ && state.class_attr.includes('block')
98
+ && state.class_attr.includes('anet-topo-canvas-entrance');
99
+
100
+ const results = {
101
+ has_entrance_class: state?.has_entrance_class === true,
102
+ entrance_attr_true: state?.entrance_attr === 'true',
103
+ original_classes_preserved: classKept,
104
+ css_keyframe_start: cssKfStart,
105
+ css_keyframe_end: cssKfEnd,
106
+ css_class_binds_600ms_ease_out: cssClassBound,
107
+ runtime_animation_one_shot: runtimeOneShot,
108
+ css_transform_origin_center: cssTransformOrigin,
109
+ css_reduced_motion_guard: cssReducedMotion,
110
+ transform_settled_to_identity: transformSettled,
111
+ opacity_settled_to_1: opacitySettled,
112
+ };
113
+ const ok = Object.values(results).every(Boolean);
114
+ console.log(`${ok ? '✅' : '❌'} R740 one-time canvas entrance animation (scale 0.99→1 + opacity 0.8→1 @ 600ms ease-out, one-shot):`,
115
+ JSON.stringify(results, null, 2),
116
+ `\n state: ${JSON.stringify(state)}`);
117
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,148 @@
1
+ /* Round 739 — diagonal scan beam (3rd member of ambient scan beam
2
+ * family). Completes the trio from pair:
3
+ * R735 horizontal beam 30 s (top → bottom)
4
+ * R736 vertical beam 23 s (left → right)
5
+ * R739 diagonal beam 19 s (NW → SE) ← this round
6
+ *
7
+ * Coprime invariants:
8
+ * gcd(19, 23) = 1
9
+ * gcd(19, 30) = 1
10
+ * gcd(23, 30) = 1
11
+ * → 3 cadences pairwise coprime → never phase-lock as a trio.
12
+ *
13
+ * Assertions:
14
+ * - <line data-topo-canvas-scan-beam-diagonal> exists with 4 SMIL
15
+ * <animate> children on x1/y1/x2/y2 (all 19s, all repeatCount=indefinite)
16
+ * - opacity animate 0 → 0.06 → 0 at keyTimes 0/0.05/0.95/1, dur 19s
17
+ * - SVG <title>: "canvas scan beam diagonal · ambient sweep · 19s cycle"
18
+ * - data-topo-canvas-scan-beam-diagonal-active="true"
19
+ * - diagonal beam in background layer (rendered before nodes)
20
+ * - diagonal beam rendered AFTER vertical beam (trio document order)
21
+ * - all 3 beams alive (R735 + R736 regressions)
22
+ * - all 3 cadences pairwise coprime (Euclid check)
23
+ * - R717 patterns has 10 entries (was 9)
24
+ * - R717 includes new `scan-beam-trio` with shape "coprime-trio"
25
+ * and cadences [19, 23, 30]
26
+ * - R729 stats: patterns_count 10, ambient_patterns 2, ambient_cadences 3
27
+ * - R732 a11y catalog: 9 entries incl. diagonal beam
28
+ */
29
+ import { chromium } from 'playwright';
30
+ import { readFileSync } from 'node:fs';
31
+
32
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
33
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
34
+
35
+ const browser = await chromium.launch({ headless: true });
36
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
37
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
38
+ await ctx.addInitScript(() => {
39
+ try {
40
+ localStorage.setItem('anet-theme', 'cyber');
41
+ localStorage.setItem('anet-topo-layout', 'ring');
42
+ sessionStorage.setItem('anet_v3_auth', '1');
43
+ } catch {}
44
+ });
45
+ await ctx.route('**/api/hub/status*', async (route) => {
46
+ const r = await route.fetch();
47
+ const b = await r.json();
48
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
49
+ const mk = (alias) => ({
50
+ alias, status: 'idle', model: 'claude-opus-4', runtime: 'claude-code-cli',
51
+ network_id: nid, project_dir: null,
52
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
53
+ });
54
+ await route.fulfill({ response: r, json: { ...b, sessions: [mk('a·1'), mk('a·2')] } });
55
+ });
56
+ await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
57
+ await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
58
+ const page = await ctx.newPage();
59
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
60
+ await page.waitForSelector('[data-topo-canvas-scan-beam-diagonal]', { timeout: 15000, state: 'attached' });
61
+ await page.waitForTimeout(300);
62
+
63
+ const state = await page.evaluate(() => {
64
+ const dbeam = document.querySelector('[data-topo-canvas-scan-beam-diagonal]');
65
+ const vbeam = document.querySelector('[data-topo-canvas-scan-beam-vertical]');
66
+ const hbeam = document.querySelector('[data-topo-canvas-scan-beam]');
67
+ if (!dbeam) return null;
68
+ const getAnim = (el, attr) => el?.querySelector(`animate[attributeName="${attr}"]`);
69
+ const x1A = getAnim(dbeam, 'x1');
70
+ const y1A = getAnim(dbeam, 'y1');
71
+ const x2A = getAnim(dbeam, 'x2');
72
+ const y2A = getAnim(dbeam, 'y2');
73
+ const opA = getAnim(dbeam, 'opacity');
74
+ const dtitle = dbeam.querySelector(':scope > title');
75
+ const svg = document.querySelector('[data-topo-canvas-aria]');
76
+ const firstNode = svg?.querySelector('g[data-node]');
77
+ const dbeamBeforeNodes = dbeam && firstNode
78
+ ? (dbeam.compareDocumentPosition(firstNode) & Node.DOCUMENT_POSITION_FOLLOWING) !== 0
79
+ : null;
80
+ const dbeamAfterVbeam = vbeam && dbeam
81
+ ? (vbeam.compareDocumentPosition(dbeam) & Node.DOCUMENT_POSITION_FOLLOWING) !== 0
82
+ : null;
83
+ return {
84
+ dbeam_present: !!dbeam,
85
+ dbeam_active_attr: dbeam?.getAttribute('data-topo-canvas-scan-beam-diagonal-active') ?? null,
86
+ x1_dur: x1A?.getAttribute('dur'), x1_vals: x1A?.getAttribute('values'),
87
+ y1_dur: y1A?.getAttribute('dur'), y1_vals: y1A?.getAttribute('values'),
88
+ x2_dur: x2A?.getAttribute('dur'), x2_vals: x2A?.getAttribute('values'),
89
+ y2_dur: y2A?.getAttribute('dur'), y2_vals: y2A?.getAttribute('values'),
90
+ op_dur: opA?.getAttribute('dur'), op_vals: opA?.getAttribute('values'), op_kt: opA?.getAttribute('keyTimes'),
91
+ dtitle_text: dtitle?.textContent ?? null,
92
+ dbeam_before_nodes: dbeamBeforeNodes,
93
+ dbeam_after_vbeam: dbeamAfterVbeam,
94
+ hbeam_present: !!hbeam,
95
+ vbeam_present: !!vbeam,
96
+ patterns: svg?.getAttribute('data-topo-respiratory-patterns') ?? null,
97
+ stats: svg?.getAttribute('data-topo-respiratory-axis-count-stats') ?? null,
98
+ a11y: svg?.getAttribute('data-topo-a11y-titles') ?? null,
99
+ };
100
+ });
101
+
102
+ await browser.close();
103
+
104
+ const gcd = (a, b) => (b === 0 ? a : gcd(b, a % b));
105
+ const coprime_trio = gcd(19, 23) === 1 && gcd(19, 30) === 1 && gcd(23, 30) === 1;
106
+
107
+ let patterns = null;
108
+ let stats = null;
109
+ let a11y = null;
110
+ try {
111
+ patterns = JSON.parse(state?.patterns ?? '');
112
+ stats = JSON.parse(state?.stats ?? '');
113
+ a11y = JSON.parse(state?.a11y ?? '');
114
+ } catch {}
115
+
116
+ const trioEntry = Array.isArray(patterns) ? patterns.find(p => p.name === 'scan-beam-trio') : null;
117
+ const trioCorrect = !!trioEntry
118
+ && JSON.stringify(trioEntry.cadences) === JSON.stringify([19, 23, 30])
119
+ && trioEntry.shape === 'coprime-trio'
120
+ && Array.isArray(trioEntry.anchors) && trioEntry.anchors.length === 3
121
+ && trioEntry.anchors.includes('scan beam diagonal');
122
+
123
+ const results = {
124
+ dbeam_line_present: state?.dbeam_present === true,
125
+ dbeam_active_true: state?.dbeam_active_attr === 'true',
126
+ x1_anim_full: state?.x1_dur === '19s' && state?.x1_vals === '-100;1100;-100',
127
+ y1_anim_full: state?.y1_dur === '19s' && state?.y1_vals === '-100;780;-100',
128
+ x2_anim_full: state?.x2_dur === '19s' && state?.x2_vals === '-30;1170;-30',
129
+ y2_anim_full: state?.y2_dur === '19s' && state?.y2_vals === '-30;850;-30',
130
+ op_anim_ramped: state?.op_dur === '19s' && state?.op_vals === '0;0.06;0.06;0' && state?.op_kt === '0;0.05;0.95;1',
131
+ dbeam_a11y_title: state?.dtitle_text === 'canvas scan beam diagonal · ambient sweep · 19s cycle',
132
+ dbeam_background_layer: state?.dbeam_before_nodes === true,
133
+ dbeam_after_vertical: state?.dbeam_after_vbeam === true,
134
+ all_three_beams_present: state?.dbeam_present && state?.vbeam_present && state?.hbeam_present,
135
+ coprime_trio_pairwise: coprime_trio,
136
+ r717_has_10_entries: Array.isArray(patterns) && patterns.length === 10,
137
+ r717_trio_entry_correct: trioCorrect,
138
+ r729_patterns_count_10: stats?.patterns_count === 10,
139
+ r729_ambient_patterns_2: stats?.ambient_patterns === 2,
140
+ r729_ambient_cadences_3: stats?.ambient_cadences === 3,
141
+ r732_a11y_has_9_entries: Array.isArray(a11y) && a11y.length === 9,
142
+ };
143
+ const ok = Object.values(results).every(Boolean);
144
+ console.log(`${ok ? '✅' : '❌'} R739 diagonal scan beam (3rd ambient member, completes scan-beam-trio with pairwise-coprime cadences):`,
145
+ JSON.stringify(results, null, 2),
146
+ `\n trio entry: ${JSON.stringify(trioEntry)}`,
147
+ `\n gcd: 19-23=${gcd(19,23)} 19-30=${gcd(19,30)} 23-30=${gcd(23,30)}`);
148
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,109 @@
1
+ /* Round 735 — SVG scan beam: ambient living-system sweep across the
2
+ * canvas every 30 s. Pivot round: first genuinely new VISIBLE
3
+ * animation outside the breath / a11y / meta-doc threads since R720.
4
+ *
5
+ * Spec:
6
+ * - 1 px tall horizontal cyan stripe (pal.legendAccent)
7
+ * - y animates -2 → 680 → -2 over 30 s repeatCount=indefinite
8
+ * - opacity animates 0 → 0.08 → 0.08 → 0 at keyTimes 0/0.05/0.95/1
9
+ * - pointer-events: none, no business logic
10
+ * - rendered AFTER panel backdrop, BEFORE all other canvas content
11
+ * (background layer; nodes paint over it)
12
+ * - gated by !reducedMotion at JSX level
13
+ * - SVG <title> child for a11y ("canvas scan beam · ambient sweep · 30s cycle")
14
+ *
15
+ * Assertions:
16
+ * - <rect data-topo-canvas-scan-beam> exists
17
+ * - Two <animate> children: attributeName="y" and attributeName="opacity"
18
+ * - y animate has values "-2;680;-2" and dur "30s"
19
+ * - opacity animate has values "0;0.08;0.08;0" and dur "30s"
20
+ * - <title> child has the expected accessible name
21
+ * - data-topo-canvas-scan-beam-active="true" (reducedMotion off in test)
22
+ * - Beam is rendered BEFORE nodes (background-layer z-order)
23
+ * - R732 a11y-titles catalog has the scan-beam entry (7 total)
24
+ * - Overlap-test selectors don't match the rect (no data-node /
25
+ * data-group, no matching translate prefix) — verified indirectly
26
+ * by overlap test still passing
27
+ */
28
+ import { chromium } from 'playwright';
29
+ import { readFileSync } from 'node:fs';
30
+
31
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
32
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
33
+
34
+ const browser = await chromium.launch({ headless: true });
35
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
36
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
37
+ await ctx.addInitScript(() => {
38
+ try {
39
+ localStorage.setItem('anet-theme', 'cyber');
40
+ localStorage.setItem('anet-topo-layout', 'ring');
41
+ sessionStorage.setItem('anet_v3_auth', '1');
42
+ } catch {}
43
+ });
44
+ await ctx.route('**/api/hub/status*', async (route) => {
45
+ const r = await route.fetch();
46
+ const b = await r.json();
47
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
48
+ const mk = (alias) => ({
49
+ alias, status: 'idle', model: 'claude-opus-4', runtime: 'claude-code-cli',
50
+ network_id: nid, project_dir: null,
51
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
52
+ });
53
+ await route.fulfill({ response: r, json: { ...b, sessions: [mk('a·1'), mk('a·2')] } });
54
+ });
55
+ await ctx.route('**/api/hub/messages*', (r) => r.fulfill({ json: { messages: [] } }));
56
+ await ctx.route('**/api/hub/tasks*', (r) => r.fulfill({ json: { tasks: [] } }));
57
+ const page = await ctx.newPage();
58
+ await page.goto('http://127.0.0.1:3000/', { waitUntil: 'networkidle' });
59
+ await page.waitForSelector('[data-topo-canvas-scan-beam]', { timeout: 15000, state: 'attached' });
60
+ await page.waitForTimeout(300);
61
+
62
+ const state = await page.evaluate(() => {
63
+ const beam = document.querySelector('[data-topo-canvas-scan-beam]');
64
+ if (!beam) return null;
65
+ const yAnim = beam.querySelector('animate[attributeName="y"]');
66
+ const opAnim = beam.querySelector('animate[attributeName="opacity"]');
67
+ const titleEl = beam.querySelector(':scope > title');
68
+ const svg = document.querySelector('[data-topo-canvas-aria]');
69
+ const firstNode = svg?.querySelector('g[data-node]');
70
+ const beamBeforeNodes = beam && firstNode
71
+ ? (beam.compareDocumentPosition(firstNode) & Node.DOCUMENT_POSITION_FOLLOWING) !== 0
72
+ : null;
73
+ const catalogAttr = svg?.getAttribute('data-topo-a11y-titles') ?? null;
74
+ return {
75
+ beam_present: !!beam,
76
+ beam_active_attr: beam?.getAttribute('data-topo-canvas-scan-beam-active') ?? null,
77
+ beam_width: beam?.getAttribute('width') ?? null,
78
+ beam_height: beam?.getAttribute('height') ?? null,
79
+ y_anim_present: !!yAnim,
80
+ y_anim_values: yAnim?.getAttribute('values') ?? null,
81
+ y_anim_dur: yAnim?.getAttribute('dur') ?? null,
82
+ y_anim_repeat: yAnim?.getAttribute('repeatCount') ?? null,
83
+ op_anim_present: !!opAnim,
84
+ op_anim_values: opAnim?.getAttribute('values') ?? null,
85
+ op_anim_dur: opAnim?.getAttribute('dur') ?? null,
86
+ op_anim_keytimes: opAnim?.getAttribute('keyTimes') ?? null,
87
+ title_text: titleEl?.textContent ?? null,
88
+ beam_before_nodes: beamBeforeNodes,
89
+ catalog_has_entry: typeof catalogAttr === 'string' && catalogAttr.includes('canvas scan beam'),
90
+ };
91
+ });
92
+
93
+ await browser.close();
94
+
95
+ const results = {
96
+ beam_rect_present: state?.beam_present === true,
97
+ beam_active_true: state?.beam_active_attr === 'true',
98
+ beam_full_width_1px: state?.beam_width === '1000' && state?.beam_height === '1',
99
+ y_anim_full_sweep: state?.y_anim_present === true && state?.y_anim_values === '-2;680;-2' && state?.y_anim_dur === '30s' && state?.y_anim_repeat === 'indefinite',
100
+ opacity_anim_ramped: state?.op_anim_present === true && state?.op_anim_values === '0;0.08;0.08;0' && state?.op_anim_dur === '30s' && state?.op_anim_keytimes === '0;0.05;0.95;1',
101
+ a11y_title_present: state?.title_text === 'canvas scan beam · ambient sweep · 30s cycle',
102
+ beam_in_background_layer: state?.beam_before_nodes === true,
103
+ r732_catalog_includes_beam: state?.catalog_has_entry === true,
104
+ };
105
+ const ok = Object.values(results).every(Boolean);
106
+ console.log(`${ok ? '✅' : '❌'} R735 SVG canvas scan beam (ambient 30s sweep, first non-introspection visible animation since R720):`,
107
+ JSON.stringify(results, null, 2),
108
+ `\n state: ${JSON.stringify(state)}`);
109
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,123 @@
1
+ /* Round 736 — vertical scan beam companion to R735's horizontal beam.
2
+ * Forms the "scan beam" ambient family — coprime cadences mean the
3
+ * beams never phase-lock; over time the visual rhythm reads as
4
+ * "ambient crosshair drift".
5
+ *
6
+ * R735 horizontal beam 30 s (top → bottom)
7
+ * R736 vertical beam 23 s (left → right) ← this round
8
+ * gcd(23, 30) = 1
9
+ *
10
+ * Assertions:
11
+ * - <rect data-topo-canvas-scan-beam-vertical> exists with 1×680 box
12
+ * - x animates -2 → 1000 → -2 over 23s repeatCount=indefinite
13
+ * - opacity animates 0 → 0.08 → 0.08 → 0 at keyTimes 0/0.05/0.95/1, dur 23s
14
+ * - SVG <title> child = "canvas scan beam vertical · ambient sweep · 23s cycle"
15
+ * - data-topo-canvas-scan-beam-vertical-active="true" (reducedMotion off)
16
+ * - vertical beam in background layer (rendered before nodes)
17
+ * - vertical beam rendered AFTER horizontal beam (pair grouping)
18
+ * - R735 horizontal beam still intact (regression — y, dur, title preserved)
19
+ * - coprime cadences: gcd(23, 30) === 1 — verified by checking the
20
+ * two beams' durs are 23s/30s and Math.gcd-equivalent reduces to 1
21
+ * - R732 a11y-titles catalog has 8 entries incl. vertical beam
22
+ */
23
+ import { chromium } from 'playwright';
24
+ import { readFileSync } from 'node:fs';
25
+
26
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
27
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
28
+
29
+ const browser = await chromium.launch({ headless: true });
30
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
31
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
32
+ await ctx.addInitScript(() => {
33
+ try {
34
+ localStorage.setItem('anet-theme', 'cyber');
35
+ localStorage.setItem('anet-topo-layout', 'ring');
36
+ sessionStorage.setItem('anet_v3_auth', '1');
37
+ } catch {}
38
+ });
39
+ await ctx.route('**/api/hub/status*', async (route) => {
40
+ const r = await route.fetch();
41
+ const b = await r.json();
42
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
43
+ const mk = (alias) => ({
44
+ alias, status: 'idle', model: 'claude-opus-4', runtime: 'claude-code-cli',
45
+ network_id: nid, project_dir: null,
46
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
47
+ });
48
+ await route.fulfill({ response: r, json: { ...b, sessions: [mk('a·1'), mk('a·2')] } });
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('[data-topo-canvas-scan-beam-vertical]', { timeout: 15000, state: 'attached' });
55
+ await page.waitForTimeout(300);
56
+
57
+ const state = await page.evaluate(() => {
58
+ const vbeam = document.querySelector('[data-topo-canvas-scan-beam-vertical]');
59
+ const hbeam = document.querySelector('[data-topo-canvas-scan-beam]');
60
+ if (!vbeam || !hbeam) return null;
61
+ const xAnim = vbeam.querySelector('animate[attributeName="x"]');
62
+ const opAnim = vbeam.querySelector('animate[attributeName="opacity"]');
63
+ const vtitle = vbeam.querySelector(':scope > title');
64
+ const yAnim = hbeam.querySelector('animate[attributeName="y"]');
65
+ const htitle = hbeam.querySelector(':scope > title');
66
+ const svg = document.querySelector('[data-topo-canvas-aria]');
67
+ const firstNode = svg?.querySelector('g[data-node]');
68
+ const vbeamBeforeNodes = vbeam && firstNode
69
+ ? (vbeam.compareDocumentPosition(firstNode) & Node.DOCUMENT_POSITION_FOLLOWING) !== 0
70
+ : null;
71
+ const vbeamAfterHbeam = hbeam && vbeam
72
+ ? (hbeam.compareDocumentPosition(vbeam) & Node.DOCUMENT_POSITION_FOLLOWING) !== 0
73
+ : null;
74
+ const catalogAttr = svg?.getAttribute('data-topo-a11y-titles') ?? null;
75
+ return {
76
+ vbeam_present: !!vbeam,
77
+ vbeam_active_attr: vbeam?.getAttribute('data-topo-canvas-scan-beam-vertical-active') ?? null,
78
+ vbeam_width: vbeam?.getAttribute('width') ?? null,
79
+ vbeam_height: vbeam?.getAttribute('height') ?? null,
80
+ x_anim_present: !!xAnim,
81
+ x_anim_values: xAnim?.getAttribute('values') ?? null,
82
+ x_anim_dur: xAnim?.getAttribute('dur') ?? null,
83
+ x_anim_repeat: xAnim?.getAttribute('repeatCount') ?? null,
84
+ op_anim_present: !!opAnim,
85
+ op_anim_values: opAnim?.getAttribute('values') ?? null,
86
+ op_anim_dur: opAnim?.getAttribute('dur') ?? null,
87
+ op_anim_keytimes: opAnim?.getAttribute('keyTimes') ?? null,
88
+ vtitle_text: vtitle?.textContent ?? null,
89
+ hbeam_present: !!hbeam,
90
+ hbeam_y_dur: yAnim?.getAttribute('dur') ?? null,
91
+ hbeam_y_values: yAnim?.getAttribute('values') ?? null,
92
+ htitle_text: htitle?.textContent ?? null,
93
+ vbeam_before_nodes: vbeamBeforeNodes,
94
+ vbeam_after_hbeam: vbeamAfterHbeam,
95
+ catalog_includes_vbeam: typeof catalogAttr === 'string' && catalogAttr.includes('canvas scan beam vertical'),
96
+ };
97
+ });
98
+
99
+ await browser.close();
100
+
101
+ const gcd = (a, b) => (b === 0 ? a : gcd(b, a % b));
102
+ const coprime_23_30 = gcd(23, 30) === 1;
103
+
104
+ const results = {
105
+ vbeam_rect_present: state?.vbeam_present === true,
106
+ vbeam_active_true: state?.vbeam_active_attr === 'true',
107
+ vbeam_1px_full_height: state?.vbeam_width === '1' && state?.vbeam_height === '680',
108
+ x_anim_full_sweep: state?.x_anim_present === true && state?.x_anim_values === '-2;1000;-2' && state?.x_anim_dur === '23s' && state?.x_anim_repeat === 'indefinite',
109
+ vbeam_opacity_anim_ramped: state?.op_anim_present === true && state?.op_anim_values === '0;0.08;0.08;0' && state?.op_anim_dur === '23s' && state?.op_anim_keytimes === '0;0.05;0.95;1',
110
+ vbeam_a11y_title_present: state?.vtitle_text === 'canvas scan beam vertical · ambient sweep · 23s cycle',
111
+ vbeam_in_background_layer: state?.vbeam_before_nodes === true,
112
+ vbeam_after_horizontal_beam: state?.vbeam_after_hbeam === true,
113
+ hbeam_y_30s_preserved: state?.hbeam_y_dur === '30s' && state?.hbeam_y_values === '-2;680;-2',
114
+ hbeam_title_preserved: state?.htitle_text === 'canvas scan beam · ambient sweep · 30s cycle',
115
+ coprime_cadences_23_30: coprime_23_30,
116
+ r732_catalog_includes_vbeam: state?.catalog_includes_vbeam === true,
117
+ };
118
+ const ok = Object.values(results).every(Boolean);
119
+ console.log(`${ok ? '✅' : '❌'} R736 vertical scan beam (companion to R735, coprime cadences form ambient crosshair pair):`,
120
+ JSON.stringify(results, null, 2),
121
+ `\n state: ${JSON.stringify(state)}`,
122
+ `\n gcd(23, 30) = ${gcd(23, 30)}`);
123
+ process.exit(ok ? 0 : 1);
@@ -0,0 +1,86 @@
1
+ /* Round 618 — extend label card hover treatments (stroke +
2
+ * filter brightness) gate from hover-only to (hover || chat-
3
+ * target). 4th anchor in chat-target-gated brightness family.
4
+ *
5
+ * Test phases:
6
+ * 1. mock 2 idle nodes → label cards render
7
+ * 2. rest (no hover, no chat): rest filter (shallow DS, NO
8
+ * brightness), brightness-attr='1', elevation='idle',
9
+ * chat-target='false'
10
+ * 3. computed transition-property contains 'filter'
11
+ * 4. source: stroke + filter conditionals include BOTH hover
12
+ * AND chat gates joined by `||`
13
+ */
14
+ import { chromium } from 'playwright';
15
+ import { readFileSync } from 'node:fs';
16
+
17
+ const TOKEN = JSON.parse(readFileSync('/home/vansin/.anet/config.json', 'utf8')).token;
18
+ const fresh = new Date(Date.now() - 60 * 1000).toISOString();
19
+
20
+ const browser = await chromium.launch({ headless: true });
21
+ const ctx = await browser.newContext({ viewport: { width: 1500, height: 1200 } });
22
+ await ctx.addCookies([{ name: 'anet_dashboard_session', value: `v3:${TOKEN}`, domain: '127.0.0.1', path: '/' }]);
23
+ await ctx.addInitScript(() => {
24
+ try {
25
+ localStorage.setItem('anet-theme', 'cyber');
26
+ localStorage.setItem('anet-topo-layout', 'ring');
27
+ sessionStorage.setItem('anet_v3_auth', '1');
28
+ } catch {}
29
+ });
30
+ await ctx.route('**/api/hub/status*', async (route) => {
31
+ const r = await route.fetch();
32
+ const b = await r.json();
33
+ const nid = (b.sessions || [])[0]?.network_id || 'default';
34
+ const mk = (alias) => ({
35
+ alias, status: 'idle', model: 'claude-opus-4', runtime: 'claude-code-cli',
36
+ network_id: nid, project_dir: null,
37
+ created_at: fresh, updated_at: fresh, last_seen_at: fresh,
38
+ });
39
+ await route.fulfill({ response: r, json: { ...b, sessions: [mk('a·1'), mk('a·2')] } });
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-node-label-card-chat-target]', { timeout: 15000, state: 'attached' });
46
+ await page.waitForTimeout(500);
47
+
48
+ const rest = await page.evaluate(() => {
49
+ const el = document.querySelector('[data-node-label-card-chat-target]');
50
+ if (!el) return null;
51
+ const cs = getComputedStyle(el);
52
+ return {
53
+ filter: cs.filter,
54
+ transitionProperty: cs.transitionProperty,
55
+ brightnessAttr: el.getAttribute('data-node-label-card-brightness'),
56
+ elevationAttr: el.getAttribute('data-node-label-card-elevation'),
57
+ chatTargetAttr: el.getAttribute('data-node-label-card-chat-target'),
58
+ };
59
+ });
60
+
61
+ await browser.close();
62
+
63
+ const src = readFileSync('/home/vansin/agent-network-dashboard/app/components/TopoGraph.tsx', 'utf8');
64
+ const sourceFilterOr = /filter: !reducedMotion && \(hoveredAlias === session\.alias \|\| chatAlias === session\.alias\)\s*\?\s*\(isLight/.test(src);
65
+ const sourceStrokeOr = /stroke=\{!reducedMotion && \(hoveredAlias === session\.alias \|\| chatAlias === session\.alias\)/.test(src);
66
+ const sourceAttrOr = /data-node-label-card-brightness=\{!reducedMotion && \(hoveredAlias === session\.alias \|\| chatAlias === session\.alias\) \? '1\.15' : '1'\}/.test(src);
67
+ const sourceChatAttr = /data-node-label-card-chat-target=\{chatAlias === session\.alias \? 'true' : 'false'\}/.test(src);
68
+
69
+ const results = {
70
+ card_present: !!rest,
71
+ rest_has_drop_shadow: /drop-shadow/.test(rest?.filter || ''),
72
+ rest_no_brightness: !/brightness/.test(rest?.filter || ''),
73
+ rest_brightness_1: rest?.brightnessAttr === '1',
74
+ rest_elevation_idle: rest?.elevationAttr === 'idle',
75
+ rest_chat_target_false: rest?.chatTargetAttr === 'false',
76
+ transition_has_filter: /filter/.test(rest?.transitionProperty || ''),
77
+ source_filter_or: sourceFilterOr,
78
+ source_stroke_or: sourceStrokeOr,
79
+ source_attr_or: sourceAttrOr,
80
+ source_chat_attr: sourceChatAttr,
81
+ };
82
+ const ok = Object.values(results).every(Boolean);
83
+ console.log(`${ok ? '✅' : '❌'} R618 card chat-target brightness (chat-gated family 4th anchor):`,
84
+ JSON.stringify(results, null, 2),
85
+ `\n rest: ${JSON.stringify(rest)}`);
86
+ process.exit(ok ? 0 : 1);