From 54c56633cde1c059d1a8b1a43fb9f2e336e14e99 Mon Sep 17 00:00:00 2001 From: archandatta <35818003+archandatta@users.noreply.github.com> Date: Wed, 10 Jun 2026 12:36:42 +0000 Subject: [PATCH 01/10] refactor: promote TelemetryEventCategory to a named schema Co-Authored-By: Claude Opus 4.7 --- server/lib/oapi/oapi.go | 718 ++++++++++++++++++++-------------------- server/openapi.yaml | 28 +- 2 files changed, 374 insertions(+), 372 deletions(-) diff --git a/server/lib/oapi/oapi.go b/server/lib/oapi/oapi.go index 901aa0a9..e4aa146a 100644 --- a/server/lib/oapi/oapi.go +++ b/server/lib/oapi/oapi.go @@ -18845,365 +18845,365 @@ func (sh *strictHandler) StreamTelemetryEvents(w http.ResponseWriter, r *http.Re var swaggerSpec = []string{ "H4sIAAAAAAAC/+y9iXIjOXYo+isIPke0ZJOUqrp67KkKxwu1pJqWuxY9SdVtz6gfCWYekhglgRwASYnd", - "UY77EfcL75e8wDlALiSSi5Za/CrC4akWE+tZcdY/Ooma5UqCtKbz8o+OBpMraQD/40eeXsA/CjD2VGul", - "3Z8SJS1I6/7J8zwTCbdCyYO/GyXd30wyhRl3//onDePOy87/dVDNf0C/mgOa7ePHj91OCibRIneTdF66", - "BZlfsfOx2zlWcpyJ5FOtHpZzS59JC1ry7BMtHZZjl6DnoJn/sNt5p+xrVcj0E+3jnbIM1+u43/znhAo2", - "mR6rWV5Y0EeJ+zwAyu0kTYX7E8/OtcpBW+EQaMwzA8srHLGRm4qpMUv8dIzjfIZZxeAOksICM25yaQXP", - "skW/0+3ktXn/6PgB7p/N2d/rFDSkLBPGuiVWZ+6zU/yHUJIZq3LDlGR2CmwstLEM3M24BYWFmdl0j80L", - "cfCaCXlGI591O3aRQ+dlh2vNF3ihGv5RCA1p5+XfyjP8Vn6nRn8Hwr4ftbo1oI9yccyz7HTuAb50k5L9", - "dHV1zhKeZWzKZZpBykYLPMwNaAlZT8z4BEyP54IZRKzVq0y4hYnSC/dvkMXMbc3hmFZZbWvGaiEnbmsp", - "txvRK7L9EzfMoZQqdAJbToAjL2nEx27H6kK67aard3GlC2BijGd3O2RjAVnKbrlh5SiWFuAQwYjfgWVi", - "Jqxx1+FPOFIqA44wtBHEwq0wK2ZgLJ/lTEj2QYo7NhOJVgYSJVOcbaz0jNvOy46Q9k8vqumFtDABJGn6", - "S3XbPBcDB8PIdS+hjDVhwm4Ft/JOt0SkEw/AHWj2HHQPsSzni0zxlI2VZsOw7yEDN69Zxa200MidBrPI", - "jf7Ks6yXZCq5YeE7R7EOgoTM2l3yTGSZqN2vP6EsZiO6TbceLSIiePE+B3l0fsbKr87SsMjMsSFImVaO", - "3+xBf9Jnw1yrBIxxLGLYZUPLb+Ay0QDSTJUd7td2UFGEJj4YXd/dnP+didQxtLEAzcZazVroNHw9E2ma", - "wS3XEF3UWG6LyK0iRwhCnNFXLFFpfZYSF5fQq3aQpXst1+s2YLoG4xy6XVqe3Kxu8fjknF0U0tFSHz+5", - "0jwBpiHXYNwVyQnezX/wOb/EccTijPuWcYs/utHI4CVhX5+9dhRvWGGAuRUkn7mJEiXdzygENLdT0MxO", - "uWRG8hsYJNwgS0BcwHmPp1rNgJ3A/EqpzLBzraxKVMZuhQZG1N2/lhE2mmWvNZ/BFkIJTzPGj7vMYZ+e", - "KWNJADVEz9ISKitm8h1h/soifwWteiNuIGX0ISMaYbfCTgWJuEzIKB50O+NCojh6x2ewOncNEuFDd7/Q", - "ZUozmOV2wQgzkTFwqeRipgpTfmyiKOx2s8Vp3GeRs9DX8dPQb2dpHPfov2vkGN1dobPV4R8u3rgju7MH", - "NuJnG4ssRqhLFNa45to+abnGlXSb8I6RWlO9WGLaq5yQmD3L+AgyBBRuH4nKIgUSD+RmIROW8MJAnN/l", - "XAcFNMvejzsv/7aVMK84wsffVgQMTtnYDGISbgX/avorl1kjubWMKLfJlF+qbA4XYIrMtqlTLKFPmXHf", - "Mm6tQ22mgaOc4MwRqnBXqAqbqBlsqUzRrA9VplrO8U2vatWr/MUPEJwDjXf2hDrWOgDtrm4F7GtoXLET", - "tWtf4etwL0uc0CP7HGSqNBvzmcgWfSfv0iIBbZh0N545mOZazUUKumdySMRYJMxyc4Nc0DAhrWJ2Kgwz", - "YF8ycA/ZXAsDbM614NIaxyk1BOJKVJbx3EAYCEKzOWjjZMqoSG7Asr35c3bA5t/vdxmXKeNy4bj+hEll", - "WaLmKEuJV7nLPVFOEL21/kBdlmdcSPb++GKfCePUCqUdlnLDhsopAEOS3wFNpoFAHR6EO5s/b/7n9w4p", - "Ci2NFZnDjAmAdW/fbgenjBP3rtovaoXEfIzl2jqiivGcFR0YH60Dp+WtLoT4WAMdfosaoXv4jrnICl2q", - "v6cXF+8vBsdH51fHPx0NPry7fP/ml6Mf35wO9/vsaOSUMzfIFIlTknfSS6+Wz8GGfprhSzqzZhrcFSOr", - "LQwfZeB+wJd6nw39TmNfS3+oPQPAhtVluF0PHWtRha3GpSJFTKLxdZXCCRTQ3xl2y4VloyKdgO2zIR9x", - "mSoJ6fCl/4QlXCaQufe2F6M5nwCTfC4myBH5LV84Db6HazbxzR/b8TQ6krtG2mSn2ykXi6KUo7voO8ND", - "mRsjJu5OasoNe5/zfxTQdZrxuCDJb4rcUQVzPNb0NIxBg0wgDtJbGBlhYTBVJiI2f1Kk1Ja3cDsFDf4+", - "ieSdtMCLSNfOn3M7jbyguJ1uPz/7fwrQpTYKd0lWpNFlV3SJGq+8x2snzY+VlJDYdlsN3HkTX5IJR0hE", - "cklhrJqBZpcnP3fZecYXt1pMprbLzos8Bwug990jxs0NKSOWiQ+cX2F0qZBf5lrdLciMJQz75e3WRh43", - "qdtfDNW+KRSrCkWaD/ytPaUekeYnwiS7olNajoG0si9sQBR2zgW9qvBrMZtBKriFbMFyDQmkjoqGtXMP", - "g7XUuCeQsRr47FHQbRdNeOWCvinBa3G2Qo1Pirb31Hyr3S4pv42TPL7RsULQreyOMzCGT2CQqCJGofRs", - "d3M7EvQfO2004wunIKDkjawLAm1UqdD0t7iBQwM3sUf+r9PF8pwgnQBkQ2ITgyRTxilR+BVxDiGFFYjD", - "9EdlnHZW5ETdg2TK5QSVH7SNiWLGNKB+CinpOGBQe3e6Okpp5DJWaWCpupXMqPpqiSqy1L0HPIz5hAtp", - "yKgn4ZaFdetbQJVu+LL8jaXCaZI63CvLi1lOSiCdVUkLd3ZQqmn+wMG26n9HCq5UuT27yIVT8BbeWcLM", - "tLDuCPtNDa5+lZ1uZ/mm6n/CPaEtZ2lHmymxjsfL6FZiwDqCVNKoDNDV12ryGNG37kbcx16RVpo5tlZM", - "prZuhYW7BHJCKjK5ns6ErcTNrXJCyAqZWER64hmGxEsqxqhkWuKgZspzMP3SDuzXPzo/O+YEDP+Xvn+v", - "8Cwz+w613OvUsAzmkHWZu9Mu43pi6KmIpqIBGpCqucttX021w8e98mzlL/Wpac5MSOh6S2rXH2VQ6Cyy", - "jjc8uzeF98i6p4vX1Ggk4xoYxwdU3HgclZfu/A8WlstY8E1WtstKuitPtE8oKqMw2dWeiiOPia90PnaX", - "vQWOKCIUn2UlrXM9KWZuZpYo0Am9Luisps/OyRnDlMwW7s0lPSp7am8j3Ib/YvX9umSxJvqKGKcaHoyG", - "xb/2/qv4EaIXUvfWG1/iCnE5i2wm7kUIt+gGsTnP3AubZ7d8Ydg1GWSuOw+6xai/ZHUvb2rukc93URWD", - "bHGarDhLmJ2iK0/DbXOPj7CxhjkqMOqt7eylm6LbQdpaZUEokoLu4b6p9iwkGyk7DXw/53ZqNpsfcJ1V", - "jvHbCs94oyZby/JMTUhQV8I0U5Nu+L0v5FhV/3XLtewysEl/v/8ZBFQ42DfxtFE8ZWry9MKpAY8vSzTt", - "JGHWcPBW3dPN0WU5NwbfRFoVkykr5FhkFn0PyIUoUKDv7c1DdDWowtvoGpqEf6ky98wBnr5iPMsYug3Y", - "siAxToMErplj3X12CWTBMTkkpcd2XGQZczhBmuSnYXmvMThuGTyr0NnM6ggg3S1YXgOLVnbkP/IcLrzo", - "kOiqMLjAEmdKCuseNtIqvP7jk/NeECrekMDOgs2c3uWW6wnYLgVqkNrvDfz4AspVMnXUfTsVPnSEdqKS", - "pNDuGRrR83GqqP3eQRl/rUcJ1VwTtJm4WqB4Crp11lQlBCv6rjZ/173jAT06wJNp7XTRdSSfDwz8Y3WV", - "t0oqq6R/OguZuLcp+uuq66JwziRoKl36zO0L0nIDVuU9RI/6yOglbME9vVWi9V6C1aIeleUpjNapGVGi", - "90FfRecPuOknqi2xZyy+Dr39pzqnCQflzPLR/roVg1zYgrKvcMSVG7AupEVDBnMuyeE4FYZQ+RX5W9wH", - "Ywx6KWHiaAF/I9LploaV8luwt0rf1Gx065lCDVj1i20euULBNeKrrgrsaHvUag6SOySdgeWoHXjILRw2", - "E6F7M4Fm4G0fJeWvak0Q19SCi73mk0XOgVFF3hHbJpuGeL117lVabvCq44hzI2TapqqEA/XRwhqsfLEI", - "OC/GSt+CZ659NqQoxgHPxfAl+xn/gx2dnwUz2p7jM3oOZMilP/YmIEGjuhV2zoZwZ0E6RBi+ZEL+nXwZ", - "fj/lb302zFTCs4GP1Ry+ZGZhLMyY/wPThZQOYjxTcmJECo3tNk15ad7pdqr9u5/CQh3HW2sLRTXdgCrt", - "yBZRUjbhQ5BmhAyOWxEdHHg6OSBRcXbSgHeghSXaQuCvoZifrM1/AicbTPshrC5WCAZDTac0ks147qB7", - "y3WKsRY94THF7d6xNlXYMqSEhAz7xb2aDdrGaqZX0vLYqLBsxhdsBIzLBfuPy/fvUEVqaD0rh8E8Coqs", - "P85EcrPxsVTgi8l9GjQJntvCaXlzwSskRG5XhRxufh2JaiMPfSFFz/TtndT6Tqpd/QAh+4SvpXbYPPKb", - "yUAGiVWRUNnjy0sWfkV7QzA949kdf81Q0WpRKSaxGPK3b5jlk0ac69JsDmBFnoPGEGpiVD9+uLp6/67L", - "jrrs5OyXFh0mqsz/IoxAo7njej7DqWXhLrMa/dTR6e9ic8MtBrvc9RKldCokt81TubO4W8zFHWQmbuBa", - "rJl4cf+Jl/DwruNW6lbQJgitfSbVUPBnWGxkeDewGCmu06+B3YXzfGN2WzG7G1h8GlbXgMsjMzp3iJUL", - "/BkWZGOvtM+fPR7T3RIDOnVb7LIfeXJjcp64V3ucC92Dmwa+h2brKQYlJIUh8zRl8iwQY3INxrRwp+25", - "LU6+ntuevTv/cNVlV6f/eXV0cdrOc5fVQXgAg7lMtMqyS7A2g3QjqzH4NTP0uWc44d3Ex7b6JFdG1DIy", - "0ZEu5KT7ZbOn1dv4xqi2YlQE9YFHjE/Ds1qA9cjcy7GnQUQJodXZXa/EdJ/HRoHelXvMfTUB45B+G7UE", - "11u0rrd47PW8PeYe/JPW2qSOqtjlvcbAcbN6hchC3OThBIHVbHMSFbu3xlKLR1lqOQWMMKQEnT+039Dq", - "Da9lzW/EHJwauiH4mGViDmwu4LaKwlqKKHbv+HGRBd79nWG/wuji6ri04byDG7XfZz/575TMFq8w5iUw", - "9LHSOEsGxjBKaP3UkaGx6/jGkltZssOKgcOKTxDV3Aqa3QNEg+W+ER26cpb2ANF1noE3JaGs+gf67LJh", - "vC9jGE2XGcU4s5pLg+QV7N+jTOQs4RKJBCPkvBG1DLnGOOphtaXhTsbyLS58cyz5KneIx5JvyyKqmPIY", - "VEaLleN+DhbxLYJ8dy7xSeLI1wHo0XnFFxRPfl+u9MoXsgjB5JqKP1DmRhtX3NEjt2UW1Fvysp/UuEcL", - "z7nyqSm1O7IqeHocVWTK2D67Ql3R6kVgm94hkGqV55CyQlqRBef+oOTH7nWptZiD6bMrDdyiB0HIXq7V", - "xD3PQ+UhDOS1wPY8vx6INMPIjwkMMr5QhQ1vlH3GDSukhkygCKCV7RTkdgzM7/Gh3Kvthr+xr1b2FbCj", - "LtOekH2thdAm/tXEo7Ykjwv8exmtUB0MnWoJEtGgTNEoHbqldzT80q/7QZdGbb6hzQkI/irOpLCvucg2", - "MoPA2yhDxD0tRuCTUzLxO+33U1Pa0ua/0dlGOnMAG4zxyp6ezGLg2Y3IjIW8HSVnYKcKk7xLPPTxTBZy", - "MgXTUb1NluJt+gbsUWHVkbU8mW5hk8VNbD7tRRBwW5FTVLY2aEtDDzAeSZhpaZGFuykvjKX4iax65JAN", - "CYtSmD57p9i40FROaVlI34os8wK4zDX1tP05SDh2a9/oeCMdl4D/ZMTcCqgnEZsNxPaVGPrVXweeDpwA", - "JTpwGB4IgN2CBoYemiIvw1t8ZYdxkWULFLNKh1pmTYKsS97Iio8ofC/gwar40qkiLIMv6yCnxAiCZTAt", - "ynuY8BzjfUi/P26q4VitxYBFc8pSuGGwqFjNkxs3m1dV2FiDmQYjhTAsV0Laz8pnvvGYnXnMJ2UvD2Et", - "gVa3NQpgmcKl5z+z/AaQympZ0KV/oUlK29zvCm+IbXLz/VR1LlsNhTlooVKRMFN+G6wdwec790Ex21Fg", - "Nc8jEeHSIb7R4EYaXAuCRybBGHR2o8BcRiIofuQG/vSiBzJRKaTs/N1ftkTQ8tpGCwsbtXS39pozviMJ", - "dZZmsDEyIkgzkYbI7aW4CM5+ODycGfaPQoD1dEc2damYkL1xJiZTy3y1Vwy+39Lb5pd+KL0t+cG/Udgq", - "hdWNik9IWx7v3iieCjlZ+zRcRcCMRoVXrK/rcDZulMtwt80zDTxduPvxuIeRT05z5PjMdW9gqViuhdJs", - "GM7upxjiHHVPsbD7XTYsdDbssmHIi3L/LtOZhpRzNdTgk4vdBQxrlRResWEEGTETL+eaSsezXOVFhliC", - "SUTcsoQb2LYIwyMRSyuIvsmnjdTjMfTpX6HrgfTIcUJUB2YTzOoEGEYspzZimM0kUg+5BjoqiRgPvX4X", - "UrUwVbX2mzdpSbAvX55eXAyO3797d3p8dfb+3eDi9PWHy9OT3cuhO3YRKYeOHqzwRFRaTITkaIFaYiOt", - "ziu3ao1LxBf2J+1f+E+vFjnUzAG4wkrabz2TxWf8/izVraRwVMOExBKD7MSnWXbZa7DJtMv+86eLLqPC", - "OV12aRcZmCm4t+3ZjE+gy95CKniXvVZuzBXc2Sv3su2yGnV3q9JtXfaWSzHGHZ5rGNMa7+0UNLHJmdJb", - "1J9uVHivYUW3Qsi18Ub+CkNTmG2lTAAfVkhoSZZ7evZb3/U3xruR8XqgPT3HXYHLI/PakAG9sTpJmSqN", - "ekKzLJq/jSjvmday53bZdz3zbrUmur+WkGHXdyv5PTmybWVzZ+GbPpamETLFHkGYwYrqT2GaZ7o3zzOe", - "u+VcG8eHcg1OWhNDwgIH0esSZqCBCtytoxy0BnpRYfx+TZFRWx8WZoiTDPltWrpjeKcONywUNHaTY38H", - "Enl/Ob3qsvP3l1ct9e+VsYPAfuIwG6l0gaLFzXJw/uGqfKR13eH4nIuMjzJoEWV0tDi+vifxmGGu9QjG", - "ytf4CaMQDHgwVNBrl43XqAt4JKndZYUU/yig0ZShcvN8k9APl9AejbtNFlYxnBWGsJ3wpuYwO0hv301G", - "QwJiXj0TX7tN10yX5YeI/g4o3mdAw7rod0SsDFnD5CX8PMpA7Ra+aQNbaAN0X59CHViGzCPrAw47o0Dy", - "kGigccVOsRoZMiO4s+zt2dtTKtnzSVUCv7O6TrCNrPMKjgqyY502MxOzNh5dHjpMWF4VCU53MwdTO8u6", - "bLk34be34hcviR6pqViYpsXeEJ2rVu3i/c9dVnah3L+vwCwL+AdCXCsZz/kETtTsmBLP3yiebmFCPXn/", - "tjEg1Npz6OMm7KfljDgXSssta+vlfPLgwnqth/om7VqlHUb+pmo28DUI0Pr4pFbH9VB6bKtjmg/Ke4sw", - "Pgr6mIV6Xox82JR4LSQL/mtufTGkFRIYu/voYpVzK+YI4kAuIfyUojb2nCqIUMNCavt99sEAG1pDBY5u", - "mx70SMD8cv+Oxsk2EvsbDO7eNo+ZQsFb8pif+WvxejDaYjHVoPLWWdBzwIpEYaapGONTsHqbz4UpOPY4", - "HIlM2EWfnfJk2hhAwTH0FH7W86u6Q+tPx1S+uf224yHN7IEn5h8emx2ObC4OW8wKT5wN3No7fnO571G7", - "zPg6B40XIBNgV2IG2Irx6Pzs0wqx5eN9k1/b4Z67sE+MeU9ivvVRTKsXebKUcdVAaJBWL1ZCr/Z8ie5D", - "FDMNdsxy0FhpdT+an1W/1UEKlovM7J6QFsipdnGMW6vFqLBgNlAeHmmV9qY8HWhInLoiZF7Y9SjduCRf", - "sCSBlByLWA0NJwlWPQxD6fpOWk5QCc8fjt9cxlEe1YVIDlt9XZMoHd5TwnhY7WHbcXcTIQj1zeV+XPSv", - "4KR/0O1YYDUUW8G/V+XSG1dU1nON1isQsXa5UeBV9B7D1s0ZgsspA0sH9nupcvW2UIKSfKO4eMP1xD2m", - "vZo3LjJ2zoV75rw5Pv9S5YU/1zc5sUFOJPlTi4c6JB5ZLGRJfk827HG6QmnC6IeyYV/XJMp9RFpNH+j/", - "zfF5VdNOjIOdsbXG8yDObNzLq+yGvjTvVonHUqXtLPPk/VvmPohwzdo6bU2qZAq6ZdsX+OO2G3/lBTb1", - "qySrn68xUmZfXImZkJPeUZap2x55yeKJ1uJ3aK9AyDXwlg1RiRdm/lHwpjyo5t7kYa7PiFFw7ghMaTYX", - "KajwU0vB5KcVevWtOR5G0HsCuYcLxZSzewu9zZJO8c2v/OrlvmzIy8Lwz2HCK/f+TZxtEGeKP/lDuwGL", - "L9w4hzpmhc5fi2nuXZn3tR3F1psM+KaEy/SL/OJdaM6832fHXGsBWH6/rLU9pi5uQiLXGmG1ast8xfku", - "w75JoTJ+3RK33BPi03KHpdv6xiPW84gKWE/MKWJw2S3T5X5SvWpBjl/s2jDkHdyy9U1DWNlivHy9b+gb", - "knPt1OL285zjB6tHokblI/p7rVPGKx//TzuI9Axp6Uy/c0OQR2v78Wm7eVQ4YNWjtd6gwKOa5lVh0dak", - "sN7fEpqJYoBQiyOu7DyyZGBnUz4HaryGcq501Zsm7jRcLmVHeWFYbXryxGAnAgzRY2cyhdxpw1STvJ7W", - "84pxZoScZMDcF5SXTOEHqQLqCTpCWSm2bvz5zU3zOeTBJ3LVXPHR+xzkGqejhNtSwbF85B6Hnp+4a1U4", - "mHQbX2wkpF9dKfoD4j7iNY0z+xSpZ0K0KG9U2xGmSuDytUDdFkL3K6Ma5fo2JWt5famZplVTnEqqQPRz", - "emUshavPjpU0xQy0e4dShtqSnobtY0LLkClWNbFY6ktYp6txtOQLnu2U7vVYWlkTyt+UsvVEaPloQHj9", - "SYnvHjoZ7jKuOV2ttPryGpmjYcwn8KSLxKAkUCC4XOyqZFTdgGKtyyTcZotyKT56Es3DCptFzD+UeJB5", - "3uO+KbVSZCjxzUTVmDBVzXTWPscyiqzVYdagyCXouUjgWHMzXcOgZ1zyCaRY9VQkwOBOWKxFCHc5VpfI", - "Fk5ncFoLYpWvaU/RbQ6buFW6V2WXlE3mWaqQNfqOXHW2+X/+1/+m+NNqFVzXUNN90DMf1olP4N5EzKFX", - "5L4gLbWXS9W2XJC6aT2UD0Zu8xsjbGWEHpkGCV3XEzLCNrjsXlsV99qsrLp0jLKoKju9ExYjRql9vpg4", - "dHU6AlYQv3OqQJnZWsgUdIY994JlimhOl+XEkimXEjJUT5AuKPmECJLYol10yQQmxpAsEqehT7khWzft", - "PHh2mZCkvezh06NMztknF9DZCW5UQ66wamKEinDmWNnWLZbusyESbZEP2Qy4JKtSOHgq3L2Q3iYwplk7", - "jQi1Nc6mwDM7XZQN77CMUp8N/X+HCTnLNcyFKky2KMc0Vmgyr+GEz2EQ31CARFmsijkuFIoxlfWxEMqW", - "qrRa7WD5ismqZlwbolDtOPeEq8wLAaxUctWoGdhprQCUKZ9WJS3RdXa6HX8PnW7HnyjK1PKoUeLspCzk", - "S3sMV9BnR6Mqvyp2N24xVuSrBfWi1yScQswyJd3QsrwVp6rc52cnLTHW/gIlj3pitJpoPms28PLHCPfp", - "O01i5U9RzJw6PyusBe3+RR0Re+Ri6/FcDLcpY1jfU9dTxTpWhILmvZr9LLJsTXmyN0IWd4y2xN6/f9u7", - "EVmGlQdR7mHVlBIIQpYdH39522eX9c7xw4MU5gc3MzMZhjeRQzMuK3LAqUtW5Nf0QmMGM6UXJUDJnBDi", - "Yrx93rvN0HLl58TSzNyW7M4UubsoE+clTyiRV677m0BuF8h4WQOlZgOHEk8pkONg2V0eu30uiePmIdpr", - "nCdKGqu5iFHgr9MmLUAiUrIVBFLss6FUEoK4mGRqxLNVannFhjOYJTWxlEy0KvLwJUIfsWMq7Cs2TPLC", - "gB2yAxyn9GKQq0wkCzIuvPvw9uiA/tBLtZiDRNqt2LOSfsuGqQxjDaZcsh/6h94/loq07F/iW+PoIqFu", - "U0OlZni0l0OWCQlNAeMOi8kms8TJFton/aHaZUu32NlgrAEGN6NI7xkNEFrZ+isRkv0sfgy9e+rBEm5z", - "XZaCxoTMMmBl6GZ/+W7oSU3IGui+M+wtzHpncqxYWszyPjsyppiBg8QLXIcKiYjfoc9OgqEmJC1pSDIu", - "Zlj9PHEKSOh6YWY8y7wfEmPeOcvcswuhNrDK8mxwMxpi7XZjHY468NON02EdyN1SqPixKdcpdVHDipwe", - "mp6NBCSsw45TAjrurDyg8QX06t1ia+Re31qEcblfHgyKd3ifhl0cvSUsegA4nuYWNmk+XhgGxSc+B/3Y", - "oogcq9ksPhvDGBPSqZfE7d6M37FnPzgtX5tuTVY0PmvJKDQmCtILMPguYAYsCZv4rjyY90yB++ZSyZ42", - "psvGIgP6F+q20xnM3H/u99mV01J9iYJ8ujAiqbhfXT10aF5gY/wWJGprVJUPLDc3JoanOauUjBEWncVT", - "9gzYHp7SLzVTs1pLVcJYQ3fvpiTfxZK21EDV4ZXbAr0whsx7Rk5nuV2sQ0pvAHPfHnN8DHDLfsDwH+HU", - "IsVGqkCXDkktRHZEVmGBSmvuqti4fSKF87szmuOH8la51nxBSouYTEAPNhGA/672FN2GFH2fNZk6TjY8", - "Pv/wkr1zmrz7H0cQL4c+gbcmWyJwD3vcmsBKRJsqA4xnmaIE3NInVav94fdtFRNyrm5IYa506z57P7b+", - "eYM+NG7YsL6TIdurTeOJqJYcC3ofgygSLlkqxmPQ9VaZOCihbfqf3Z3ORWLFrM/ebkP/jXtrK9lYvzvi", - "dyWL2FYlQ4TaTRs7Kp2CHiIU77aJqlAKrOhm28P9IXxzEyWslQHbM92mFF3lSls00CMgeohuhmXNdL3O", - "ll7PaicDtnuyeVMsYXaZUN5wF3U7I57cOEVWpgP/l/AQvlX6BrT7w5RrSKv/xuI4UQ0x7DoU1T+mp4QA", - "c6zkWEzuY6fzr5FapX7fVhVTGrHbvnsuBK9j6yOB5zaZ7h73tnyWhT/Jan2DY1qBGZXNIVhJmCpsomZA", - "1Q5qncCecB/UBo38ogcpWEzFLK15wdni0CfX6m6BKkHZRS3s0yjykjzVJmkFdz15YdlepiZddsu17FIt", - "v33clWMBxWRqGdwlkPvoGNqf1Sp7wv0dTZwi4p9m1IPVMD7hQhpbr2DYZaZIpk7ACEnaQMKzzARn9Iol", - "yreb8/Wwqr6+T3eSD5QVVS4VjJV72OTddNkNLFJ1K92LCDuH7uPmQsGap9tYvfzvQVlTYQaWp9zyPkVf", - "TZ4SCc8xaLqkjHAx9YgbKgm2lPn85vicLqlWfvoJdxnqlo+alaJDLehauWjTZz+JyZTNVVbM4BVT47ET", - "nymMeZFZqmyW256QtHsyzD3dzkNI2S9vveG+ohZV2J4a9/xDA20fVN2D/JO9YOclu6+j+o9rpGTLjnaT", - "NjQoZGWiaTVoQnXZQytEMmikeyqkMRMUUKsZ9P0EcYb/pvbgfXYmWb3Mmu9B7ANcCGIvmZoJ60O/hPEm", - "kj3PzG+nCi0bNPk+y4DPQ1O9sKIaj73Rw63lFzcM7nhivRMqKeU1Kj2OiekCaH9HV8c/1QrBte3G+Egy", - "bBvqHlgELTb84+NwH+N1mFQ9lb9qbk6DdbwV/THoXXJ6FzmErhSju2VKs1QY6mJaDZ0LTrvrsoUq2Kyg", - "Wp0pbuEuz0QiLBu6gwzdDEME/rChgJeW2q2Q7D7IVTUDTCJo5oVJn12uAr7P3odnWdBxbmBR3vXyRe87", - "qAUNCW3XnvgN2JcMi1/fApbAJm++9/KjT9P4LFaVdWsdVbrelkT97JMp3++zXym/duh3NOxWjswaDjlw", - "ODzypPESsQntnwH1XzEuF+QRUz6C0h18PO6zsrVLNd+e10u6IYyRuh126+KNFIdhxRPJ4BrhhIgoI3DX", - "jL5Mq/rsqDqSB1SohEGb9CdhSQZcE33ZOGTpAEPfqGBYoese9avJfJdxYoz75Eiz1RwOyaeg4RXmLGfq", - "1jBeWDXj1seNuQcpelR5/ZqajCXiofHH2zZ0plWTj5LKsXfHBVYKp06X25FUXlM7I3pwjrA9aMqCo6+8", - "IMCwEm/fNd4qTp5qKra9yqFnYIxXKFZfkHEneLnagKae8dxQ7xP0hR6MRQZEHd6afwB3FqQRSh7kWrmf", - "D1Jh8owvmEPYV2V8s58Q64Q61ufDfh0ouBW+jEq9x2FzJ/iIrM8UfY/F+8O9zz3VV3e53BGu3/BIq3wQ", - "7p+qU2lb/4Nvv4gX4K662ykvwf2HP3/4UBSzwTjjE0PwcVe02T8VzhxAGHsyHzt99q0qDPhCpjvGx40K", - "a2OFGnBKRr+SyYmYDXKG2j1lMLbuUe+Yq9uqSNMsvLDJjXfLdRqFE6riLQXdrvzbHr/xT5Haqk5173Q7", - "GDGAn0QXmKosHdzAwsSOl1IUnvvZnc99W+96RbPWjJqrIXlLBkpZzAb0uqDlkOd2Xj5bpvR3mHOFhgsx", - "A09YOXj7Slh31WJzt3qK/2SJUjpFh3oZM4A3lisKIovOFCml+F/3mWkJXe86buoWJM1HiuvUJ3DviKPx", - "qnTHXmFKwuRUks5nH2yOOXSTRjdLHc70UfVGvYcZ0bcr1h53HZThDpLCol0259oXRUZW78UmdcsgrZKU", - "Yc/ir2U1S04Zu+TTWO0fTaPdJaBm6T7wY3Ou+QwsaNO/lqde/1Wy/J1GNmo1ooUtaAy5VnORtkRAICnP", - "HM/YJGNXGdbHbifVfLLd8BPNJ8ujZ2oO241+q+awPBr9lo5NbBp87j78GRa1sWQ72DTwEr+qDwM7SApt", - "1EaN5BLsMX5YH50BCbi1A91HHoVrsRKrkTrBirqCYQ05XINv475p5tCRoLrK8moasG2cPBwkxrmrSTcc", - "08mJK7iz5fUsU3m8xHK3c6yBWzjBKttKL+4nPGcqhTWaRhpmZ+5DtqcS9FHjKbsMY7n+9Ycf9vvshIQF", - "yoJ//eEHVOK4taDddP/v3w57//rbH993X3z8p3iynp1Ggp5HRmWO21SbcB/iOwmPvrTIQf+fN7tm3Eqx", - "yzyBDCycczu93z1uOELYeIrLPP7GLyBB2Te53+5jbpizlaQCHRapnYQdZfmUy2IGWiTumT5d5KE/fQ3+", - "vPf7Ue+vh70/9377l3/ars7ECamfW77al4pT4Uu5XeAG1Z6+q8pstFQUwW6fA80tbJ7Sf8009haV7Kff", - "2d6ML5z4kUWWMTHG92IKFhJ0Uu9HF70VaQyhllfDz9buP3q1yxLoaRRuxzZblO1SySatOxpjCO7xUddD", - "D5dVlRP3yUq1tRHYWwAZNuIUbR8ZzLX12Ov4P+OZKhMyLabQz4QUM7fRwxhM1rbf9Kk4GN7DwpcrewtO", - "HEdaGuiG3F5mZWivmSllp/9O9ju0IKGpKZgQnMbtzjDiBlKMTMcFkb9kICf+HPyOzvHs8PDwsHauH6IH", - "e8grwx1hp0dGnFO+11j3hWXCoFr5t7suW/xWV+lzLrQpYReqX99ORUabmGAsyVun6nndkXHLMuDGsufU", - "oBfdi+VOl7dcD9Qqwzie4+VV/7F8mrU/EiwbOOzgGvH0sGkx47KXiRtgP8LvAmtm6jlU2IwQvuULOggT", - "0ljgWGM9ExK4dxXlKvNWrF8x7sGthkYCM8hBDwxMENOIHCAfIJENZgZtbWIiVbP2Ti0StvF540g/7EiX", - "ZTEQ3NcKBM9oF6vUsJE+V87ZfMUetj9jyy0hbtG+sDCjvy8fQodson2D7C1tjz1r7PXZ5uCCNuFemuG2", - "NYgtTbzO7HJKb7nzjC9ukQtvKwzizWdqr8NqSky+icT9pi32EqpGf/AffM7pn5S9U81Nz0z845QbxrFJ", - "uPv9u5xP4Lsu+85n7H5Hr8vvvNn0OzbnWjhx65+OszyDl+y6w2+5sGiN7k+UVXvfTa3NzcuDA6Bv+oma", - "fbf/immwhZas9jnmGu7tv7ruxEKCqEgUFQtIGnj4pxU8fEvc2p8RnzC+gXOIJg/qNROG/emwweG/b/D3", - "zbiGl78lPhjc8I7oELolLWFBdbpVD1zA8qU4e+wN6FHY6U3V/fi2jPEuC37Tq+9EihYmSFbxSbi5PUqL", - "3Sc2koKO7OcyBNdR08Iyrqp+sIglN1Wx4qjlZD6QYsvZqCv+Ol8l1G8b0kYj/bjjrJFM4xeIIchrkcGZ", - "HKtVfiTMIBV6/a5QfqEbsXzOtXTRUq1FB50on6FC4kMMQy2oMtUi5RZ6vibpahx8lO+4Y9HrdiSsz5jt", - "sutOqm/vdM/933XHPWyuOz1929M993/XnXg8Wzxq7kduoJEUNRbBKbp6E1u/ioPOuook4ncYjBYWInhy", - "6cPh8Oe+r28YtiHAbBEJF6IaOer1tcW6AQ9qMPSX3oZOFPLYkoT1uvTRYOblBNqaOG6Dfnw8pgTmrfHw", - "vrAsl7ovUHfDkrhZzOcoLXKo28COL06Prk473c6vF2f4vyenb07xHxen747enm6Rb0SpRq0KC3aeWfZB", - "tsD3RLj/Crl0hfQ1tcsyJKV/1sf3hN4Hnm//TPG8GKJVhcPzMqGGZ8zyOyXVbPESk+0oqd033qtmN1YD", - "n/nw5WHKLScXstIz1CyULGGNOoTbyggydcv2yMJNWyLTt4+UGLbfw7DLNEy4TjOnuaixW5jlxSgTmCcp", - "bJ8d8ywD3av+6C8AAybeX16xg3L3B/6nkOVXplSFuirC0M2+YgaADZf2Ur5HsQ+hmfIc+uwXnom0LHGe", - "4GZCrHw9lk6Y8oJDIkLiC6h8Z0KzneARRR0prSBOAn/G81xQc32ei4Fba4Nj+ygX7noIpbohOnSAsZuD", - "IPzXzuDDPS/dCNJWysnSfODDJzbNkebH9GF9rDvetsNPym/LGShGYuC1ofUT0LeoIS2Pz9Rku9Fv1CSM", - "rcVhkANwwwxn1ffoDInNg+6IbWf5GRaxOcgCX1ZJ2no6clc0Kn91O5mYw2Au4HZLIL8Rc/hFwO0SpKtp", - "toZ3mGkV6D7MpDbVxmO+pSEntRHLswkpbGhdvtVkZ1LYeg//aioNfpWd5rsIozZMuvN8q3PVQzm3meqy", - "/D7MVC+ttl0bx7M0g+XRSx3j79mavzZh6IS8c5fpxhy+f+Lu3Sk73da+VPfsABZmXOpSs3UrliY1rzYd", - "2b2nSzlNku9Q4b8cpXi6SynlMK5WDnTnUqurc+xwjy01EbsrBbF2rTVWSz4JpWR2LtPT6a5kv+9aWMAn", - "hrqXweIdau+koH7sdpSE7QOll+Xjx+4uw2pCecuBMRredWidcncbG2FCu01QccMtx8XweoehceaywwQV", - "Re4waAnjd1lumevsMjbwnN3Xq5P4vQBznxniiuHug0t9cPehEd1vy0laNITdRq/qZbuNX1F17jn8HvTc", - "ogxuObrxMtuWZS69o7YftqxKbzkyqtPvOPaeS7e9O7ccHhV3962JR/Xv3whj0cgWMUhpzRfu+b9q3hKS", - "rK2YkkYp9f1tU+dLE3LEL1yK20j1w0xNlrOZa62e10aML/etmZQeBQt3trXPSEs/hCsx8926yh1RNzPK", - "2N3WFt3ipqsvHbOuYYDFuY9mvSh1+2Vz/LZhtiGI7f7htW0zbB1WuxLNuFskyiNGZGB43wNjMVJhLJcJ", - "NBx0Pzx1BIbb804RGA8PS/BW9CoGwf2TS7t0i3HD+ib0rEI8AoYxq+6FptvOtBO63j9GMAVjB5tiHcFY", - "7C2vZOnh2RQq2O0YnWyamEqCbT3nsl8wLNCtnSJ2Q+9v6nxpB8fxX6i0Nnv/c9mnfZWvq5uNWHtGpfbB", - "BM9nf7PXU91Ez3LObTL1YYj3g3hbHOJJe/xhySievzjcPRrxpDUKsc/OxiFXr8sK47NMp2IyBWOr+qM0", - "JHBFDYg+Xsh6P9KfDrvfH3af/9B9dvhbfIt4td6gtgleYx+lpGHseAclaYnfgVhwWd/AKSFlAOqBBjym", - "MBj0PYc4p/HZXlXO02qQa7U6FckMmXC+jGZ1/uCDtIqBNAVVRuUpzynmWcJtqGFWhWogTuBdToGn4yLr", - "UiZl+EvWgp6t4Z8nrWGfJdp8//xwuyDQ5VyA+0neDQGaQeoGsUW1FRaGojKXW7HVUNSB+7BL33INzGIh", - "p80xYGsEaRnUPtskUW9gQbXgmHGX4yX69gI2vv4bH9roZjeL2UhRuQlcyDded0uExgIjYLz2LTNFXtUt", - "u0uVVSq7lnsGgP3ns2d4lsWMpTDGIt9Kmv0+84FOpqynd925wPCX606XXXfQJkH/PLY6o38dZf5Pr3+4", - "7vSvKbyRIuCEofjMBDfIM6PcLhM1G3mRZXxOAM33LzZETuB/4Wr/csVHOO0OF7rErfF2o/yaqgWd3kHy", - "aLFs3B1vhvGSC+n4iMSCxquiietJMyzyb5HaKTQT15Oi7Li4PVZxM9BKNYMa48comhWCMRPaDWW5FnOR", - "wQRa2A43g8InGa+fMjQmc1+7qWSRofQIPH41U5LOHolUwIsOZQLMFLKsvHInC4p4f6fkNlaxQWksY1w9", - "Vvd4PbJi38/ofdW0CDXsXD7AZp0L5Lwdvf6IxbN7mP3xcRlgp3IutJL48CjjFLE+rW+sEq+FVWH+Sqzh", - "buGF7QBsjyIkcG4kwweFEPI60ZUAK8+xSoRr34On5fnbHoPxOmNwJ+wgHrN6HiqthULzLWWzMaJwMPrT", - "i3hAUa04DH3KRsV43NLBiyIKt51MFbZ9so/t0PtZVOl+u4HvksrsI/bKsrtPDXubIKMKFg2m1rk6vXjb", - "WT9vPazJf/7z2Zs3nW7n7N1Vp9v56cP55mgmv/YaJL5AVfS+0oRqYbLzq//qjXhy0yxquhwTnZl4Z7yy", - "z0aismJGbebWxft2O1rdbprLfbJjkDrO2qWNrrmxy5zfyvqFbVWiKCK6V3uV+tqSMLB2sVkKHvmvGWe5", - "gSJVvfL0e+dX/7W/zFhJs0dBVIagzIEkUou4jAMttJFZBhw9aOqHwLCp5dSGHUC6spL77P7LfIx2SW3C", - "9R78/KxmMOYjx5A4M262dfQQrQz5/rIEVluHglB7Mzb8Eku49cpekpFORrX9lHbcohBpnBFj49cBt3E7", - "MVWHX+nX4IftYCpuJTXLbbFrH/rjWpGmwpCUbedKeTHIk1jbRGPFDOM2j88/sALt6TnoBKTlE4h2KV8j", - "Rqs+LaJZW3TKje90tI2OQgW2WyKfqx2HcsWhWjLtvgyKbpHgUXPLeQVT24i0rXqA0PbjsqgdsKmQ9xM6", - "J9xyx8lutSAD6BLqUdKBkHkRCaROueVbKRZpfZXNLTrKeX/beOYH6YtuOz7B07jpVk/ovrAg25CkygjD", - "D5j/vN/Z1qTij6KBV1Htu+hOl6dlVWoNuQbjOFStJZHPFlF6pfzhQ6FZOtYqZHGniKqgEPfTvWluaSX8", - "3JFCNNV3K9ZQMlKaXBh2jQOvO20k6/YfkQJkCPdh36rWKCSZFvKmWUEJk3fKlKAtiZjithH+D7NDjFS6", - "oMaaNGWoz0cXID11L4eyr+8FHssTKIsjstJGhnaKdC6M0ouXvtrdjVS3YXVf6SV0wCpbNC/VLuSFnSot", - "LGZXZlSyltJMTa0AYZ+dIUCp2ZzxJbUKSQsmhbEONxc5mK5DA7K9YgUu4jHNRhmhCG5VC7UbiibXK7dW", - "1Wgb9X3L8pqNKqFlpHkVebq2MU5bEUG6PE/i/Qd3wdmQ+7G+GfS2dUaotgToeO7XWEhMUthGDaoKSIRR", - "bUrQRnsS6XerfzZlJYza74005q2Vtmq3ftA9N7t0z6hM1vcZu/MqBukCJtvUcNrO7/STryAZ6nlMvBFk", - "TfWLFk/Er+iB2GWiLaMSaK7vjO+xPnbcX0t4UJzCDnNGXcHhFrrhYjeB7D4eFV0CekMhpiZiREVQs1zT", - "rl7qzPLB3XrHzk9Ki9+VxGJAuBbjM1VI22cUnuIezvh3wzAFuMskTHjj7w4OcclNO9hQ++MXt+Nki/VT", - "dSsjyxd5fPGHRGKUBaO2N+pvogpufYnMqqpVc6ndiWLnKbcOj1gp9bUj1xJpCnJDcjOFcVQ+Mj9oo4/f", - "f9ey7dcig3PQM4E9x8399o99xeKGN2o5Rnmjmv2lYb3YNUE5UoPrTy9e7O9Wckvdypifx+0Vf0LPTtjv", - "h5b9bpPMSnmVeXW35M4lzyG61NP7lsNak1xcrx23Y+8KXhiolxqgeuI5JI7209J3sKPzoe4Jx6JxMd9D", - "vahDI2jscCNR1hePXohTYV6bX7lNHrXCWVl+Ds0BWAkyXpbBEa6Yw2a7bUntfj5Wjs0WW8TytEYm4Q08", - "sE7aWPMZxCNvLirdNnzkQDzOHcXOQWuRgglvJX8D+3WYPz/cZASOmkTDgy1izKwpsIC090jV2nDTAaHP", - "5CUhcLvjsdpH3fEWAjDX387aC5nxO6wiIH6HM/n2x/YdYBRzaAX09sctIbJcPOtZS0CWO91RkQq1GbmP", - "fYF37j6nAmTYOHYuUlB9dkGIbOrvaqdn8Dm4hz+N8pF87il9XmQGjvxfkxuo6pBDSq2yMD2eGbCGjZSd", - "1mqp7/saURSk1MQXYWhHPfci729Zb//Sqvyh9KV0Am6ezTd5NptBKriFbIE9nzHKQRWWTTRPYFxkZYt7", - "XxxghmFxaCoUEuM6tC6whDweFXEk7ubZpToiAcxt6AlLI1ZZ/HIOmcp3jbW8wgp0NJSV7hCLfTVr5WLY", - "UgWCSO+MYAhcW+C0WQcCi8f+o9WW3pspqaySIimDrxg5Eaqd8kQrY8pG6/WOhr5ND/tgfF/QN9zYHq7c", - "Ozvx0YWFD+K/vDwNdkBv/hSGKsWRRWmlg+8O7lJ3xmAp/W0tDNuSHpYKYFDpq1uhoZfBHDJvS8KiDVgI", - "K68Vx/CQYyBTPA9yi1BAw5fAqE7fZ0d6JKzmOtSx8Ool9XbxRTGqEhCOgaU0WZ+9Xmnita5SRzdWYgN3", - "DLqHNitCG5aqBIOkoOwnO/RGsH/2tSsOlv5ygvPWAuC6bLVAx6bm12vNo1+0kbEC4X9cvn9X2hhj8MmE", - "8fe6vlAJ1W0id8QyvJo1u2OQIEC6C3+6Zt+XYAOWeXFZuglae39bx+t9v8yy//f27b+x13ej+3ej8Xej", - "ErJ/serQMJx250Ncd+wR/rRG3hL2l8HTeQ+fcltLldVgyTzPRIsV9leeZb0kU8kNXVllrqhdZrMZj4Ov", - "n5LydGwoz1jtaKlPy/YO+K5v4bFz5xXfb+Xe4s5LtIwbuyKJq07ZGgzYIBGb10LP63gv+h2elv74dI4o", - "7ixVMN/Z3viwOr83sDBWqxsw0dqc0eiXeP3Qe+VFhYDNah8hL6yWH+U40R22Pc74on8tG0xCF8D2Qr/b", - "WciIO0hDleb9Prukrl5lQsG19BHgjgW4tagHumQqvAdr6zVuiu3h3/790N2LT9va71/LWr1YbELhbm2R", - "k5S4VTrFxs4p+Uh9SHF5ciGt5j33FS1orqXTGySnMlwoEOnnnBfGwekKG1y5vfmW8SZUn42CLtrzq9vS", - "VcOhIt4rtgUgYTBVGLZODS1ayqipgSOYBNbjIvY2nXIn4J2uv8gVE/LvvvmXe/W/YjNhLL8BUpRQTqIO", - "gnc24smNyXkCFRKwwz57L7OFZ2EmdgNsz4gMpM0WjXu6ltVniBv7dFXlE/aw/yyK9SEsZ9uOIr9qYaHs", - "gXI/Ql8PrUbASij7Fxa8byuUj9itk9yWWK+187LjtdEzbO3Jjs7POt3OHLSh7Rz2n/UP0UCag+S56Lzs", - "fN8/7H/vi97hQQ5CPtEB9UMi41gSsY69BT0BzA3CLwkF4E4YDOpQEkyXFbkTPmxp0khG0ly451kOGr3y", - "aZeIDAvSFtKKjLrDhq9PYH6lVGbYdQfVPSnk5LqDecuZkNjASo1QZ0rZCMZKh8qoaC/yqXOITGW/ubMU", - "7aM2mYZVXvt+UL5W0Y8qXVAwa9Ujp0rTPvi7IWssScyIKznc5pJ2EY5Ed2gVm+G1+kqdf7vu9Ho3Qpkb", - "Slvp9Xyvwd4kL647v+3fP9OENhRHq+o7R5+UbIZZi7jO88PDiCEf90/wTvFlVR7NA3u5XuvHbucFzRTT", - "PMoVD37kgSapYvTHbueHbcZh2QzJMz8KK8zOZtw9hTofCC/LLWa8kMnUA8Ft3u8Zh1XYW3YT20QVhQHd", - "Cx15qmUAy5hrYYBRZzZW2erKkJcRL3/uO6zqXsuN5MJ2p5ZruSu5HIPGyvPhFkJfVPdI8Q3ohRxrHopU", - "eixmp6Hx2qXvjd29ltjkuYelySEtZ6RzlPMHNESj7/HJ+UHITseOihrYyGnSkF5LtHCEu9xI2edVU7j7", - "EndcNMQ0qm2A32c/h1xA/5PkMzDXcs9nnHlpeqzUjQDj7/G6Q30lsfSzdz1Nyxnor/1reQnAQuFv6opX", - "7aQ/UWqSQYnYB+QSKvNlw999EBJl3Lnz/8iNSI4KO30/B/2Ttflp6DRLdxDdMJqW3MfmQz7RPAVTjvJC", - "9S2/Oy4tCeYc9LnDk87L7593O+cqL3JzlGXqFtLXSn/QmUHn52pR885vHx+LrwVc+WpZ2zLaubO0c7gi", - "zxRPe1WvxB6XaS9869ieMhFF5wMOo3Kyms0cBymnYL+LnHGdTMXcUTjcWWxUaKcwY4VMQbODqZrBAbGQ", - "qlelObguDg+/Txwp4L+gey3de1A7Hjerr0B8W8h7KBol57yWn1DRoPsqGaM5kumFv+N1PGlWZFbk2ONT", - "6Vkv2MradI5ax8vWhN3qG6d8EPgpQDKxYs5to/pGc/p4EenXKnMwRfe6VSzPeAK++HsA125QX3IpHPX+", - "ynu/H/b+3B/0fvvjWff5Dz/EowB+F/kAG3mubPGvFUKGdio++rSQOeUyVeRT7noPO+2FZOMZl2IMxqKI", - "3q9bIUZCOkrcpNWX2/PVuGMvk7UKXA2699PinsUikktsIFSAtBvhdkQ1JXFgtCpPPzffW2FBJTRrSL7H", - "jWNIZr/OBMsjem7o39IHo6DjxbneacijlkwttfhZ6i9pyC3nm08enZ9h6ek+O/K/ouSncCWnzpC1zArf", - "U1lkgOFYIUT6LskK45DXqT/YPl0qpjCwAJMfqi7ahiVcko0Cu69jf5AQ/WGsyk0wIoyFNtZ3fwitK8PF", - "M1HWHSFrZWhJSW15r2UoUF4YdE5iz+Cpp6oUKIPLvQsrOyAm51BBHbfaDSyoR6i/rmsZPJ45X7hZvCOC", - "aVXItGe1yJlTHWVCMeSABQZkKuYiLXjmp4lx3h9REWz2EL2/GrjWZrq6UtUG8X7KCE7Z0v7ic9JeSQjU", - "LzVKAHWcXiKzpfakgdiagKsakz4RvCKdT+8JJuoVF/q6BrL+rBC6FLMio4RRorp65+a4IXEFRmSuOnCs", - "vh1MF8DT45ppK3ZbjwWuZtNihNbS26vsPeyXRDm1QjcPvl13aLIsl5lGK1a+tutE22D7fTaNk0+E+nEL", - "6H3RH62ePrsMG5qWUPhiGNavZJANxvQt4FW2A46DqYwOfiIIrTYa3ho4j7J+rfRZjM4ocHkuQkuM8rX8", - "xUD8J5H6Iizqtl7fsQnmZqPruNaHtaVQa8EQ+cBQqSNnt3RSOc2Nh6qKblltySuEoQdyuUvnRMxDI0RS", - "TDPgBlC3qveX2tBCMqbxlA1Rnwg1V1t+35NvuIm+EHGJW6kqZxKYOMJhCWMmYAlhBmUn/lYm8RewjSqn", - "Tyke4+VU47SLUQd00vIQj3GLfwHbCGzwmgcxi7DSNspHs4N8/HLLaqtPhOarvekfpB36W3An+7yo/jYU", - "EW1AJ0jFMjWg4jRmG4g1uvav4aMhHLhcB934yDNr/v4yL4Hs5FWCTK3c3LWMFZGjEDEsdJZrmIKkd/Nq", - "tbouMwDX0m0mXnGOcVuZ0SfC9scaIAVzY1XeV3pycOf+X66VVQd3z57RP/KMC3lAk6Uw7k+Jn/twrqmS", - "Spt64IePfgzndS9qH3Wf+KvA/ArjTWgEBZVGPR6+BOITkcNyhcX7UgMCFLHlS9IWSMbXbUmIl1sgfr1l", - "TxuruuI3cFkPjXwSjXElZfOjh9FaiYOBrAc5pRhXK222bq4IlmoDFB37WQFa5iawCkAhCG0DOFWWtTMx", - "SkZlc5+wSVUADpSj7ZBE6v5mazpejZM2tcWGna9Rx9OrgY1sUN/WWrJMTTBX1IrkxrA9qazPVCYTZw2D", - "2AimfC4cSvMFm3O9eMVsgVY638W/VnQAY6YwraI6CrkbQ3IqprJ626V3dXcbRRN8yA96ehomzb1yDlSF", - "qwX2Ke4DrUgULBRiwQMrHIbYMDJg9HoacuCWvWO9HgVdHTLyIJBCTj6EYYxDXoac0Cciv1qW8n25o0ev", - "L8SGRJupdAUCD7dOM95BmwtBvy3M0QdcPhFcluM5H2TkoCDCL0ZqubORUWMdFHyMcDtPq2oJB3cjc/+P", - "wpAXy+HJyLVKF5Gx3CloVuU5JmMkwPYoIKF7Lb1PtvLGdB3jwPw1747r1nQ+Xw7aiN+FnOz7V3O5kCiL", - "jTG444nNFtcSl2t4pjTwVEgny93r2b3HMYo6rDGkEtqFzoa4nmc7nI3A2B6Mx0rba1n1IysLZ4dZg5fC", - "zYyKmnvY8AkwSk/40fFGB4TQxFTPeIahplZdy2FQJ4e+AQOXC7xptlAFSxWGQEtwOz6yLAPulFYZDMsU", - "n+G+Rr/kCJgvqdS/lhchcKYJK+r9rwtZVjxGt9XLWvxNHTYeAl1yr3dROZbLEOtHQYLFbggcJPpAphQY", - "WybtUMz6tbSaSxPU25dMjBlH146uwn/cvtHZ5DbIdebEYkV0DJMMARsTh0y4GRfS4QOuTYHACXhcdX+S", - "Svae3915f1euVc4nTiD3r+W5hjGq1u56nBgzkHPMeB1W0QX/PKTkoQN/R0P05/noViKbDIJ3sWe1mEzA", - "6UnXkmBAlCQkwtMnsFbh+zFhFW75uKTfRwwUoLCgQT28bSm+4+p179987k0zdonNeM7+z//63wxjvA3M", - "uLQiwSLK50dXxz+x1ei5eM1j/9WgJVCytgPycbPhH9cUxHjdeVmPk/zt43DLDeHo6G48WLfZxswxDdRM", - "4u+k1T4LQ7aHJVcOqODKAdikHxJWqd54CKheRSAKKTfd4J/FtN8yQWSZG4uKFTfClhqU2iTSaEm0NXEk", - "p/UwH4NWyLD7xEmspMDKJNUUfYwMoWNUmQFr4472+5uDUB4cIvL08RsYM+6GDDzvXL1Ny3X/d2Nj0SmY", - "9gUGr3fYiJ3BYFOfxuiZs2cFps88OwvxV75kBRZM9w2uqsBBP9j9P3NQa5yPGryBzI3fQ3c7hdqxoQ/z", - "O6BV0LE/3KcE1aG7t3xQkcSQpAKySAK3j2cIh7VTXsbXGCfv8INbzfMcVhr5bwSXL4flhHuEjC/elN4f", - "L97BC/eKC68V36UtqMsykBOyzyecaM2y54cv/o3qLHYr0nMATDDYl8IokEd4ANAuRhm01MVu3uUapa1K", - "sAo3iN6DaizlcGuRk7NyCSdLrNhzMrKsLOQzibA2PtwRRW5M5v6iXFQNTcjzy1eVulligZs5g2XfVf8h", - "iv2Lwz9vHuc2mIlk5TnwOM7yZe0hPB9a7wlQ4XL/i7y8jOlOWT7leMX1l8cR6jP0bE9LhQaf8j47t6mJ", - "5llhVu4+VPw6qEnfMso+Es7tpepTGTgjDZI+MUb71UOy5SqwPngva3grNS75s2Hsg2OXW47jUGNsDhIN", - "3MKg7IOBaFLEIobww7KIz1OFDTVX2QlVnq2rOUTn/ILMC3RSxjHnq7r+AJcUHNvcAi4n+OFTw4VWqTe0", - "u7dfugQJHTF9GGW92DzunbKvVSHTR3Ro484Zb4db0IPXgOw1qbtfNrSwotz/AEAhPEoYqVvpNGZHXYPf", - "BZYQmoCNVeqyhZaGcfbXs3NWvgVqb4jwNCiLylTV3wJq9FdjSPz6J0L/VeQYka/5DCxog+0v2ho+lpSD", - "OqhVpa7vVINwKHzduXH/KADZAb3pQh28Jg5060aMTXX1fttJOPt7fZDTy916OGNZOwkRq37BXyNeemDV", - "WYh7DRCihQdtHF+NTbdA2PD23bNc1x7As+AcRj3UzbW/Fq+v5RrEZn81NmVqPAZtmBETKcYi4Zh6PuaG", - "nn+0oNdfr2UK9T+5f3NNL8DfRe4NLjyZCphju1ywy7MgGcUjs2pU5e7oayGr7h+rzd/K42IEQ5/9JCZT", - "0PRfZQ9pZmY8y+rmiFFhmeU3wDIlJ6D717JHkDD2JftvB22agj3rMp/47wALKdv77+8PD3s/HB6ytz8e", - "mH030Bc2aA78vstGPOMycaqUG3mAEGB7//3sh9pYAlxz6L92AzzDkB8Oe//WGLSyzWdd/Gs54vlh70U5", - "ogUiNWwZ4DSdOjiq1lHhX1WlJn9VnW7tN9oy/sPEWhLsyhU99T6ILV4t2bX+f8Ial8x5JXtEg0uo3eDZ", - "YpM1lM3kt+UJyAn8ta70tf9SJOxuOmHVUH8VoVDLq3Xr/wrR5i9g6yco20etQK9Em0wYi3q6acWbN8Jg", - "vWdzT2HydWJKdeoIqlTPt4xqk3yFuILZugh5SiRcxQ1slN/2fAut3Z8wNPYxnm4YilqZO75COOEJsJk3", - "ernWEbMGnpaP7igtXwBP/ZN7O1LGxYJK6Ob/UqhZJRZsr2pa9CBdAll/NI/rK0MWzBpruOtK5DBAjH5Q", - "qy3fSt2rJf6fLgmppZfAvatr1Ern+5ShrxCQl2BXCb3eFuAA2w6YqchLCJMHtD0IC+ucmJqj1OeOK13F", - "l5BA8KH6GmbK8wDKZeu3VJ0I6sGjRY+UGkmLiz4FYwcb2im4b3yf9ZKD+appXqHdppFCt3Nfb7735Fdb", - "3bkcA93Co1ViQCiVRRi+dlYXKc4w9vpanRyCaXNtkRmOhheKQcOO2VRPRlhT2TZX0leW8auNOMi6+Wik", - "sSvqp/WOE7VKOVWMhNqODh4psmUdPdwTsf8q8gqtawD8H4PkvF7waAlFV/DdG1c2IPyuptE2uriWmwlj", - "s4m0YRG9lksm0fZyR97G+WjE1RpFdTWFZdNLKUK2iBv6bEQbj/JpK9b6bvtAH9/Gy+8NixlheV+HTr0e", - "ftOrxu33d6uhHODwJOziyN/h/3CWsYyuLWzjdrkg0dJLoNYI6aneAJFeS9vD9p7FU/HY0bbnH6T4RwGx", - "BkEVVd7669gqXm25XrtNpuyxa/x9JmSjw9SN1L5Qk5zUNDG8rYM/wpV/9GXMgYqULOObyit0WzJSoOHB", - "Wxq83aGE4zrbw2ZTw4tYYX0CFAU7f+WAusSWPyGuPGbtWwbSAeXItZqSqGv3a3NKn31CWC2bhSzcWdpt", - "1B60yR9wiU9b32wnknNaNb1R49pb2OcQYpNTnuKp/+j8Z+/y8rTnywf1rqKtKN5CKrivtj7GrjLYesOn", - "JO4tM7H9hucueOlWWF3EKffxa0RT6i60fMu+5Amx3RJj3WN+fZARFuXZxuB5UlO++Irx8xP6vd9XDQlC", - "G8vWDpaN3il/evGibZvY9rFlW2v7XhLxbSPxH2iOvac1oywJ9bWLUTRLOckZ4iGrUK1MTcxBdbFxF52a", - "GCKdFj68hBC+u9A6zA2MxqN4Vd822tU/vsxYZZm6jUceNFp/1/rkLYMZEzzKtD0xDu38hGF+a2sIs12q", - "7LJO7ezx1aoPBjm1qel8Non2Rk22FGUOsb5o6RWTDG7TlEN5eXlKBJJnfHGrKe2NikZuUV61bP51Xo5m", - "iWO26AsdazDTWlNbBM2dZXzChTT0Eg9ZCLqQWMJZKskylfBsqox9+efnz59TdirOOuUGe84ZZNXf5XwC", - "33XZd37e7yih5zs/5Xdlp5hQpcH3YfSxGDhjtTkslWsLLavWbwG9YoYTfwXVuY9JOjzFy25lrc+U9RDZ", - "h7vQeLJKeblfYjnU6ghYduASd04YEUFOTyDEk5A62h/6vsGWW+jJ6vuUK3wmPGjsoA0DqmrG2n/zRZTB", - "TdRs5riEWchkqpVUhQlVbwOATc5v5UYIX+JXTwpiXOLzwthvoQ3I+PNnLn6yClu+Brh/+H/g2/xGNCsI", - "RQH9s8BSNJvf5dXMa1XCUpMvCpE+5LFwL4C603yRlUrf//xVxhc4ViIm7qVpFQtqazvGUWGAjTh3QZ/9", - "j8E6Os83vHu8ACWsL8HZ+dV/9UbUSmEz8hnLbdFuigwsn7761Lj3xHKMDhUTYf6XrzJK2QOAmXC8dtCn", - "YgudBr/6H8N18DifWX+iLbTpTz8usHUHmd++WotbJfkY4dlaPFSF3WSIqy5PFXatRe4z8aMHWJbKs7lh", - "W9qYwu2qwuYFddXPxBiSRZLBNwfK0zlQalitCrtkMNOQYLnQyUHlhI1zV8ocvgjfP2midrnK5tqyy+me", - "fuDnS9H+TLUtysTuXMNc4JuREXAhZXORgqr5EWpQ98llrVwsZJ/VAb/We1Y6rfzqut5kn6qQ+Sb+jWqu", - "RajV7b0C5fA2RxYyvbgbi/d+P+r99bD3595v//JP92KNeGEHs/zFg9MJKoz0MY8NBlf+2nstJDap7x3F", - "Gj2LGRjLZ7ljctScHy271dQ0uM/+UnDNpQWKlxsBu3h9/P333/+5v94D0tjKJcWj3GsnPpblvhtxW3l+", - "+HwdYWNxOZFlTGCxyIkGY7osx34WzOoF2T6pxmPzui/A6kXvaOx+WC2FW0wmlCuKbTWwA6SQrGqYH7ov", - "6gURQXWIMpbtWSSW7eNXnHBKpXgN0iI1UN+Co2SCpEdr/uCFJ2zz0P4UZT7AOoESVqNMz5Ug+xV6DY0r", - "dbnLR0uw41lWn7Z5bSsdUCOhd08tfJuLrJW9z9aRqGcCX2GFKLyBsop7xdf67D2VnK3zuhw0OzvBFohY", - "23wijMUujViy2nGQ/iqUVb4OyCp/ehjX1ri/euVD4T5vwXCr8qb4oes2Cc/Aqt9BqwPfz35tmxB6K7iJ", - "fnlLRQvdDFj4QzE3S9cBl+s0w+fLmP10dXXOrObjsUiYkkzYPjvmWRZqhRydn1GJbGHclLdOWt3yG2DC", - "shEkvDDAPkhxo/nY0q+h83jiGzvdgG9SsghFDELOyS9vo6U+6JiX7uRX6q+gVWebsEb8vmdVz52S+btK", - "HwU4ZynMcmVJbPiZ8V4h3GrtivqrgAO5Hm4XYKzSYHzZTJq6PErZiaBao+v4r7pFFQJvs7kZ0hpQoxFp", - "BgRQGluqOb+8ZVL5UiJYOdt43WYKWcq4A1vUyy4fDhuQTwQamngTZCxkMHO6z8ZCO/WGTOWoZqm9Pgsf", - "vzh8wcS49h1V7a6KpEZbz/wF7FW5nye0fpWLXFpuo2b3q/gB76u7rXa3ap+/rFy5xM649k0wKN+VANIK", - "CJRqCbcwoUq8cOcuSzjEMFg/ol5HhY1UusBqshTUnb4KL7n6FBosp3FCl5hgqEO/2Qn0zPf1ZzCH+tYd", - "vvoFKSeGaOMlwy7/LMmAaxOKNtVOG+ti5G6xiUxP0KmXAjDKZeoFNz+dLffe2PwVZ077gp/ryKiIdd0B", - "u4FuAhY/P3zWxOJbTmhcs8JUGP3KB2e5cYdunLBugEP0DJIQwKVy2xPyJeOV6J9y67HczV6ntj2+VAKX", - "kvWkshjc74jYKQ66gC5TOlBSIJ4g8fdbieYVCQL3f6XU8AJxN6Z9XtjPR2dfPF3tmr/0NBsy8HkDnC7X", - "ibyGGlJLSImrh2fy79ivg0vyBTARclOrBcg10WUT7pv6YVJlggXJl7dRJ/lDojH82hgxkZAykHPIVA6V", - "suiXNYynwdz5/PBF5PexyOjZuCdVWD6UuPbJZvjtd6YiXGEq2kXCfnF46LS2Oc9Eysvu+S3NPs6LUSZM", - "JffIgfNEXkxaC5f4TF7M6pweSNFIPwRHTrt1rLqEaMJ16FJQwZv6jSXQJ+qN6O80IU8SyBG9CltBej2u", - "vSIJErbygNrwzaaDNOEWJLFMbCuOzmWLP0hqHjwH1vT5VTMTwfbZKU+mbKz5jAKhsfyG0jM2FOlL9oeB", - "f3y8vpYpt/wl+yOAoOfg7f5+fS2HTlrS3fteBGWLuASM6c2UVFZJkaCDMQdt0PSWaGXMErvzqYmvGGdv", - "uLE9hFjv7IRsANgtyUtxN1BWEhqpDB/oGkwxC89+OnafnWiV06YoqIoAPuG5CQr1UKRD6lGCHYm8DQPE", - "HFL6TRiqYmGnXLJnjE+BpyHkO3N7NQASP+0GX+ctaMcoBOYtl33iR8V4DLrPjjOBX/neplbz5CYym1MW", - "UrCQWNxvn73G6Pfq+CboF0tXhia/atlK7/egcsDAtAoDgAW+adevWM6NYcP/W0Oe8cW/8ywbUl55YzqV", - "pVj0Ep8Wjtt6/DUWuG/8dCvcfU95jmka2A4RJGiRsGGTzw2pZ2vQmvztgX/IeMr8GVufUGNJtuc+X2AL", - "Jodt1CiQs1QlxQykGzW0ixyG1ESsZNZD6pnicE7pWVk0pGro4/WVf8ZtneDHxLK6zKBCSPuhyaMdBhHh", - "msfbWJnvwqFs6EaCyp1p0pPvFqY0MyBTdhiBRwBvaMu3LU12mVFNwprzrKCchhk4MtMaEqwFQUtxt4aQ", - "ts+u+A1gJ9cEUlwI/dhDwpshiVVsJ0kLY6syXM4xJF5Y1dPg0bhaLgMusVEWIhKZ/Xs0pYPQVBgsb1lV", - "ViVvUuWEbBDBbklG54j4uyB8n11gDWAkaZY4fsIte3b4/MUrHFAiM69xAgwTL/SYJ0BFQ8dCG0vEPsEM", - "M+25TL+1gCzdSDx0IsvuVwP2AcEnW8nzN1sIo68u42n5BA6il+g/7106evQcwI3+/wIAAP//guav5CfA", - "AQA=", + "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", + "0UsAN/r/CwAA///NImELd8ABAA==", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/server/openapi.yaml b/server/openapi.yaml index fcbc991a..d1785267 100644 --- a/server/openapi.yaml +++ b/server/openapi.yaml @@ -1478,19 +1478,7 @@ components: type: string description: Event type identifier. category: - type: string - description: Event category. - enum: - - console - - network - - page - - interaction - - control - - connection - - system - - screenshot - - captcha - - monitor + $ref: "#/components/schemas/TelemetryEventCategory" source: $ref: "#/components/schemas/BrowserEventSource" data: @@ -1501,6 +1489,20 @@ components: truncated: type: boolean description: Set by the server when the data field was truncated to fit the size limit. + TelemetryEventCategory: + type: string + description: Event category. + enum: + - console + - network + - page + - interaction + - control + - connection + - system + - screenshot + - captcha + - monitor BrowserEventSource: type: object description: Provenance metadata identifying which producer emitted the event. From dfd50d06e1461f444b6fad8d725a575a136120d0 Mon Sep 17 00:00:00 2001 From: archandatta <35818003+archandatta@users.noreply.github.com> Date: Wed, 10 Jun 2026 14:04:21 +0000 Subject: [PATCH 02/10] feat: add events.Read for one-shot S2 telemetry reads Co-Authored-By: Claude Opus 4.7 --- server/lib/events/s2storage.go | 55 ++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/server/lib/events/s2storage.go b/server/lib/events/s2storage.go index d10b51f5..94c8d111 100644 --- a/server/lib/events/s2storage.go +++ b/server/lib/events/s2storage.go @@ -226,3 +226,58 @@ func (w *S2StorageWriter) Stop(ctx context.Context) error { } return w.storage.Close(ctx) } + +// ReadOptions bounds a one-shot read. SeqNum and Timestamp set the start +// position; Count and Until bound the end. +type ReadOptions struct { + SeqNum *uint64 + Timestamp *uint64 + Count *uint64 + Until *uint64 +} + +// Read returns every telemetry envelope in the bounded range from streamName. +// It opens a fresh client per call and surfaces S2 errors to the caller. +func Read(ctx context.Context, basin, accessToken, streamName string, opts ReadOptions, log *slog.Logger) ([]Envelope, error) { + if basin == "" || accessToken == "" || streamName == "" { + return nil, fmt.Errorf("s2storage: basin, accessToken, and streamName are required") + } + + readOpts := &s2.ReadOptions{ + Clamp: s2.Bool(true), + IgnoreCommandRecords: true, + SeqNum: opts.SeqNum, + Timestamp: opts.Timestamp, + Count: opts.Count, + Until: opts.Until, + } + // An unbounded read blocks waiting for new records; cap it at the tail. + if readOpts.Count == nil && readOpts.Until == nil { + readOpts.Until = s2.Uint64(uint64(time.Now().UnixMilli())) + } + + client := s2.New(accessToken, nil) + stream := client.Basin(basin).Stream(s2.StreamName(streamName)) + + session, err := stream.ReadSession(ctx, readOpts) + if err != nil { + return nil, fmt.Errorf("s2storage: open read session: %w", err) + } + defer session.Close() + + envelopes := make([]Envelope, 0) + for session.Next() { + rec := session.Record() + var env Envelope + if err := json.Unmarshal(rec.Body, &env); err != nil { + return nil, fmt.Errorf("s2storage: unmarshal envelope seqnum=%d: %w", rec.SeqNum, err) + } + envelopes = append(envelopes, env) + } + if err := session.Err(); err != nil { + return nil, fmt.Errorf("s2storage: read session: %w", err) + } + + log.DebugContext(ctx, "s2storage: read complete", "stream", streamName, "records", len(envelopes)) + return envelopes, nil +} From b4ce0a40528bb23947322908510d459b10d2a9d4 Mon Sep 17 00:00:00 2001 From: archandatta <35818003+archandatta@users.noreply.github.com> Date: Wed, 10 Jun 2026 14:24:18 +0000 Subject: [PATCH 03/10] feat: make S2 batcher linger and max-records configurable Co-Authored-By: Claude Opus 4.7 --- server/cmd/api/main.go | 5 ++++- server/cmd/config/config.go | 5 +++++ server/cmd/config/config_test.go | 8 ++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/server/cmd/api/main.go b/server/cmd/api/main.go index b3500a52..5054c9c8 100644 --- a/server/cmd/api/main.go +++ b/server/cmd/api/main.go @@ -118,7 +118,10 @@ func main() { var s2Writer *events.S2StorageWriter if config.S2Basin != "" && config.S2AccessToken != "" && config.S2Stream != "" { slogger.Info("S2 storage enabled", "basin", config.S2Basin, "stream", config.S2Stream) - s2Writer = events.NewS2StorageWriter(eventStream, config.S2Basin, config.S2AccessToken, config.S2Stream, events.S2Config{}, slogger) + s2Writer = events.NewS2StorageWriter(eventStream, config.S2Basin, config.S2AccessToken, config.S2Stream, events.S2Config{ + BatcherLinger: config.S2BatcherLinger, + BatcherMaxRecords: config.S2BatcherMaxRecords, + }, slogger) if err := s2Writer.Start(ctx); err != nil { slogger.Error("failed to start S2 storage writer", "err", err) os.Exit(1) diff --git a/server/cmd/config/config.go b/server/cmd/config/config.go index aae38b9e..1caa3cd7 100644 --- a/server/cmd/config/config.go +++ b/server/cmd/config/config.go @@ -47,6 +47,9 @@ type Config struct { S2Basin string `envconfig:"S2_BASIN" default:""` S2AccessToken string `envconfig:"S2_ACCESS_TOKEN" default:""` S2Stream string `envconfig:"S2_STREAM" default:""` + // S2 batcher tuning for the append path. + S2BatcherLinger time.Duration `envconfig:"S2_BATCHER_LINGER" default:"100ms"` + S2BatcherMaxRecords int `envconfig:"S2_BATCHER_MAX_RECORDS" default:"50"` } // LogValue implements slog.LogValuer, redacting secret fields. @@ -73,6 +76,8 @@ func (c *Config) LogValue() slog.Value { slog.String("s2_basin", c.S2Basin), slog.String("s2_access_token", s2AccessToken), slog.String("s2_stream", c.S2Stream), + slog.Duration("s2_batcher_linger", c.S2BatcherLinger), + slog.Int("s2_batcher_max_records", c.S2BatcherMaxRecords), ) } diff --git a/server/cmd/config/config_test.go b/server/cmd/config/config_test.go index 27dd8b3d..447e7ac9 100644 --- a/server/cmd/config/config_test.go +++ b/server/cmd/config/config_test.go @@ -31,6 +31,8 @@ func TestLoad(t *testing.T) { ChromeDriverProxyPort: 9224, ChromeDriverUpstreamAddr: "127.0.0.1:9225", DevToolsProxyAddr: "127.0.0.1:9222", + S2BatcherLinger: 100 * time.Millisecond, + S2BatcherMaxRecords: 50, }, }, { @@ -48,6 +50,8 @@ func TestLoad(t *testing.T) { "SCALE_TO_ZERO_COOLDOWN": "5s", "CHROMEDRIVER_PROXY_PORT": "5432", "CHROMEDRIVER_UPSTREAM_ADDR": "127.0.0.1:9999", + "S2_BATCHER_LINGER": "250ms", + "S2_BATCHER_MAX_RECORDS": "100", }, wantCfg: &Config{ Port: 12345, @@ -63,6 +67,8 @@ func TestLoad(t *testing.T) { ChromeDriverProxyPort: 5432, ChromeDriverUpstreamAddr: "127.0.0.1:9999", DevToolsProxyAddr: "127.0.0.1:9876", + S2BatcherLinger: 250 * time.Millisecond, + S2BatcherMaxRecords: 100, }, }, { @@ -85,6 +91,8 @@ func TestLoad(t *testing.T) { ChromeDriverProxyPort: 9224, ChromeDriverUpstreamAddr: "127.0.0.1:9225", DevToolsProxyAddr: "10.0.0.1:1234", + S2BatcherLinger: 100 * time.Millisecond, + S2BatcherMaxRecords: 50, }, }, { From d15c099cb3150d83f47fbb31fba1a1f3e147d8ba Mon Sep 17 00:00:00 2001 From: archandatta <35818003+archandatta@users.noreply.github.com> Date: Wed, 10 Jun 2026 17:37:12 +0000 Subject: [PATCH 04/10] feat: add GET /telemetry/events to read archived telemetry from S2 Co-Authored-By: Claude Opus 4.7 --- server/cmd/api/api/api.go | 17 + server/cmd/api/api/api_test.go | 2 +- server/cmd/api/api/display_test.go | 2 +- server/cmd/api/api/events.go | 110 +++ server/cmd/api/api/events_test.go | 68 ++ server/cmd/api/api/telemetry_test.go | 2 +- server/cmd/api/main.go | 3 + server/lib/oapi/oapi.go | 1045 +++++++++++++++++--------- server/openapi.yaml | 58 ++ 9 files changed, 944 insertions(+), 363 deletions(-) diff --git a/server/cmd/api/api/api.go b/server/cmd/api/api/api.go index b9b0a346..cf7764f3 100644 --- a/server/cmd/api/api/api.go +++ b/server/cmd/api/api/api.go @@ -92,6 +92,17 @@ type ApiService struct { monitorMu sync.Mutex lifecycleCtx context.Context lifecycleCancel context.CancelFunc + + // Durable S2 telemetry storage. All three must be set for reads to hit S2; + // they mirror the values that gate the S2 storage writer. + s2Basin string + s2AccessToken string + s2Stream string +} + +// s2Enabled reports whether durable S2 telemetry storage is configured. +func (s *ApiService) s2Enabled() bool { + return s.s2Basin != "" && s.s2AccessToken != "" && s.s2Stream != "" } var _ oapi.StrictServerInterface = (*ApiService)(nil) @@ -105,6 +116,9 @@ func New( telemetrySession *telemetry.TelemetrySession, eventStream *events.EventStream, displayNum int, + s2Basin string, + s2AccessToken string, + s2Stream string, ) (*ApiService, error) { switch { case recordManager == nil: @@ -140,6 +154,9 @@ func New( cdpMonitor: mon, lifecycleCtx: ctx, lifecycleCancel: cancel, + s2Basin: s2Basin, + s2AccessToken: s2AccessToken, + s2Stream: s2Stream, }, nil } diff --git a/server/cmd/api/api/api_test.go b/server/cmd/api/api/api_test.go index 4f2c2165..4d1a3b4d 100644 --- a/server/cmd/api/api/api_test.go +++ b/server/cmd/api/api/api_test.go @@ -321,7 +321,7 @@ func newTelemetrySession(t *testing.T) (*telemetry.TelemetrySession, *events.Eve func newSvc(t *testing.T, mgr recorder.RecordManager) (*ApiService, error) { t.Helper() ts, es := newTelemetrySession(t) - return New(mgr, newMockFactory(), newTestUpstreamManager(), scaletozero.NewNoopController(), newMockNekoClient(t), ts, es, 0) + return New(mgr, newMockFactory(), newTestUpstreamManager(), scaletozero.NewNoopController(), newMockNekoClient(t), ts, es, 0, "", "", "") } func TestApiService_PatchChromiumFlags(t *testing.T) { diff --git a/server/cmd/api/api/display_test.go b/server/cmd/api/api/display_test.go index 154b6359..175b22ad 100644 --- a/server/cmd/api/api/display_test.go +++ b/server/cmd/api/api/display_test.go @@ -36,7 +36,7 @@ func testFFmpegFactory(t *testing.T, tempDir string) recorder.FFmpegRecorderFact func newTestServiceWithFactory(t *testing.T, mgr recorder.RecordManager, factory recorder.FFmpegRecorderFactory) *ApiService { t.Helper() ts, es := newTelemetrySession(t) - svc, err := New(mgr, factory, newTestUpstreamManager(), scaletozero.NewNoopController(), newMockNekoClient(t), ts, es, 0) + svc, err := New(mgr, factory, newTestUpstreamManager(), scaletozero.NewNoopController(), newMockNekoClient(t), ts, es, 0, "", "", "") require.NoError(t, err) return svc } diff --git a/server/cmd/api/api/events.go b/server/cmd/api/api/events.go index 27dfc50a..c444e5f6 100644 --- a/server/cmd/api/api/events.go +++ b/server/cmd/api/api/events.go @@ -12,6 +12,7 @@ import ( "time" "github.com/kernel/kernel-images/server/lib/events" + "github.com/kernel/kernel-images/server/lib/logger" oapi "github.com/kernel/kernel-images/server/lib/oapi" ) @@ -136,6 +137,115 @@ func (s *ApiService) StreamTelemetryEvents(ctx context.Context, req oapi.StreamT return oapi.StreamTelemetryEvents200TexteventStreamResponse{Body: pr, Headers: headers}, nil } +// defaultReadWindow bounds a read that supplies no since/until. +const defaultReadWindow = 5 * time.Minute + +// maxReadLimit caps the number of envelopes a single read returns. +const maxReadLimit = 1000 + +// ReadTelemetryEvents handles GET /telemetry/events. +// Reads archived telemetry envelopes for the current session from durable S2 +// storage, applies category and limit filters, and returns them in ascending +// sequence order. Returns an empty list when S2 storage is not configured. +func (s *ApiService) ReadTelemetryEvents(ctx context.Context, req oapi.ReadTelemetryEventsRequestObject) (oapi.ReadTelemetryEventsResponseObject, error) { + log := logger.FromContext(ctx) + + if !s.s2Enabled() { + return readTelemetryEventsOKResponse{}, nil + } + + startSeq := s.telemetrySession.SessionStartSeq() + envs, err := events.Read(ctx, s.s2Basin, s.s2AccessToken, s.s2Stream, buildReadOptions(req.Params), log) + if err != nil { + log.Error("failed to read telemetry events from S2", "err", err) + return oapi.ReadTelemetryEvents500JSONResponse{InternalErrorJSONResponse: oapi.InternalErrorJSONResponse{Message: "failed to read telemetry events"}}, nil + } + + envs = dropPriorSessions(envs, startSeq) + envs = filterByCategory(envs, req.Params.Category) + envs = capLimit(envs, req.Params.Limit) + + return readTelemetryEventsOKResponse{envs: envs}, nil +} + +// buildReadOptions maps query params to a bounded read window. since/until are +// the start/end of the window; the window defaults to the last defaultReadWindow. +// limit is applied after category filtering, not pushed into the S2 read. +func buildReadOptions(p oapi.ReadTelemetryEventsParams) events.ReadOptions { + var opts events.ReadOptions + if p.Since != nil { + start := uint64(*p.Since) + opts.Timestamp = &start + } else { + start := uint64(time.Now().Add(-defaultReadWindow).UnixMilli()) + opts.Timestamp = &start + } + if p.Until != nil { + until := uint64(*p.Until) + opts.Until = &until + } + return opts +} + +// dropPriorSessions removes envelopes from before the current session's start. +// startSeq is 0 when no session has run, in which case nothing is dropped. +func dropPriorSessions(envs []events.Envelope, startSeq uint64) []events.Envelope { + if startSeq == 0 { + return envs + } + out := make([]events.Envelope, 0, len(envs)) + for _, e := range envs { + if e.Seq >= startSeq { + out = append(out, e) + } + } + return out +} + +func filterByCategory(envs []events.Envelope, cats *[]oapi.TelemetryEventCategory) []events.Envelope { + if cats == nil || len(*cats) == 0 { + return envs + } + want := make(map[oapi.TelemetryEventCategory]struct{}, len(*cats)) + for _, c := range *cats { + want[c] = struct{}{} + } + out := make([]events.Envelope, 0, len(envs)) + for _, e := range envs { + if _, ok := want[e.Event.Category]; ok { + out = append(out, e) + } + } + return out +} + +func capLimit(envs []events.Envelope, limit *int) []events.Envelope { + n := maxReadLimit + if limit != nil && *limit > 0 && *limit < n { + n = *limit + } + if len(envs) > n { + return envs[:n] + } + return envs +} + +// readTelemetryEventsOKResponse serializes events.Envelope directly so the +// response shape matches the SSE stream frames and the publish endpoint. +type readTelemetryEventsOKResponse struct{ envs []events.Envelope } + +func (r readTelemetryEventsOKResponse) VisitReadTelemetryEventsResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + envs := r.envs + if envs == nil { + envs = []events.Envelope{} + } + return json.NewEncoder(w).Encode(struct { + Events []events.Envelope `json:"events"` + }{Events: envs}) +} + // publishTelemetryEventOKResponse serializes events.Envelope directly so the response // is identical in shape to the SSE stream frames. type publishTelemetryEventOKResponse struct{ env events.Envelope } diff --git a/server/cmd/api/api/events_test.go b/server/cmd/api/api/events_test.go index 36ab935f..208e619e 100644 --- a/server/cmd/api/api/events_test.go +++ b/server/cmd/api/api/events_test.go @@ -4,6 +4,8 @@ import ( "bufio" "context" "encoding/json" + "net/http" + "net/http/httptest" "strconv" "strings" "testing" @@ -296,3 +298,69 @@ func TestStreamResumeAfterLastEventIDUnchanged(t *testing.T) { id := streamFirstID(t, svc, oapi.StreamTelemetryEventsParams{LastEventID: ptrOf("5")}) assert.Equal(t, uint64(6), id, "Last-Event-ID without replay must behave as before and resume after seq 5") } + +func TestReadTelemetryEventsS2Disabled(t *testing.T) { + t.Parallel() + svc := newTestService(t, newMockRecordManager()) // s2 creds empty -> disabled + + resp, err := svc.ReadTelemetryEvents(context.Background(), oapi.ReadTelemetryEventsRequestObject{}) + require.NoError(t, err) + ok, isOK := resp.(readTelemetryEventsOKResponse) + require.True(t, isOK, "expected 200 response when S2 is disabled") + + rec := httptest.NewRecorder() + require.NoError(t, ok.VisitReadTelemetryEventsResponse(rec)) + assert.Equal(t, http.StatusOK, rec.Code) + // Empty result must serialize as [] not null, or the Python SDK chokes. + assert.JSONEq(t, `{"events":[]}`, rec.Body.String()) +} + +func TestDropPriorSessions(t *testing.T) { + t.Parallel() + envs := []events.Envelope{{Seq: 1}, {Seq: 2}, {Seq: 3}} + + got := dropPriorSessions(envs, 2) + require.Len(t, got, 2) + assert.Equal(t, uint64(2), got[0].Seq) + + // startSeq 0 means no session ran; keep everything. + assert.Len(t, dropPriorSessions(envs, 0), 3) +} + +func TestFilterByCategory(t *testing.T) { + t.Parallel() + mk := func(c oapi.TelemetryEventCategory) events.Envelope { + return events.Envelope{Event: events.Event{Category: c}} + } + envs := []events.Envelope{mk(events.Console), mk(events.Network), mk(events.Console)} + + assert.Len(t, filterByCategory(envs, nil), 3, "nil filter keeps everything") + + cats := []oapi.TelemetryEventCategory{events.Console} + assert.Len(t, filterByCategory(envs, &cats), 2) +} + +func TestCapLimit(t *testing.T) { + t.Parallel() + envs := make([]events.Envelope, 5) + + assert.Len(t, capLimit(envs, nil), 5, "no limit returns all under the ceiling") + + three := 3 + assert.Len(t, capLimit(envs, &three), 3) +} + +func TestBuildReadOptions(t *testing.T) { + t.Parallel() + // No params: defaults the start to roughly defaultReadWindow ago, no end bound. + opts := buildReadOptions(oapi.ReadTelemetryEventsParams{}) + require.NotNil(t, opts.Timestamp) + assert.Nil(t, opts.Until) + + since, until := int64(1000), int64(2000) + opts = buildReadOptions(oapi.ReadTelemetryEventsParams{Since: &since, Until: &until}) + require.NotNil(t, opts.Timestamp) + require.NotNil(t, opts.Until) + assert.Equal(t, uint64(1000), *opts.Timestamp) + assert.Equal(t, uint64(2000), *opts.Until) +} diff --git a/server/cmd/api/api/telemetry_test.go b/server/cmd/api/api/telemetry_test.go index 258b6987..27cb595c 100644 --- a/server/cmd/api/api/telemetry_test.go +++ b/server/cmd/api/api/telemetry_test.go @@ -358,7 +358,7 @@ func (m *mockRecordManager) StopAll(_ context.Context) error func newTestService(t *testing.T, mgr recorder.RecordManager) *ApiService { t.Helper() ts, es := newTelemetrySession(t) - svc, err := New(mgr, newMockFactory(), newTestUpstreamManager(), scaletozero.NewNoopController(), newMockNekoClient(t), ts, es, 0) + svc, err := New(mgr, newMockFactory(), newTestUpstreamManager(), scaletozero.NewNoopController(), newMockNekoClient(t), ts, es, 0, "", "", "") require.NoError(t, err) svc.cdpMonitor = &stubCdpMonitor{} return svc diff --git a/server/cmd/api/main.go b/server/cmd/api/main.go index 5054c9c8..78f79524 100644 --- a/server/cmd/api/main.go +++ b/server/cmd/api/main.go @@ -137,6 +137,9 @@ func main() { telemetrySession, eventStream, config.DisplayNum, + config.S2Basin, + config.S2AccessToken, + config.S2Stream, ) if err != nil { slogger.Error("failed to create api service", "err", err) diff --git a/server/lib/oapi/oapi.go b/server/lib/oapi/oapi.go index e4aa146a..52a2034b 100644 --- a/server/lib/oapi/oapi.go +++ b/server/lib/oapi/oapi.go @@ -3850,6 +3850,21 @@ type DownloadRecordingParams struct { Id *string `form:"id,omitempty" json:"id,omitempty"` } +// ReadTelemetryEventsParams defines parameters for ReadTelemetryEvents. +type ReadTelemetryEventsParams struct { + // Since Start of the time window, unix milliseconds. Defaults to 5 minutes ago. + Since *int64 `form:"since,omitempty" json:"since,omitempty"` + + // Until End of the time window (exclusive), unix milliseconds. Defaults to the current time. + Until *int64 `form:"until,omitempty" json:"until,omitempty"` + + // Limit Maximum number of events to return. + Limit *int `form:"limit,omitempty" json:"limit,omitempty"` + + // Category Restrict results to these event categories. Repeat the parameter for multiple values. + Category *[]TelemetryEventCategory `form:"category,omitempty" json:"category,omitempty"` +} + // StreamTelemetryEventsParams defines parameters for StreamTelemetryEvents. type StreamTelemetryEventsParams struct { // Replay Pass `all` to start from the oldest retained event. Ring buffer caps at 1024; older events are evicted and surface as a first `id` greater than 1. @@ -5191,6 +5206,9 @@ type ClientInterface interface { PutTelemetry(ctx context.Context, body PutTelemetryJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + // ReadTelemetryEvents request + ReadTelemetryEvents(ctx context.Context, params *ReadTelemetryEventsParams, reqEditors ...RequestEditorFn) (*http.Response, error) + // PublishTelemetryEventWithBody request with any body PublishTelemetryEventWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -6196,6 +6214,18 @@ func (c *Client) PutTelemetry(ctx context.Context, body PutTelemetryJSONRequestB return c.Client.Do(req) } +func (c *Client) ReadTelemetryEvents(ctx context.Context, params *ReadTelemetryEventsParams, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewReadTelemetryEventsRequest(c.Server, params) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + func (c *Client) PublishTelemetryEventWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { req, err := NewPublishTelemetryEventRequestWithBody(c.Server, contentType, body) if err != nil { @@ -8342,6 +8372,103 @@ func NewPutTelemetryRequestWithBody(server string, contentType string, body io.R return req, nil } +// NewReadTelemetryEventsRequest generates requests for ReadTelemetryEvents +func NewReadTelemetryEventsRequest(server string, params *ReadTelemetryEventsParams) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/telemetry/events") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + if params != nil { + queryValues := queryURL.Query() + + if params.Since != nil { + + if queryFrag, err := runtime.StyleParamWithOptions("form", true, "since", *params.Since, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "integer", Format: "int64"}); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + if params.Until != nil { + + if queryFrag, err := runtime.StyleParamWithOptions("form", true, "until", *params.Until, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "integer", Format: "int64"}); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + if params.Limit != nil { + + if queryFrag, err := runtime.StyleParamWithOptions("form", true, "limit", *params.Limit, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "integer", Format: ""}); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + if params.Category != nil { + + if queryFrag, err := runtime.StyleParamWithOptions("form", true, "category", *params.Category, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "array", Format: ""}); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + queryURL.RawQuery = queryValues.Encode() + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + // NewPublishTelemetryEventRequest calls the generic PublishTelemetryEvent builder with application/json body func NewPublishTelemetryEventRequest(server string, body PublishTelemetryEventJSONRequestBody) (*http.Request, error) { var bodyReader io.Reader @@ -8708,6 +8835,9 @@ type ClientWithResponsesInterface interface { PutTelemetryWithResponse(ctx context.Context, body PutTelemetryJSONRequestBody, reqEditors ...RequestEditorFn) (*PutTelemetryResponse, error) + // ReadTelemetryEventsWithResponse request + ReadTelemetryEventsWithResponse(ctx context.Context, params *ReadTelemetryEventsParams, reqEditors ...RequestEditorFn) (*ReadTelemetryEventsResponse, error) + // PublishTelemetryEventWithBodyWithResponse request with any body PublishTelemetryEventWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PublishTelemetryEventResponse, error) @@ -9979,6 +10109,31 @@ func (r PutTelemetryResponse) StatusCode() int { return 0 } +type ReadTelemetryEventsResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *struct { + Events []TelemetryEnvelope `json:"events"` + } + JSON500 *InternalError +} + +// Status returns HTTPResponse.Status +func (r ReadTelemetryEventsResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r ReadTelemetryEventsResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + type PublishTelemetryEventResponse struct { Body []byte HTTPResponse *http.Response @@ -10740,6 +10895,15 @@ func (c *ClientWithResponses) PutTelemetryWithResponse(ctx context.Context, body return ParsePutTelemetryResponse(rsp) } +// ReadTelemetryEventsWithResponse request returning *ReadTelemetryEventsResponse +func (c *ClientWithResponses) ReadTelemetryEventsWithResponse(ctx context.Context, params *ReadTelemetryEventsParams, reqEditors ...RequestEditorFn) (*ReadTelemetryEventsResponse, error) { + rsp, err := c.ReadTelemetryEvents(ctx, params, reqEditors...) + if err != nil { + return nil, err + } + return ParseReadTelemetryEventsResponse(rsp) +} + // PublishTelemetryEventWithBodyWithResponse request with arbitrary body returning *PublishTelemetryEventResponse func (c *ClientWithResponses) PublishTelemetryEventWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PublishTelemetryEventResponse, error) { rsp, err := c.PublishTelemetryEventWithBody(ctx, contentType, body, reqEditors...) @@ -12795,6 +12959,41 @@ func ParsePutTelemetryResponse(rsp *http.Response) (*PutTelemetryResponse, error return response, nil } +// ParseReadTelemetryEventsResponse parses an HTTP response from a ReadTelemetryEventsWithResponse call +func ParseReadTelemetryEventsResponse(rsp *http.Response) (*ReadTelemetryEventsResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &ReadTelemetryEventsResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest struct { + Events []TelemetryEnvelope `json:"events"` + } + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: + var dest InternalError + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON500 = &dest + + } + + return response, nil +} + // ParsePublishTelemetryEventResponse parses an HTTP response from a PublishTelemetryEventWithResponse call func ParsePublishTelemetryEventResponse(rsp *http.Response) (*PublishTelemetryEventResponse, error) { bodyBytes, err := io.ReadAll(rsp.Body) @@ -13005,6 +13204,9 @@ type ServerInterface interface { // Set telemetry configuration // (PUT /telemetry) PutTelemetry(w http.ResponseWriter, r *http.Request) + // Read archived telemetry events from durable storage + // (GET /telemetry/events) + ReadTelemetryEvents(w http.ResponseWriter, r *http.Request, params ReadTelemetryEventsParams) // Publish an event into the telemetry stream // (POST /telemetry/events) PublishTelemetryEvent(w http.ResponseWriter, r *http.Request) @@ -13335,6 +13537,12 @@ func (_ Unimplemented) PutTelemetry(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNotImplemented) } +// Read archived telemetry events from durable storage +// (GET /telemetry/events) +func (_ Unimplemented) ReadTelemetryEvents(w http.ResponseWriter, r *http.Request, params ReadTelemetryEventsParams) { + w.WriteHeader(http.StatusNotImplemented) +} + // Publish an event into the telemetry stream // (POST /telemetry/events) func (_ Unimplemented) PublishTelemetryEvent(w http.ResponseWriter, r *http.Request) { @@ -14368,6 +14576,57 @@ func (siw *ServerInterfaceWrapper) PutTelemetry(w http.ResponseWriter, r *http.R handler.ServeHTTP(w, r) } +// ReadTelemetryEvents operation middleware +func (siw *ServerInterfaceWrapper) ReadTelemetryEvents(w http.ResponseWriter, r *http.Request) { + + var err error + + // Parameter object where we will unmarshal all parameters from the context + var params ReadTelemetryEventsParams + + // ------------- Optional query parameter "since" ------------- + + err = runtime.BindQueryParameterWithOptions("form", true, false, "since", r.URL.Query(), ¶ms.Since, runtime.BindQueryParameterOptions{Type: "integer", Format: "int64"}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "since", Err: err}) + return + } + + // ------------- Optional query parameter "until" ------------- + + err = runtime.BindQueryParameterWithOptions("form", true, false, "until", r.URL.Query(), ¶ms.Until, runtime.BindQueryParameterOptions{Type: "integer", Format: "int64"}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "until", Err: err}) + return + } + + // ------------- Optional query parameter "limit" ------------- + + err = runtime.BindQueryParameterWithOptions("form", true, false, "limit", r.URL.Query(), ¶ms.Limit, runtime.BindQueryParameterOptions{Type: "integer", Format: ""}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err}) + return + } + + // ------------- Optional query parameter "category" ------------- + + err = runtime.BindQueryParameterWithOptions("form", true, false, "category", r.URL.Query(), ¶ms.Category, runtime.BindQueryParameterOptions{Type: "array", Format: ""}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "category", Err: err}) + return + } + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.ReadTelemetryEvents(w, r, params) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + // PublishTelemetryEvent operation middleware func (siw *ServerInterfaceWrapper) PublishTelemetryEvent(w http.ResponseWriter, r *http.Request) { @@ -14702,6 +14961,9 @@ func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handl r.Group(func(r chi.Router) { r.Put(options.BaseURL+"/telemetry", wrapper.PutTelemetry) }) + r.Group(func(r chi.Router) { + r.Get(options.BaseURL+"/telemetry/events", wrapper.ReadTelemetryEvents) + }) r.Group(func(r chi.Router) { r.Post(options.BaseURL+"/telemetry/events", wrapper.PublishTelemetryEvent) }) @@ -16931,6 +17193,34 @@ func (response PutTelemetry500JSONResponse) VisitPutTelemetryResponse(w http.Res return json.NewEncoder(w).Encode(response) } +type ReadTelemetryEventsRequestObject struct { + Params ReadTelemetryEventsParams +} + +type ReadTelemetryEventsResponseObject interface { + VisitReadTelemetryEventsResponse(w http.ResponseWriter) error +} + +type ReadTelemetryEvents200JSONResponse struct { + Events []TelemetryEnvelope `json:"events"` +} + +func (response ReadTelemetryEvents200JSONResponse) VisitReadTelemetryEventsResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(200) + + return json.NewEncoder(w).Encode(response) +} + +type ReadTelemetryEvents500JSONResponse struct{ InternalErrorJSONResponse } + +func (response ReadTelemetryEvents500JSONResponse) VisitReadTelemetryEventsResponse(w http.ResponseWriter) error { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(500) + + return json.NewEncoder(w).Encode(response) +} + type PublishTelemetryEventRequestObject struct { Body *PublishTelemetryEventJSONRequestBody } @@ -17183,6 +17473,9 @@ type StrictServerInterface interface { // Set telemetry configuration // (PUT /telemetry) PutTelemetry(ctx context.Context, request PutTelemetryRequestObject) (PutTelemetryResponseObject, error) + // Read archived telemetry events from durable storage + // (GET /telemetry/events) + ReadTelemetryEvents(ctx context.Context, request ReadTelemetryEventsRequestObject) (ReadTelemetryEventsResponseObject, error) // Publish an event into the telemetry stream // (POST /telemetry/events) PublishTelemetryEvent(ctx context.Context, request PublishTelemetryEventRequestObject) (PublishTelemetryEventResponseObject, error) @@ -18784,6 +19077,32 @@ func (sh *strictHandler) PutTelemetry(w http.ResponseWriter, r *http.Request) { } } +// ReadTelemetryEvents operation middleware +func (sh *strictHandler) ReadTelemetryEvents(w http.ResponseWriter, r *http.Request, params ReadTelemetryEventsParams) { + var request ReadTelemetryEventsRequestObject + + request.Params = params + + handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) { + return sh.ssi.ReadTelemetryEvents(ctx, request.(ReadTelemetryEventsRequestObject)) + } + for _, middleware := range sh.middlewares { + handler = middleware(handler, "ReadTelemetryEvents") + } + + response, err := handler(r.Context(), w, r, request) + + if err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } else if validResponse, ok := response.(ReadTelemetryEventsResponseObject); ok { + if err := validResponse.VisitReadTelemetryEventsResponse(w); err != nil { + sh.options.ResponseErrorHandlerFunc(w, r, err) + } + } else if response != nil { + sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response)) + } +} + // PublishTelemetryEvent operation middleware func (sh *strictHandler) PublishTelemetryEvent(w http.ResponseWriter, r *http.Request) { var request PublishTelemetryEventRequestObject @@ -18844,366 +19163,372 @@ func (sh *strictHandler) StreamTelemetryEvents(w http.ResponseWriter, r *http.Re // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", - "0UsAN/r/CwAA///NImELd8ABAA==", + "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", + "fvQSwI3+/wIAAP//Ltc+3oHGAQA=", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/server/openapi.yaml b/server/openapi.yaml index d1785267..fb1c467b 100644 --- a/server/openapi.yaml +++ b/server/openapi.yaml @@ -1379,6 +1379,64 @@ paths: description: Event accepted but filtered by the active telemetry config; not published. "400": $ref: "#/components/responses/BadRequestError" + get: + summary: Read archived telemetry events from durable storage + description: > + Reads telemetry event envelopes for the current session from durable S2 + storage, so events remain available after they age out of the live SSE + ring buffer. Results are scoped to the current session and returned in + ascending sequence order within the requested time window. Returns an + empty list when durable storage is not configured. + operationId: readTelemetryEvents + parameters: + - in: query + name: since + required: false + description: Start of the time window, unix milliseconds. Defaults to 5 minutes ago. + schema: + type: integer + format: int64 + - in: query + name: until + required: false + description: End of the time window (exclusive), unix milliseconds. Defaults to the current time. + schema: + type: integer + format: int64 + - in: query + name: limit + required: false + description: Maximum number of events to return. + schema: + type: integer + minimum: 1 + maximum: 1000 + - in: query + name: category + required: false + description: Restrict results to these event categories. Repeat the parameter for multiple values. + schema: + type: array + items: + $ref: "#/components/schemas/TelemetryEventCategory" + style: form + explode: true + responses: + "200": + description: Telemetry events from durable storage in ascending sequence order. + content: + application/json: + schema: + type: object + required: + - events + properties: + events: + type: array + items: + $ref: "#/components/schemas/TelemetryEnvelope" + "500": + $ref: "#/components/responses/InternalError" /telemetry/stream: get: summary: Stream telemetry events as Server-Sent Events From 72a74d1e9906b30e31325382792d7aa2a06a42c2 Mon Sep 17 00:00:00 2001 From: archandatta <35818003+archandatta@users.noreply.github.com> Date: Wed, 10 Jun 2026 18:12:22 +0000 Subject: [PATCH 05/10] test: add e2e read path for GET /telemetry/events Co-Authored-By: Claude Opus 4.7 --- server/e2e/e2e_telemetry_events_read_test.go | 119 +++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 server/e2e/e2e_telemetry_events_read_test.go diff --git a/server/e2e/e2e_telemetry_events_read_test.go b/server/e2e/e2e_telemetry_events_read_test.go new file mode 100644 index 00000000..a6fd4d40 --- /dev/null +++ b/server/e2e/e2e_telemetry_events_read_test.go @@ -0,0 +1,119 @@ +package e2e + +import ( + "context" + "net/http" + "os" + "os/exec" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + instanceoapi "github.com/kernel/kernel-images/server/lib/oapi" +) + +// TestReadTelemetryEvents starts a headless container with S2 credentials, +// publishes a known set of events, and reads them back through +// GET /telemetry/events. It exercises the full archive read path against a real +// S2 stream rather than the in-memory ring buffer. +// +// Skips automatically when S2_BASIN, S2_ACCESS_TOKEN, or S2_STREAM are unset. +func TestReadTelemetryEvents(t *testing.T) { + basin := os.Getenv("S2_BASIN") + accessToken := os.Getenv("S2_ACCESS_TOKEN") + stream := os.Getenv("S2_STREAM") + if basin == "" || accessToken == "" || stream == "" { + t.Skip("S2_BASIN, S2_ACCESS_TOKEN, and S2_STREAM must be set to run this test") + } + + if _, err := exec.LookPath("docker"); err != nil { + t.Skipf("docker not available: %v", err) + } + + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute) + defer cancel() + + c := NewTestContainer(t, headlessImage) + require.NoError(t, c.Start(ctx, ContainerConfig{ + Env: map[string]string{ + "S2_BASIN": basin, + "S2_ACCESS_TOKEN": accessToken, + "S2_STREAM": stream, + }, + }), "failed to start container") + defer c.Stop(ctx) + + require.NoError(t, c.WaitReady(ctx), "api not ready") + + client, err := c.APIClient() + require.NoError(t, err) + + // Start a telemetry session. The default config enables the system and + // connection categories, which is what we publish into below. + startResp, err := client.PutTelemetryWithResponse(ctx, instanceoapi.PutTelemetryJSONRequestBody{}) + require.NoError(t, err) + require.Equal(t, http.StatusCreated, startResp.StatusCode(), "put telemetry: %s", string(startResp.Body)) + + // Publish a deterministic set of events across two enabled categories. + const systemCount, connectionCount = 3, 2 + for i := 0; i < systemCount; i++ { + publishEvent(t, ctx, client, "test.system", instanceoapi.PublishEventRequestCategorySystem) + } + for i := 0; i < connectionCount; i++ { + publishEvent(t, ctx, client, "test.connection", instanceoapi.PublishEventRequestCategoryConnection) + } + + // Give the storage writer time to flush to S2 (batcher linger + network). + time.Sleep(2 * time.Second) + + // Bound every read tightly: a correct handler caps the S2 read at the tail, + // so these return promptly. A hang here means the read is unbounded. + readCtx, readCancel := context.WithTimeout(ctx, 10*time.Second) + defer readCancel() + + // Full read returns at least everything we published. + all, err := client.ReadTelemetryEventsWithResponse(readCtx, &instanceoapi.ReadTelemetryEventsParams{}) + require.NoError(t, err) + require.Equal(t, http.StatusOK, all.StatusCode(), "read events: %s", string(all.Body)) + require.NotNil(t, all.JSON200) + assert.GreaterOrEqual(t, len(all.JSON200.Events), systemCount+connectionCount) + + // Category filter returns only the requested category. + systemCat := []instanceoapi.TelemetryEventCategory{instanceoapi.TelemetryEventCategorySystem} + systemOnly, err := client.ReadTelemetryEventsWithResponse(readCtx, &instanceoapi.ReadTelemetryEventsParams{Category: &systemCat}) + require.NoError(t, err) + require.Equal(t, http.StatusOK, systemOnly.StatusCode()) + require.NotNil(t, systemOnly.JSON200) + assert.GreaterOrEqual(t, len(systemOnly.JSON200.Events), systemCount) + for _, e := range systemOnly.JSON200.Events { + require.NotNil(t, e.Event.Category) + assert.Equal(t, instanceoapi.TelemetryEventCategorySystem, *e.Event.Category) + } + + // Limit caps the number of returned events. + limit := 1 + limited, err := client.ReadTelemetryEventsWithResponse(readCtx, &instanceoapi.ReadTelemetryEventsParams{Limit: &limit}) + require.NoError(t, err) + require.NotNil(t, limited.JSON200) + assert.Len(t, limited.JSON200.Events, 1) + + // An empty window returns [] not null, or the Python SDK chokes deserializing. + pastSince, pastUntil := int64(1), int64(2) + empty, err := client.ReadTelemetryEventsWithResponse(readCtx, &instanceoapi.ReadTelemetryEventsParams{Since: &pastSince, Until: &pastUntil}) + require.NoError(t, err) + require.NotNil(t, empty.JSON200) + assert.Empty(t, empty.JSON200.Events) + assert.Contains(t, string(empty.Body), `"events":[]`) +} + +func publishEvent(t *testing.T, ctx context.Context, client *instanceoapi.ClientWithResponses, eventType string, category instanceoapi.PublishEventRequestCategory) { + t.Helper() + resp, err := client.PublishTelemetryEventWithResponse(ctx, instanceoapi.PublishTelemetryEventJSONRequestBody{ + Type: eventType, + Category: &category, + }) + require.NoError(t, err) + require.Equal(t, http.StatusOK, resp.StatusCode(), "publish %s: %s", eventType, string(resp.Body)) +} From 0f44c616e92c9dd640674548b1d27efa7b594d85 Mon Sep 17 00:00:00 2001 From: archandatta <35818003+archandatta@users.noreply.github.com> Date: Thu, 11 Jun 2026 12:37:27 +0000 Subject: [PATCH 06/10] fix: read full per-browser telemetry stream and keep newest events on limit Co-Authored-By: Claude Opus 4.7 --- server/cmd/api/api/events.go | 27 +++++-------------- server/cmd/api/api/events_test.go | 20 +++++--------- server/lib/oapi/oapi.go | 44 +++++++++++++++---------------- server/openapi.yaml | 10 +++---- 4 files changed, 39 insertions(+), 62 deletions(-) diff --git a/server/cmd/api/api/events.go b/server/cmd/api/api/events.go index c444e5f6..d9c5e99b 100644 --- a/server/cmd/api/api/events.go +++ b/server/cmd/api/api/events.go @@ -144,9 +144,9 @@ const defaultReadWindow = 5 * time.Minute const maxReadLimit = 1000 // ReadTelemetryEvents handles GET /telemetry/events. -// Reads archived telemetry envelopes for the current session from durable S2 -// storage, applies category and limit filters, and returns them in ascending -// sequence order. Returns an empty list when S2 storage is not configured. +// Reads archived telemetry envelopes for this browser from durable S2 storage, +// applies category and limit filters, and returns them in ascending sequence +// order. Returns an empty list when S2 storage is not configured. func (s *ApiService) ReadTelemetryEvents(ctx context.Context, req oapi.ReadTelemetryEventsRequestObject) (oapi.ReadTelemetryEventsResponseObject, error) { log := logger.FromContext(ctx) @@ -154,14 +154,12 @@ func (s *ApiService) ReadTelemetryEvents(ctx context.Context, req oapi.ReadTelem return readTelemetryEventsOKResponse{}, nil } - startSeq := s.telemetrySession.SessionStartSeq() envs, err := events.Read(ctx, s.s2Basin, s.s2AccessToken, s.s2Stream, buildReadOptions(req.Params), log) if err != nil { log.Error("failed to read telemetry events from S2", "err", err) return oapi.ReadTelemetryEvents500JSONResponse{InternalErrorJSONResponse: oapi.InternalErrorJSONResponse{Message: "failed to read telemetry events"}}, nil } - envs = dropPriorSessions(envs, startSeq) envs = filterByCategory(envs, req.Params.Category) envs = capLimit(envs, req.Params.Limit) @@ -187,21 +185,6 @@ func buildReadOptions(p oapi.ReadTelemetryEventsParams) events.ReadOptions { return opts } -// dropPriorSessions removes envelopes from before the current session's start. -// startSeq is 0 when no session has run, in which case nothing is dropped. -func dropPriorSessions(envs []events.Envelope, startSeq uint64) []events.Envelope { - if startSeq == 0 { - return envs - } - out := make([]events.Envelope, 0, len(envs)) - for _, e := range envs { - if e.Seq >= startSeq { - out = append(out, e) - } - } - return out -} - func filterByCategory(envs []events.Envelope, cats *[]oapi.TelemetryEventCategory) []events.Envelope { if cats == nil || len(*cats) == 0 { return envs @@ -219,13 +202,15 @@ func filterByCategory(envs []events.Envelope, cats *[]oapi.TelemetryEventCategor return out } +// capLimit returns at most n envelopes, keeping the most recent when the set +// exceeds the limit. Order is preserved (ascending sequence). func capLimit(envs []events.Envelope, limit *int) []events.Envelope { n := maxReadLimit if limit != nil && *limit > 0 && *limit < n { n = *limit } if len(envs) > n { - return envs[:n] + return envs[len(envs)-n:] } return envs } diff --git a/server/cmd/api/api/events_test.go b/server/cmd/api/api/events_test.go index 208e619e..a424f19d 100644 --- a/server/cmd/api/api/events_test.go +++ b/server/cmd/api/api/events_test.go @@ -315,18 +315,6 @@ func TestReadTelemetryEventsS2Disabled(t *testing.T) { assert.JSONEq(t, `{"events":[]}`, rec.Body.String()) } -func TestDropPriorSessions(t *testing.T) { - t.Parallel() - envs := []events.Envelope{{Seq: 1}, {Seq: 2}, {Seq: 3}} - - got := dropPriorSessions(envs, 2) - require.Len(t, got, 2) - assert.Equal(t, uint64(2), got[0].Seq) - - // startSeq 0 means no session ran; keep everything. - assert.Len(t, dropPriorSessions(envs, 0), 3) -} - func TestFilterByCategory(t *testing.T) { t.Parallel() mk := func(c oapi.TelemetryEventCategory) events.Envelope { @@ -342,12 +330,16 @@ func TestFilterByCategory(t *testing.T) { func TestCapLimit(t *testing.T) { t.Parallel() - envs := make([]events.Envelope, 5) + envs := []events.Envelope{{Seq: 1}, {Seq: 2}, {Seq: 3}, {Seq: 4}, {Seq: 5}} assert.Len(t, capLimit(envs, nil), 5, "no limit returns all under the ceiling") three := 3 - assert.Len(t, capLimit(envs, &three), 3) + got := capLimit(envs, &three) + require.Len(t, got, 3) + // The most recent events are kept, in ascending order. + assert.Equal(t, uint64(3), got[0].Seq) + assert.Equal(t, uint64(5), got[2].Seq) } func TestBuildReadOptions(t *testing.T) { diff --git a/server/lib/oapi/oapi.go b/server/lib/oapi/oapi.go index 52a2034b..6a83bef5 100644 --- a/server/lib/oapi/oapi.go +++ b/server/lib/oapi/oapi.go @@ -3858,7 +3858,7 @@ type ReadTelemetryEventsParams struct { // Until End of the time window (exclusive), unix milliseconds. Defaults to the current time. Until *int64 `form:"until,omitempty" json:"until,omitempty"` - // Limit Maximum number of events to return. + // Limit Maximum number of events to return. The most recent events within the window are kept. Limit *int `form:"limit,omitempty" json:"limit,omitempty"` // Category Restrict results to these event categories. Repeat the parameter for multiple values. @@ -19508,27 +19508,27 @@ var swaggerSpec = []string{ "uqIEQx36zU6oZ76vP4M5NLfu6NUvSDkxxBsvGXb5Z0kGXJtQtKlx2lgXIwfFNjE9QadeCsColmkW3Px0", "vtx7U/MfOHPaF/xcx0ZlrOsO2A18E6j4+eGzNhXfciLjhhempuhXPjjLjTt044R1AxyhZ5CEAC5V2IGQ", "LxmvVf+MW0/lbvYmt+3xpRK4lKwnlcXgfsfEznDQJfSZ0oGTAvMEjb/fyTSvSBG4/6u0hleIuwnts9J+", - "Pj774vlq1/ylp9mQgc8b4HSxTuW1zJDVhJRla4Q746yaCz9nIOeQqQJMlcVV6yeqLofWf+p1zMVzd83R", - "fArYBN/fE6j7B+NzLjL8jOq62xksGJ8CQx87BWdmYg74JoHpkdflZALayQ6DcfpOkZpEFeQhi+2GOrXW", - "4ZzcJCDp+uX73FOHFeT5tq52k4oc2K2QqbqtBRaXDPLCUrEiYuRwXH/W7djZAbgio660n5U3al2BprG5", - "PiuluGu2KTTtbIbvWC5k6WwZPlVd7mAjZNJObKictULaP73oxfJMV0KCZRrZINuDuyQrjZjD/sbNtuxf", - "dAHE91tKK7KH7vedL1lYF+UPl1nlCadr+Uzkwra9mDRX7+Wzw8PD/nqnZj92G9MisT5MMkDC+Ie9hsZy", - "pIgd1bAlRKAXZMiq8MicZyW1YXD2qEohvH5Gqxt6ZdY6zFauwTb9Hod5Io01jF1klMSg896DIz3ayae1", - "JNtx016Ybawc4hf4dYt81Mu2wDRteVgJiG5JNHy8ykU+VTldluLxTaEtF3UUnMq/Y+cmJ/mQFkWoUlBP", - "TI/UfTblvr0rptcn2JpiWSE1jb9Dsrbwa2PE1MnpoGRqt4Ff1jCehoev54cvIr9PREYOxD2pwvJBF3iF", - "hd9+Y2oTTpjaikMT78Xhobu/z3kmUlLrvtNC3Cq7zoSZtTnhqeKBaS1c4jPFs0SYJxLzjegoaLfOaK8w", - "mnAd+tXU+A4MMCQ7LuLJoQl5kkCB5FXaGtPrae0V3SXCVh7QJaTdfpYm3IIlls2ulZCX5bdfkNRG3hs+", - "dfTHMhcP2WuezNjEKQBMicFCTErnbCzSl+x3A//4eHUlU275S/Z7QMHA4dv9/epKjt29yQsfUoBVs9AE", - "jBnkSiqrpEjQjipAG3yESbQyZsnw9Unqrxhnb7mxA8TY4PSERA32zfP3OTdQ1nc15DJUXk7x5cEBTMce", - "shOtCm/oYXgtIXzKCxNcK2ORjqlbFfam895sQMGHvwlD9YzsjEv2jPGZk43BvnR7NQASP+0H+XgL2gkK", - "gRUs8ASYBuLNz+NM4Fe+y7XVPLmJzOY0eAoWEov7HbI3mAdVH9+Em+YSyPDxp162tmk9qhwyMMHOAGCr", - "B9r1K1ZwY9j4/9ZQZHzx7zzLxlRhpDWdylIsf4xOJidtPf0aC9y3ALwVDt4zXqApi41xQYIWCRu35dyY", - "uneH+7OHHniXlufMH7EJFrUYZnvu8wU243PURi1jOUtVUuYg3aix07FjaidZCesxdc9yNKd0XpmJdWs3", - "f3P9Z9zWCX5MIqvPDLoGaD80ebTXLBLcjga5u4jk9f1FmBpJxE++b6TSzIBM2WEEHwG9oUHrtjyJN6oW", - "Y6HRR2wEjs20hgSrAtFS3K0hpB2yS34D2NM7gZQsjzloNia6GZNaxcbCtDA2rcTlnEDipVUDDZ6M6+Uy", - "4BJbJiIh0QPwgKZ0GJoJg4WO6xrbFFdQm6EtJtgt3fQMCX8Xgh+y8/pGyRInT7hlzw6fv3iFAypi5g1J", - "gAlDpZ7wBKh89ERoY4nZp5hrrL2UGXaWEieIxIPosux+1cAfEIa4lT5/u4Uy+sPlvq4YxdywC4ykGlw4", - "fvQSwI3+/wIAAP//Ltc+3oHGAQA=", + "Pj774vlq1/ylp9mQgc8b4HSxTuW1zJDVhJRla4Q746yaCz9nIOeQqQKMz+ISpmIeNPtTr1wunrv7jeZT", + "wO73/oJAbT8Yn3OR4WdU0N3OYMH4FBg61ykqMxNzwMcIzIu8LicT0E5oGAzQ5+RIqqI0uUlA0q3Kt6+n", + "xinIym0VDCl5pm6FTNVtLYe4ZJAXlmoQEX+Gw/iTbMelDm4VdXRl86w8Pevq4I3N9VkpxV2z+6BpJyl8", + "x3IhS2ei8Knq8vIaIZN2vkLlgxXS/ulFL5Y+uhLpK9PIBtke3CVZacQc9jdutmXW4s0+vt9SWpE9dL/v", + "fCXCutZ+uKMqTzgUTtzwzYUvGiTjT8mxu2Bhu3aciVzYtj+Tlu+9fHZ4eNhf797sx+5lWiTWB0wG4Bn/", + "xNfQXY56sbcaNocIJIasWZUgmfOspIYMzjJVKYR30GidQ6/WWofZyknYJvnjME+kxYaxi4zSGXTee3DM", + "RzsNtZZpO27ai7WNNUT8Ar9ukZl62Radpi0gK5nSLbyGj1fDyCctp8vyPL4ptOqiLoNT+Xfs4eSEJdKi", + "CPUK6onpubrPptw3esVE+wSbVCyrpqYZeEh2F35tjJg60R7UTe1A8MsaxtPwBPb88EXk94nIyJW4J1VY", + "PrQ98AnI+O03pjbmhKntOTT2Xhweupv8nGciJQXvey7E7bPrTJhZmxOeKjKY1sIlPlNkS4R5ItHfiI6C", + "duvM9wqjCdehc02N78AAQ7LoIj4dmpAnCRRIXqWtMb2e1l7RrSJs5QH9QtqNaGnCLVhi2QBbCX5ZfgUG", + "SQ3lvSVUx4Esc/GQvebJjE2cAsDkGCzJpHTOxiJ9yX438I+PV1cy5Za/ZL8HFAwcvt3fr67k2N2gvPAh", + "nVm1DU3AmEGupLJKigSDTgrQBp9jEq2MWTKBfbr6K8bZW27sADE2OD0hUYMd9PzNzg2U9a0NuQyVl1N8", + "eXAF07GH7ESrgjZFgbaE8CkvTHCyjEU6pr5V2KXO+7UBBR/+JgxVNrIzLtkzxmdONgaD0+3VAEj8tF9Z", + "A6CdoBBYywJPgAkh3h49zgR+5ftdW82Tm8hsToOnYCGxuN8he4MZUfXxTbhzLoEMn4HqZWtfkEeVQwam", + "2hkAbPpAu37FCm4MG//fGoqML/6dZ9mYao20plNZioWQ0d3kpK2nX2OB+2aAt8LBe8YLtH6xRS5I0CJh", + "47acG1Mf73AZ8NAD79zynPkjtsOiZsNsz32+wLZ8jtqoeSxnqUrKHKQbNXY6dkyNJSthPaY+Wo7mlM4r", + "y7Ju8ubvsP+M2zrBj0lk9ZlBJwHthyaPdp1FgtvRhnc3k7y+0AhTI4n4yXeQVJoZkCk7jOAjoDe0at2W", + "J/GK1WIsNPqIjcCxmdaQYH0gWoq7NYS0Q3bJbwC7eyeQkuUxB83GRDdjUqvYYpgWxvaVuJwTSLy0aqDB", + "k3G9XAZcYvNEJCR6Ch7QlA5DM2Gw5HFdbZsiDGoztMUEuyWeniHh70LwQ3ZeXzFZ4uQJt+zZ4fMXr3BA", + "Rcy8IQkwdajUE54AFZKeCG0sMfsUs461lzLDzqLiBJF4OF2W3a8u+AMCErfS52+3UEZ/uCzYFaOYG3aB", + "MVWDC8ePXgK40f9fAAAA///bVimUi8YBAA==", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/server/openapi.yaml b/server/openapi.yaml index fb1c467b..2f900264 100644 --- a/server/openapi.yaml +++ b/server/openapi.yaml @@ -1382,11 +1382,11 @@ paths: get: summary: Read archived telemetry events from durable storage description: > - Reads telemetry event envelopes for the current session from durable S2 + Reads telemetry event envelopes for this browser from durable S2 storage, so events remain available after they age out of the live SSE - ring buffer. Results are scoped to the current session and returned in - ascending sequence order within the requested time window. Returns an - empty list when durable storage is not configured. + ring buffer. Results are returned in ascending sequence order within the + requested time window. Returns an empty list when durable storage is not + configured. operationId: readTelemetryEvents parameters: - in: query @@ -1406,7 +1406,7 @@ paths: - in: query name: limit required: false - description: Maximum number of events to return. + description: Maximum number of events to return. The most recent events within the window are kept. schema: type: integer minimum: 1 From ebd8a1766d308ee65354946623718d1c475d7130 Mon Sep 17 00:00:00 2001 From: archandatta <35818003+archandatta@users.noreply.github.com> Date: Thu, 11 Jun 2026 14:13:04 +0000 Subject: [PATCH 07/10] refactor: inject S2 reader into ApiService instead of raw config Co-Authored-By: Claude Opus 4.7 --- server/cmd/api/api/api.go | 17 +++++------------ server/cmd/api/api/api_test.go | 2 +- server/cmd/api/api/display_test.go | 2 +- server/cmd/api/api/events.go | 2 +- server/cmd/api/api/telemetry_test.go | 2 +- server/cmd/api/main.go | 4 +--- server/lib/events/s2storage.go | 26 +++++++++++++++++++------- 7 files changed, 29 insertions(+), 26 deletions(-) diff --git a/server/cmd/api/api/api.go b/server/cmd/api/api/api.go index cf7764f3..5360c9e8 100644 --- a/server/cmd/api/api/api.go +++ b/server/cmd/api/api/api.go @@ -93,16 +93,13 @@ type ApiService struct { lifecycleCtx context.Context lifecycleCancel context.CancelFunc - // Durable S2 telemetry storage. All three must be set for reads to hit S2; - // they mirror the values that gate the S2 storage writer. - s2Basin string - s2AccessToken string - s2Stream string + // Reader for durable S2 telemetry storage. Nil when S2 is not configured. + telemetryReader *events.S2Reader } // s2Enabled reports whether durable S2 telemetry storage is configured. func (s *ApiService) s2Enabled() bool { - return s.s2Basin != "" && s.s2AccessToken != "" && s.s2Stream != "" + return s.telemetryReader != nil } var _ oapi.StrictServerInterface = (*ApiService)(nil) @@ -116,9 +113,7 @@ func New( telemetrySession *telemetry.TelemetrySession, eventStream *events.EventStream, displayNum int, - s2Basin string, - s2AccessToken string, - s2Stream string, + telemetryReader *events.S2Reader, ) (*ApiService, error) { switch { case recordManager == nil: @@ -154,9 +149,7 @@ func New( cdpMonitor: mon, lifecycleCtx: ctx, lifecycleCancel: cancel, - s2Basin: s2Basin, - s2AccessToken: s2AccessToken, - s2Stream: s2Stream, + telemetryReader: telemetryReader, }, nil } diff --git a/server/cmd/api/api/api_test.go b/server/cmd/api/api/api_test.go index 4d1a3b4d..42c00717 100644 --- a/server/cmd/api/api/api_test.go +++ b/server/cmd/api/api/api_test.go @@ -321,7 +321,7 @@ func newTelemetrySession(t *testing.T) (*telemetry.TelemetrySession, *events.Eve func newSvc(t *testing.T, mgr recorder.RecordManager) (*ApiService, error) { t.Helper() ts, es := newTelemetrySession(t) - return New(mgr, newMockFactory(), newTestUpstreamManager(), scaletozero.NewNoopController(), newMockNekoClient(t), ts, es, 0, "", "", "") + return New(mgr, newMockFactory(), newTestUpstreamManager(), scaletozero.NewNoopController(), newMockNekoClient(t), ts, es, 0, nil) } func TestApiService_PatchChromiumFlags(t *testing.T) { diff --git a/server/cmd/api/api/display_test.go b/server/cmd/api/api/display_test.go index 175b22ad..c37700c3 100644 --- a/server/cmd/api/api/display_test.go +++ b/server/cmd/api/api/display_test.go @@ -36,7 +36,7 @@ func testFFmpegFactory(t *testing.T, tempDir string) recorder.FFmpegRecorderFact func newTestServiceWithFactory(t *testing.T, mgr recorder.RecordManager, factory recorder.FFmpegRecorderFactory) *ApiService { t.Helper() ts, es := newTelemetrySession(t) - svc, err := New(mgr, factory, newTestUpstreamManager(), scaletozero.NewNoopController(), newMockNekoClient(t), ts, es, 0, "", "", "") + svc, err := New(mgr, factory, newTestUpstreamManager(), scaletozero.NewNoopController(), newMockNekoClient(t), ts, es, 0, nil) require.NoError(t, err) return svc } diff --git a/server/cmd/api/api/events.go b/server/cmd/api/api/events.go index d9c5e99b..5677401f 100644 --- a/server/cmd/api/api/events.go +++ b/server/cmd/api/api/events.go @@ -154,7 +154,7 @@ func (s *ApiService) ReadTelemetryEvents(ctx context.Context, req oapi.ReadTelem return readTelemetryEventsOKResponse{}, nil } - envs, err := events.Read(ctx, s.s2Basin, s.s2AccessToken, s.s2Stream, buildReadOptions(req.Params), log) + envs, err := s.telemetryReader.Read(ctx, buildReadOptions(req.Params), log) if err != nil { log.Error("failed to read telemetry events from S2", "err", err) return oapi.ReadTelemetryEvents500JSONResponse{InternalErrorJSONResponse: oapi.InternalErrorJSONResponse{Message: "failed to read telemetry events"}}, nil diff --git a/server/cmd/api/api/telemetry_test.go b/server/cmd/api/api/telemetry_test.go index 27cb595c..7b6a0b52 100644 --- a/server/cmd/api/api/telemetry_test.go +++ b/server/cmd/api/api/telemetry_test.go @@ -358,7 +358,7 @@ func (m *mockRecordManager) StopAll(_ context.Context) error func newTestService(t *testing.T, mgr recorder.RecordManager) *ApiService { t.Helper() ts, es := newTelemetrySession(t) - svc, err := New(mgr, newMockFactory(), newTestUpstreamManager(), scaletozero.NewNoopController(), newMockNekoClient(t), ts, es, 0, "", "", "") + svc, err := New(mgr, newMockFactory(), newTestUpstreamManager(), scaletozero.NewNoopController(), newMockNekoClient(t), ts, es, 0, nil) require.NoError(t, err) svc.cdpMonitor = &stubCdpMonitor{} return svc diff --git a/server/cmd/api/main.go b/server/cmd/api/main.go index 78f79524..822fcf12 100644 --- a/server/cmd/api/main.go +++ b/server/cmd/api/main.go @@ -137,9 +137,7 @@ func main() { telemetrySession, eventStream, config.DisplayNum, - config.S2Basin, - config.S2AccessToken, - config.S2Stream, + events.NewS2Reader(config.S2Basin, config.S2AccessToken, config.S2Stream), ) if err != nil { slogger.Error("failed to create api service", "err", err) diff --git a/server/lib/events/s2storage.go b/server/lib/events/s2storage.go index 94c8d111..938bbeed 100644 --- a/server/lib/events/s2storage.go +++ b/server/lib/events/s2storage.go @@ -236,13 +236,25 @@ type ReadOptions struct { Until *uint64 } -// Read returns every telemetry envelope in the bounded range from streamName. -// It opens a fresh client per call and surfaces S2 errors to the caller. -func Read(ctx context.Context, basin, accessToken, streamName string, opts ReadOptions, log *slog.Logger) ([]Envelope, error) { +// S2Reader reads archived telemetry envelopes from a single S2 stream. +type S2Reader struct { + basin string + accessToken string + streamName string +} + +// NewS2Reader returns a reader for streamName, or nil when any connection value +// is empty (durable storage not configured). +func NewS2Reader(basin, accessToken, streamName string) *S2Reader { if basin == "" || accessToken == "" || streamName == "" { - return nil, fmt.Errorf("s2storage: basin, accessToken, and streamName are required") + return nil } + return &S2Reader{basin: basin, accessToken: accessToken, streamName: streamName} +} +// Read returns every telemetry envelope in the bounded range. It opens a fresh +// client per call and surfaces S2 errors to the caller. +func (r *S2Reader) Read(ctx context.Context, opts ReadOptions, log *slog.Logger) ([]Envelope, error) { readOpts := &s2.ReadOptions{ Clamp: s2.Bool(true), IgnoreCommandRecords: true, @@ -256,8 +268,8 @@ func Read(ctx context.Context, basin, accessToken, streamName string, opts ReadO readOpts.Until = s2.Uint64(uint64(time.Now().UnixMilli())) } - client := s2.New(accessToken, nil) - stream := client.Basin(basin).Stream(s2.StreamName(streamName)) + client := s2.New(r.accessToken, nil) + stream := client.Basin(r.basin).Stream(s2.StreamName(r.streamName)) session, err := stream.ReadSession(ctx, readOpts) if err != nil { @@ -278,6 +290,6 @@ func Read(ctx context.Context, basin, accessToken, streamName string, opts ReadO return nil, fmt.Errorf("s2storage: read session: %w", err) } - log.DebugContext(ctx, "s2storage: read complete", "stream", streamName, "records", len(envelopes)) + log.DebugContext(ctx, "s2storage: read complete", "stream", r.streamName, "records", len(envelopes)) return envelopes, nil } From d7a70b183c0d65ffea48833ff108ddadad7fd036 Mon Sep 17 00:00:00 2001 From: archandatta <35818003+archandatta@users.noreply.github.com> Date: Thu, 11 Jun 2026 15:52:47 +0000 Subject: [PATCH 08/10] feat: paginate telemetry events with an S2 sequence cursor Co-Authored-By: Claude Opus 4.7 --- server/cmd/api/api/events.go | 101 ++-- server/cmd/api/api/events_test.go | 43 +- server/lib/events/s2storage.go | 31 +- server/lib/oapi/oapi.go | 790 ++++++++++++++++-------------- server/openapi.yaml | 53 +- 5 files changed, 564 insertions(+), 454 deletions(-) diff --git a/server/cmd/api/api/events.go b/server/cmd/api/api/events.go index 5677401f..16f1a7fd 100644 --- a/server/cmd/api/api/events.go +++ b/server/cmd/api/api/events.go @@ -137,16 +137,19 @@ func (s *ApiService) StreamTelemetryEvents(ctx context.Context, req oapi.StreamT return oapi.StreamTelemetryEvents200TexteventStreamResponse{Body: pr, Headers: headers}, nil } -// defaultReadWindow bounds a read that supplies no since/until. -const defaultReadWindow = 5 * time.Minute - -// maxReadLimit caps the number of envelopes a single read returns. -const maxReadLimit = 1000 +const ( + // defaultReadWindow bounds a read that supplies no since/until. + defaultReadWindow = 5 * time.Minute + // defaultPageSize / maxPageSize bound how many records one page reads. + defaultPageSize = 100 + maxPageSize = 1000 +) // ReadTelemetryEvents handles GET /telemetry/events. -// Reads archived telemetry envelopes for this browser from durable S2 storage, -// applies category and limit filters, and returns them in ascending sequence -// order. Returns an empty list when S2 storage is not configured. +// Reads one page of archived telemetry envelopes for this browser from durable +// S2 storage in ascending sequence order, applying the category filter. The +// X-Has-More / X-Next-Offset response headers carry the pagination cursor. +// Returns an empty list when S2 storage is not configured. func (s *ApiService) ReadTelemetryEvents(ctx context.Context, req oapi.ReadTelemetryEventsRequestObject) (oapi.ReadTelemetryEventsResponseObject, error) { log := logger.FromContext(ctx) @@ -154,37 +157,62 @@ func (s *ApiService) ReadTelemetryEvents(ctx context.Context, req oapi.ReadTelem return readTelemetryEventsOKResponse{}, nil } - envs, err := s.telemetryReader.Read(ctx, buildReadOptions(req.Params), log) + result, err := s.telemetryReader.Read(ctx, buildReadOptions(req.Params), log) if err != nil { log.Error("failed to read telemetry events from S2", "err", err) return oapi.ReadTelemetryEvents500JSONResponse{InternalErrorJSONResponse: oapi.InternalErrorJSONResponse{Message: "failed to read telemetry events"}}, nil } - envs = filterByCategory(envs, req.Params.Category) - envs = capLimit(envs, req.Params.Limit) + // has_more / next cursor track the raw stream position, independent of the + // category filter, so a filtered page may come back empty while more remain. + envs := filterByCategory(result.Envelopes, req.Params.Category) - return readTelemetryEventsOKResponse{envs: envs}, nil + return readTelemetryEventsOKResponse{envs: envs, nextSeqNum: result.NextSeqNum, hasMore: result.HasMore}, nil } -// buildReadOptions maps query params to a bounded read window. since/until are -// the start/end of the window; the window defaults to the last defaultReadWindow. -// limit is applied after category filtering, not pushed into the S2 read. +// buildReadOptions maps query params to a bounded, paginated read. offset is the +// S2 sequence cursor and takes precedence over since as the start position (the +// two are mutually exclusive starts); until bounds the window end; the page is +// bounded to limit records. func buildReadOptions(p oapi.ReadTelemetryEventsParams) events.ReadOptions { var opts events.ReadOptions - if p.Since != nil { - start := uint64(*p.Since) - opts.Timestamp = &start - } else { - start := uint64(time.Now().Add(-defaultReadWindow).UnixMilli()) - opts.Timestamp = &start + + switch { + case p.Offset != nil && *p.Offset >= 0: + seq := uint64(*p.Offset) + opts.SeqNum = &seq + case p.Since != nil: + ts := uint64(*p.Since) + opts.Timestamp = &ts + default: + ts := uint64(time.Now().Add(-defaultReadWindow).UnixMilli()) + opts.Timestamp = &ts } + if p.Until != nil { until := uint64(*p.Until) opts.Until = &until } + + count := uint64(pageSize(p.Limit)) + opts.Count = &count return opts } +// pageSize clamps a requested limit into [1, maxPageSize], defaulting when unset. +func pageSize(limit *int) int { + switch { + case limit == nil: + return defaultPageSize + case *limit < 1: + return 1 + case *limit > maxPageSize: + return maxPageSize + default: + return *limit + } +} + func filterByCategory(envs []events.Envelope, cats *[]oapi.TelemetryEventCategory) []events.Envelope { if cats == nil || len(*cats) == 0 { return envs @@ -202,33 +230,28 @@ func filterByCategory(envs []events.Envelope, cats *[]oapi.TelemetryEventCategor return out } -// capLimit returns at most n envelopes, keeping the most recent when the set -// exceeds the limit. Order is preserved (ascending sequence). -func capLimit(envs []events.Envelope, limit *int) []events.Envelope { - n := maxReadLimit - if limit != nil && *limit > 0 && *limit < n { - n = *limit - } - if len(envs) > n { - return envs[len(envs)-n:] - } - return envs +// readTelemetryEventsOKResponse serializes a page of events.Envelope directly, +// matching the SSE stream and publish endpoints. The pagination cursor rides in +// the X-Has-More / X-Next-Offset headers (X-Next-Offset only when there is more), +// following the offset_pagination convention used by the list endpoints. +type readTelemetryEventsOKResponse struct { + envs []events.Envelope + nextSeqNum uint64 + hasMore bool } -// readTelemetryEventsOKResponse serializes events.Envelope directly so the -// response shape matches the SSE stream frames and the publish endpoint. -type readTelemetryEventsOKResponse struct{ envs []events.Envelope } - func (r readTelemetryEventsOKResponse) VisitReadTelemetryEventsResponse(w http.ResponseWriter) error { + w.Header().Set("X-Has-More", strconv.FormatBool(r.hasMore)) + if r.hasMore { + w.Header().Set("X-Next-Offset", strconv.FormatUint(r.nextSeqNum, 10)) + } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) envs := r.envs if envs == nil { envs = []events.Envelope{} } - return json.NewEncoder(w).Encode(struct { - Events []events.Envelope `json:"events"` - }{Events: envs}) + return json.NewEncoder(w).Encode(envs) } // publishTelemetryEventOKResponse serializes events.Envelope directly so the response diff --git a/server/cmd/api/api/events_test.go b/server/cmd/api/api/events_test.go index a424f19d..90f0a939 100644 --- a/server/cmd/api/api/events_test.go +++ b/server/cmd/api/api/events_test.go @@ -312,7 +312,9 @@ func TestReadTelemetryEventsS2Disabled(t *testing.T) { require.NoError(t, ok.VisitReadTelemetryEventsResponse(rec)) assert.Equal(t, http.StatusOK, rec.Code) // Empty result must serialize as [] not null, or the Python SDK chokes. - assert.JSONEq(t, `{"events":[]}`, rec.Body.String()) + assert.JSONEq(t, `[]`, rec.Body.String()) + assert.Equal(t, "false", rec.Header().Get("X-Has-More")) + assert.Empty(t, rec.Header().Get("X-Next-Offset"), "no cursor when there is no more") } func TestFilterByCategory(t *testing.T) { @@ -328,31 +330,42 @@ func TestFilterByCategory(t *testing.T) { assert.Len(t, filterByCategory(envs, &cats), 2) } -func TestCapLimit(t *testing.T) { +func TestPageSize(t *testing.T) { t.Parallel() - envs := []events.Envelope{{Seq: 1}, {Seq: 2}, {Seq: 3}, {Seq: 4}, {Seq: 5}} + assert.Equal(t, defaultPageSize, pageSize(nil), "unset defaults") - assert.Len(t, capLimit(envs, nil), 5, "no limit returns all under the ceiling") - - three := 3 - got := capLimit(envs, &three) - require.Len(t, got, 3) - // The most recent events are kept, in ascending order. - assert.Equal(t, uint64(3), got[0].Seq) - assert.Equal(t, uint64(5), got[2].Seq) + ptr := func(n int) *int { return &n } + assert.Equal(t, 50, pageSize(ptr(50))) + assert.Equal(t, 1, pageSize(ptr(0)), "clamped up to 1") + assert.Equal(t, 1, pageSize(ptr(-5)), "clamped up to 1") + assert.Equal(t, maxPageSize, pageSize(ptr(5000)), "clamped down to max") } func TestBuildReadOptions(t *testing.T) { t.Parallel() - // No params: defaults the start to roughly defaultReadWindow ago, no end bound. + + // No params: defaults the start to ~defaultReadWindow ago, no end bound, default page. opts := buildReadOptions(oapi.ReadTelemetryEventsParams{}) require.NotNil(t, opts.Timestamp) + assert.Nil(t, opts.SeqNum) assert.Nil(t, opts.Until) + require.NotNil(t, opts.Count) + assert.Equal(t, uint64(defaultPageSize), *opts.Count) - since, until := int64(1000), int64(2000) - opts = buildReadOptions(oapi.ReadTelemetryEventsParams{Since: &since, Until: &until}) + // since/until/limit map through; limit bounds the page. + since, until, limit := int64(1000), int64(2000), 25 + opts = buildReadOptions(oapi.ReadTelemetryEventsParams{Since: &since, Until: &until, Limit: &limit}) require.NotNil(t, opts.Timestamp) - require.NotNil(t, opts.Until) assert.Equal(t, uint64(1000), *opts.Timestamp) + require.NotNil(t, opts.Until) assert.Equal(t, uint64(2000), *opts.Until) + require.NotNil(t, opts.Count) + assert.Equal(t, uint64(25), *opts.Count) + + // offset is the cursor and takes precedence over since (SeqNum start, no Timestamp). + offset := int64(4213) + opts = buildReadOptions(oapi.ReadTelemetryEventsParams{Offset: &offset, Since: &since}) + require.NotNil(t, opts.SeqNum) + assert.Equal(t, uint64(4213), *opts.SeqNum) + assert.Nil(t, opts.Timestamp, "since is ignored when offset is set") } diff --git a/server/lib/events/s2storage.go b/server/lib/events/s2storage.go index 938bbeed..07caa39d 100644 --- a/server/lib/events/s2storage.go +++ b/server/lib/events/s2storage.go @@ -252,9 +252,17 @@ func NewS2Reader(basin, accessToken, streamName string) *S2Reader { return &S2Reader{basin: basin, accessToken: accessToken, streamName: streamName} } -// Read returns every telemetry envelope in the bounded range. It opens a fresh -// client per call and surfaces S2 errors to the caller. -func (r *S2Reader) Read(ctx context.Context, opts ReadOptions, log *slog.Logger) ([]Envelope, error) { +// S2ReadResult is one page of a paginated read. NextSeqNum is the S2 sequence +// number to resume from on the next page; it is meaningful only when HasMore. +type S2ReadResult struct { + Envelopes []Envelope + NextSeqNum uint64 + HasMore bool +} + +// Read returns one page of telemetry envelopes from the bounded range. It opens +// a fresh client per call and surfaces S2 errors to the caller. +func (r *S2Reader) Read(ctx context.Context, opts ReadOptions, log *slog.Logger) (*S2ReadResult, error) { readOpts := &s2.ReadOptions{ Clamp: s2.Bool(true), IgnoreCommandRecords: true, @@ -290,6 +298,19 @@ func (r *S2Reader) Read(ctx context.Context, opts ReadOptions, log *slog.Logger) return nil, fmt.Errorf("s2storage: read session: %w", err) } - log.DebugContext(ctx, "s2storage: read complete", "stream", r.streamName, "records", len(envelopes)) - return envelopes, nil + // Both positions ride along in the read batches, so there's no extra + // round-trip. More records remain whenever the resume position hasn't caught + // up to the stream tail. This holds regardless of whether the page stopped on + // the count, byte, or time bound, so it never under-reports as a "full page" + // heuristic would. + result := &S2ReadResult{Envelopes: envelopes} + next := session.NextReadPosition() + tail := session.LastObservedTail() + if next != nil && tail != nil && next.SeqNum < tail.SeqNum { + result.NextSeqNum = next.SeqNum + result.HasMore = true + } + + log.DebugContext(ctx, "s2storage: read complete", "stream", r.streamName, "records", len(envelopes), "has_more", result.HasMore) + return result, nil } diff --git a/server/lib/oapi/oapi.go b/server/lib/oapi/oapi.go index 6a83bef5..f0db145d 100644 --- a/server/lib/oapi/oapi.go +++ b/server/lib/oapi/oapi.go @@ -3852,13 +3852,16 @@ type DownloadRecordingParams struct { // ReadTelemetryEventsParams defines parameters for ReadTelemetryEvents. type ReadTelemetryEventsParams struct { - // Since Start of the time window, unix milliseconds. Defaults to 5 minutes ago. + // Offset Pagination cursor: pass the `X-Next-Offset` value from the previous response to fetch the next page. This is a stream position and takes precedence over `since`; it is not an event's `seq` field — do not derive it from the response body. + Offset *int64 `form:"offset,omitempty" json:"offset,omitempty"` + + // Since Start of the time window, unix milliseconds. Defaults to 5 minutes ago. Ignored when `offset` is set. Since *int64 `form:"since,omitempty" json:"since,omitempty"` - // Until End of the time window (exclusive), unix milliseconds. Defaults to the current time. + // Until End of the time window (exclusive), unix milliseconds. Until *int64 `form:"until,omitempty" json:"until,omitempty"` - // Limit Maximum number of events to return. The most recent events within the window are kept. + // Limit Maximum number of events per page. Defaults to 100. Limit *int `form:"limit,omitempty" json:"limit,omitempty"` // Category Restrict results to these event categories. Repeat the parameter for multiple values. @@ -8394,6 +8397,22 @@ func NewReadTelemetryEventsRequest(server string, params *ReadTelemetryEventsPar if params != nil { queryValues := queryURL.Query() + if params.Offset != nil { + + if queryFrag, err := runtime.StyleParamWithOptions("form", true, "offset", *params.Offset, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "integer", Format: "int64"}); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + if params.Since != nil { if queryFrag, err := runtime.StyleParamWithOptions("form", true, "since", *params.Since, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "integer", Format: "int64"}); err != nil { @@ -10112,10 +10131,8 @@ func (r PutTelemetryResponse) StatusCode() int { type ReadTelemetryEventsResponse struct { Body []byte HTTPResponse *http.Response - JSON200 *struct { - Events []TelemetryEnvelope `json:"events"` - } - JSON500 *InternalError + JSON200 *[]TelemetryEnvelope + JSON500 *InternalError } // Status returns HTTPResponse.Status @@ -12974,9 +12991,7 @@ func ParseReadTelemetryEventsResponse(rsp *http.Response) (*ReadTelemetryEventsR switch { case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: - var dest struct { - Events []TelemetryEnvelope `json:"events"` - } + var dest []TelemetryEnvelope if err := json.Unmarshal(bodyBytes, &dest); err != nil { return nil, err } @@ -14584,6 +14599,14 @@ func (siw *ServerInterfaceWrapper) ReadTelemetryEvents(w http.ResponseWriter, r // Parameter object where we will unmarshal all parameters from the context var params ReadTelemetryEventsParams + // ------------- Optional query parameter "offset" ------------- + + err = runtime.BindQueryParameterWithOptions("form", true, false, "offset", r.URL.Query(), ¶ms.Offset, runtime.BindQueryParameterOptions{Type: "integer", Format: "int64"}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "offset", Err: err}) + return + } + // ------------- Optional query parameter "since" ------------- err = runtime.BindQueryParameterWithOptions("form", true, false, "since", r.URL.Query(), ¶ms.Since, runtime.BindQueryParameterOptions{Type: "integer", Format: "int64"}) @@ -17201,15 +17224,23 @@ type ReadTelemetryEventsResponseObject interface { VisitReadTelemetryEventsResponse(w http.ResponseWriter) error } +type ReadTelemetryEvents200ResponseHeaders struct { + XHasMore bool + XNextOffset int64 +} + type ReadTelemetryEvents200JSONResponse struct { - Events []TelemetryEnvelope `json:"events"` + Body []TelemetryEnvelope + Headers ReadTelemetryEvents200ResponseHeaders } func (response ReadTelemetryEvents200JSONResponse) VisitReadTelemetryEventsResponse(w http.ResponseWriter) error { w.Header().Set("Content-Type", "application/json") + w.Header().Set("X-Has-More", fmt.Sprint(response.Headers.XHasMore)) + w.Header().Set("X-Next-Offset", fmt.Sprint(response.Headers.XNextOffset)) w.WriteHeader(200) - return json.NewEncoder(w).Encode(response) + return json.NewEncoder(w).Encode(response.Body) } type ReadTelemetryEvents500JSONResponse struct{ InternalErrorJSONResponse } @@ -19163,372 +19194,375 @@ func (sh *strictHandler) StreamTelemetryEvents(w http.ResponseWriter, r *http.Re // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", - "MVWDC8ePXgK40f9fAAAA///bVimUi8YBAA==", + "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", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/server/openapi.yaml b/server/openapi.yaml index 2f900264..301a987d 100644 --- a/server/openapi.yaml +++ b/server/openapi.yaml @@ -1382,35 +1382,49 @@ paths: get: summary: Read archived telemetry events from durable storage description: > - Reads telemetry event envelopes for this browser from durable S2 - storage, so events remain available after they age out of the live SSE - ring buffer. Results are returned in ascending sequence order within the - requested time window. Returns an empty list when durable storage is not - configured. + Reads a page of telemetry event envelopes for this browser from durable + S2 storage, so events remain available after they age out of the live + SSE ring buffer. Events are returned in ascending sequence order. To page + through results, pass the `X-Next-Offset` value from the previous + response as `offset` and repeat while `X-Has-More` is true. Returns an + empty list when durable storage is not configured. operationId: readTelemetryEvents parameters: + - in: query + name: offset + required: false + description: > + Pagination cursor: pass the `X-Next-Offset` value from the previous + response to fetch the next page. This is a stream position and takes + precedence over `since`; it is not an event's `seq` field — do not + derive it from the response body. + schema: + type: integer + format: int64 + minimum: 0 - in: query name: since required: false - description: Start of the time window, unix milliseconds. Defaults to 5 minutes ago. + description: Start of the time window, unix milliseconds. Defaults to 5 minutes ago. Ignored when `offset` is set. schema: type: integer format: int64 - in: query name: until required: false - description: End of the time window (exclusive), unix milliseconds. Defaults to the current time. + description: End of the time window (exclusive), unix milliseconds. schema: type: integer format: int64 - in: query name: limit required: false - description: Maximum number of events to return. The most recent events within the window are kept. + description: Maximum number of events per page. Defaults to 100. schema: type: integer minimum: 1 maximum: 1000 + default: 100 - in: query name: category required: false @@ -1423,18 +1437,23 @@ paths: explode: true responses: "200": - description: Telemetry events from durable storage in ascending sequence order. + description: A page of telemetry events from durable storage in ascending sequence order. + headers: + X-Has-More: + description: Whether more events are available beyond this page. + schema: + type: boolean + X-Next-Offset: + description: Cursor to pass as `offset` for the next page. Present only when X-Has-More is true. + schema: + type: integer + format: int64 content: application/json: schema: - type: object - required: - - events - properties: - events: - type: array - items: - $ref: "#/components/schemas/TelemetryEnvelope" + type: array + items: + $ref: "#/components/schemas/TelemetryEnvelope" "500": $ref: "#/components/responses/InternalError" /telemetry/stream: From 97ff47e54adac236a2eeac6a25acd141223a527b Mon Sep 17 00:00:00 2001 From: archandatta <35818003+archandatta@users.noreply.github.com> Date: Thu, 11 Jun 2026 16:03:03 +0000 Subject: [PATCH 09/10] test: cover telemetry events pagination end-to-end Co-Authored-By: Claude Opus 4.7 --- server/e2e/e2e_telemetry_events_read_test.go | 133 +++++++++++++------ 1 file changed, 95 insertions(+), 38 deletions(-) diff --git a/server/e2e/e2e_telemetry_events_read_test.go b/server/e2e/e2e_telemetry_events_read_test.go index a6fd4d40..545e592b 100644 --- a/server/e2e/e2e_telemetry_events_read_test.go +++ b/server/e2e/e2e_telemetry_events_read_test.go @@ -2,9 +2,11 @@ package e2e import ( "context" + "fmt" "net/http" "os" "os/exec" + "strconv" "testing" "time" @@ -14,47 +16,52 @@ import ( instanceoapi "github.com/kernel/kernel-images/server/lib/oapi" ) -// TestReadTelemetryEvents starts a headless container with S2 credentials, -// publishes a known set of events, and reads them back through -// GET /telemetry/events. It exercises the full archive read path against a real -// S2 stream rather than the in-memory ring buffer. -// -// Skips automatically when S2_BASIN, S2_ACCESS_TOKEN, or S2_STREAM are unset. -func TestReadTelemetryEvents(t *testing.T) { +// startTelemetryReadContainer boots a headless container wired to S2 on a +// per-test stream (so tests sharing the S2_STREAM env don't pollute each other) +// and starts a telemetry session. Skips when S2 creds or docker are absent. +func startTelemetryReadContainer(t *testing.T, ctx context.Context) *instanceoapi.ClientWithResponses { + t.Helper() basin := os.Getenv("S2_BASIN") accessToken := os.Getenv("S2_ACCESS_TOKEN") stream := os.Getenv("S2_STREAM") if basin == "" || accessToken == "" || stream == "" { t.Skip("S2_BASIN, S2_ACCESS_TOKEN, and S2_STREAM must be set to run this test") } - if _, err := exec.LookPath("docker"); err != nil { t.Skipf("docker not available: %v", err) } - ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute) - defer cancel() - c := NewTestContainer(t, headlessImage) require.NoError(t, c.Start(ctx, ContainerConfig{ Env: map[string]string{ "S2_BASIN": basin, "S2_ACCESS_TOKEN": accessToken, - "S2_STREAM": stream, + "S2_STREAM": fmt.Sprintf("%s-%s", stream, t.Name()), }, }), "failed to start container") - defer c.Stop(ctx) + t.Cleanup(func() { c.Stop(context.Background()) }) require.NoError(t, c.WaitReady(ctx), "api not ready") client, err := c.APIClient() require.NoError(t, err) - // Start a telemetry session. The default config enables the system and - // connection categories, which is what we publish into below. startResp, err := client.PutTelemetryWithResponse(ctx, instanceoapi.PutTelemetryJSONRequestBody{}) require.NoError(t, err) require.Equal(t, http.StatusCreated, startResp.StatusCode(), "put telemetry: %s", string(startResp.Body)) + return client +} + +// TestReadTelemetryEvents publishes a known set of events and reads them back +// through GET /telemetry/events against a real S2 stream, exercising the full +// archive read path rather than the in-memory ring buffer. +// +// Skips automatically when S2_BASIN, S2_ACCESS_TOKEN, or S2_STREAM are unset. +func TestReadTelemetryEvents(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute) + defer cancel() + + client := startTelemetryReadContainer(t, ctx) // Publish a deterministic set of events across two enabled categories. const systemCount, connectionCount = 3, 2 @@ -68,44 +75,94 @@ func TestReadTelemetryEvents(t *testing.T) { // Give the storage writer time to flush to S2 (batcher linger + network). time.Sleep(2 * time.Second) - // Bound every read tightly: a correct handler caps the S2 read at the tail, - // so these return promptly. A hang here means the read is unbounded. + // Bound every read tightly: a correct handler caps the S2 read, so these + // return promptly. A hang here means the read is unbounded. readCtx, readCancel := context.WithTimeout(ctx, 10*time.Second) defer readCancel() // Full read returns at least everything we published. - all, err := client.ReadTelemetryEventsWithResponse(readCtx, &instanceoapi.ReadTelemetryEventsParams{}) - require.NoError(t, err) - require.Equal(t, http.StatusOK, all.StatusCode(), "read events: %s", string(all.Body)) - require.NotNil(t, all.JSON200) - assert.GreaterOrEqual(t, len(all.JSON200.Events), systemCount+connectionCount) + all, _, _ := readEventsPage(t, readCtx, client, &instanceoapi.ReadTelemetryEventsParams{}) + assert.GreaterOrEqual(t, len(all), systemCount+connectionCount) // Category filter returns only the requested category. systemCat := []instanceoapi.TelemetryEventCategory{instanceoapi.TelemetryEventCategorySystem} - systemOnly, err := client.ReadTelemetryEventsWithResponse(readCtx, &instanceoapi.ReadTelemetryEventsParams{Category: &systemCat}) - require.NoError(t, err) - require.Equal(t, http.StatusOK, systemOnly.StatusCode()) - require.NotNil(t, systemOnly.JSON200) - assert.GreaterOrEqual(t, len(systemOnly.JSON200.Events), systemCount) - for _, e := range systemOnly.JSON200.Events { + systemOnly, _, _ := readEventsPage(t, readCtx, client, &instanceoapi.ReadTelemetryEventsParams{Category: &systemCat}) + assert.GreaterOrEqual(t, len(systemOnly), systemCount) + for _, e := range systemOnly { require.NotNil(t, e.Event.Category) assert.Equal(t, instanceoapi.TelemetryEventCategorySystem, *e.Event.Category) } - // Limit caps the number of returned events. - limit := 1 - limited, err := client.ReadTelemetryEventsWithResponse(readCtx, &instanceoapi.ReadTelemetryEventsParams{Limit: &limit}) - require.NoError(t, err) - require.NotNil(t, limited.JSON200) - assert.Len(t, limited.JSON200.Events, 1) - - // An empty window returns [] not null, or the Python SDK chokes deserializing. + // An empty window returns [] (not null) with no cursor. pastSince, pastUntil := int64(1), int64(2) empty, err := client.ReadTelemetryEventsWithResponse(readCtx, &instanceoapi.ReadTelemetryEventsParams{Since: &pastSince, Until: &pastUntil}) require.NoError(t, err) require.NotNil(t, empty.JSON200) - assert.Empty(t, empty.JSON200.Events) - assert.Contains(t, string(empty.Body), `"events":[]`) + assert.Empty(t, *empty.JSON200) + assert.JSONEq(t, `[]`, string(empty.Body), "empty result must be [] not null") + assert.Equal(t, "false", empty.HTTPResponse.Header.Get("X-Has-More")) +} + +// TestReadTelemetryEventsPagination publishes more events than the page size and +// walks every page via the X-Next-Offset cursor, asserting the full set comes +// back exactly once in ascending order. +func TestReadTelemetryEventsPagination(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute) + defer cancel() + + client := startTelemetryReadContainer(t, ctx) + + const published = 5 + for i := 0; i < published; i++ { + publishEvent(t, ctx, client, "test.system", instanceoapi.PublishEventRequestCategorySystem) + } + time.Sleep(2 * time.Second) + + readCtx, readCancel := context.WithTimeout(ctx, 20*time.Second) + defer readCancel() + + const pageLimit = 2 + var collected []instanceoapi.TelemetryEnvelope + var offset *int64 + pages := 0 + for { + pages++ + require.LessOrEqual(t, pages, 50, "pagination did not terminate") + limit := pageLimit + page, hasMore, next := readEventsPage(t, readCtx, client, &instanceoapi.ReadTelemetryEventsParams{Limit: &limit, Offset: offset}) + require.LessOrEqual(t, len(page), pageLimit, "a page must not exceed the limit") + collected = append(collected, page...) + if !hasMore { + break + } + offset = &next + } + + require.GreaterOrEqual(t, pages, 3, "5 events at limit 2 should span multiple pages") + require.GreaterOrEqual(t, len(collected), published) + // Strictly ascending seqs prove the cursor neither skips nor re-reads across + // page boundaries. + for i := 1; i < len(collected); i++ { + assert.Greater(t, collected[i].Seq, collected[i-1].Seq, "events must be strictly ascending with no dupes across pages") + } +} + +// readEventsPage calls the endpoint and returns the page plus its cursor state. +func readEventsPage(t *testing.T, ctx context.Context, client *instanceoapi.ClientWithResponses, params *instanceoapi.ReadTelemetryEventsParams) (page []instanceoapi.TelemetryEnvelope, hasMore bool, next int64) { + t.Helper() + resp, err := client.ReadTelemetryEventsWithResponse(ctx, params) + require.NoError(t, err) + require.Equal(t, http.StatusOK, resp.StatusCode(), "read events: %s", string(resp.Body)) + require.NotNil(t, resp.JSON200) + + hasMore = resp.HTTPResponse.Header.Get("X-Has-More") == "true" + if hasMore { + nextStr := resp.HTTPResponse.Header.Get("X-Next-Offset") + require.NotEmpty(t, nextStr, "X-Next-Offset must be set when X-Has-More is true") + next, err = strconv.ParseInt(nextStr, 10, 64) + require.NoError(t, err) + } + return *resp.JSON200, hasMore, next } func publishEvent(t *testing.T, ctx context.Context, client *instanceoapi.ClientWithResponses, eventType string, category instanceoapi.PublishEventRequestCategory) { From 48cdaf0d111d3844cdab9b167aa887fe7309a23e Mon Sep 17 00:00:00 2001 From: archandatta <35818003+archandatta@users.noreply.github.com> Date: Thu, 11 Jun 2026 16:29:10 +0000 Subject: [PATCH 10/10] fix: don't emit api_call events for telemetry read endpoints Reading telemetry emitted its own api_call event back into the stream, a feedback loop that prevents a paginated read from catching the tail. Co-Authored-By: Claude Opus 4.7 --- server/cmd/api/api/middleware.go | 12 ++++++++++++ server/e2e/e2e_telemetry_events_read_test.go | 7 +++++++ 2 files changed, 19 insertions(+) diff --git a/server/cmd/api/api/middleware.go b/server/cmd/api/api/middleware.go index a558199a..14508fde 100644 --- a/server/cmd/api/api/middleware.go +++ b/server/cmd/api/api/middleware.go @@ -35,6 +35,15 @@ func DisableTelemetryMiddleware() { telemetryMiddlewareEnabled.Store(false) } // TelemetryMiddlewareEnabled reports the current state. func TelemetryMiddlewareEnabled() bool { return telemetryMiddlewareEnabled.Load() } +// telemetryReadOps are the telemetry-observer endpoints that must not emit their +// own api_call event: doing so would append to the very stream they read, a +// feedback loop that (e.g. at page size 1) prevents a paginated read from ever +// catching the tail. +var telemetryReadOps = map[string]struct{}{ + "ReadTelemetryEvents": {}, + "StreamTelemetryEvents": {}, +} + // TelemetryHTTPMiddleware emits a BrowserApiCallEvent per documented operation, // capturing the final status and wall-clock duration. publish is wired to // TelemetrySession.Publish; the middleware ignores the returns. @@ -55,6 +64,9 @@ func TelemetryHTTPMiddleware(publish func(events.Event) (events.Envelope, bool)) if tc.operationID == "" { return } + if _, skip := telemetryReadOps[tc.operationID]; skip { + return + } data, _ := json.Marshal(oapi.BrowserApiCallEventData{ RequestId: chiMiddleware.GetReqID(ctx), OperationId: tc.operationID, diff --git a/server/e2e/e2e_telemetry_events_read_test.go b/server/e2e/e2e_telemetry_events_read_test.go index 545e592b..2aff7095 100644 --- a/server/e2e/e2e_telemetry_events_read_test.go +++ b/server/e2e/e2e_telemetry_events_read_test.go @@ -145,6 +145,13 @@ func TestReadTelemetryEventsPagination(t *testing.T) { for i := 1; i < len(collected); i++ { assert.Greater(t, collected[i].Seq, collected[i-1].Seq, "events must be strictly ascending with no dupes across pages") } + + // Reads must be side-effect-free: reading telemetry must not emit an api_call + // event back into the stream, or pagination could never catch the tail. Two + // full reads must return the same count. + first, _, _ := readEventsPage(t, readCtx, client, &instanceoapi.ReadTelemetryEventsParams{}) + second, _, _ := readEventsPage(t, readCtx, client, &instanceoapi.ReadTelemetryEventsParams{}) + assert.Equal(t, len(first), len(second), "a read must not append to the stream it reads") } // readEventsPage calls the endpoint and returns the page plus its cursor state.