Pixel

Pixel Updates & Events

Server Updates & Events

Announcements

DEV Community

What a 24/7 NOC Actually Monitors — and What It Doesn't

If you run a 30–80-person company, someone has probably tried to sell you "24/7 monitoring." It sounds like a person watching your network around the clock. Sometimes it is. Often it isn't — it's a dashboard that emails someone the next morning. I work at Amen Security, a Winnipeg MSP that runs monitoring for small and mid-sized companies. This is the honest version of what a NOC (network operations centre) watches, what it can't watch, and the questions worth asking before you pay for it. What a NOC actually monitors 1. Is it up? The basics: servers, firewalls, switches, internet links, and key services (email, file shares, line-of-business apps). A ping or health check every minute or two. If something stops answering, an alert fires. This is the least glamorous part and the most valuable — most outages are found this way, not by a user phoning in. 2. Is it about to break? Disk filling up, memory exhausted, a UPS battery degrading, a backup job that ran long or failed outright. Good monitoring watches trends, not just thresholds: a disk growing 2% a week will be full in a month, and that's a ticket today, not an outage later. 3. Is something behaving strangely? A login at 3 a.m. from a country nobody on your team is in. A server suddenly talking to an address it has never contacted. A mailbox rule created that forwards everything externally. These are the signals that matter most — and the ones a threshold alert will never catch on its own. They need someone who knows what "normal" looks like for your company. 4. Are the safety nets intact? Backups completed — and, more importantly, restorable. Patch levels current. Antivirus/EDR agents actually reporting in, not silently uninstalled or expired. Certificates not about to expire. The unglamorous checks are the ones that decide whether a bad day becomes a disaster. What it doesn't monitor It doesn't read your employees' minds — or their inboxes. A NOC sees that email is flowing; it doesn't know that the "invoice" your accounts person just opened was a phishing lure until the EDR or the user reports it. User awareness is still a layer no dashboard replaces. It doesn't fix your business processes. Monitoring will tell you the CRM is down. It won't tell you that half the sales team has been working around a broken workflow for six months. It measures systems, not whether the systems serve the work. It doesn't see inside encrypted traffic it has no business seeing. A NOC that promises to inspect everything is either breaking your privacy or overselling. The right scope is metadata and behaviour — what's connecting, how much, how often — not the contents of your team's work. It doesn't prevent everything. Monitoring shortens the time between "something broke" and "someone is fixing it." It does not make hardware immortal or attackers polite. Anyone selling zero downtime is selling a feeling, not a service. What to ask before you buy it Who answers the alert at 2 a.m., and how fast? A dashboard that pages a human is different from one that sends an email nobody reads until 9 a.m. Ask for the actual response times in writing. What's excluded? Printers, personal devices, that one server under someone's desk — the exclusions list is where surprises live. How do you know the backup works? "Backup completed successfully" is not proof. A restore test is. Ask how often restores are tested and whether you get the report. What does an alert look like to me? You should get a plain-language summary, not a raw log dump. If you can't understand the report, you can't judge the service. What happens when you find something? Monitoring without a defined response — who calls whom, who can approve a shutdown, who talks to your team — is just a more expensive way to watch things break. The short version A real NOC watches uptime, capacity trends, strange behaviour, and the safety nets — and it has a human who acts on what it sees. It doesn't watch your people, fix your processes, or promise nothin...

Powered by Readybot.io

**DEV Community** ## What a 24/7 NOC Actually Monitors — …

DEV Community

Building a touchscreen macro deck on an ESP32-P4 with LVGL 9.6

I wanted a Stream Deck-style macro pad without paying for a Stream Deck, so I built one on a GUITION JC1060P470C. It is a 7-inch, 1024 x 600 capacitive touchscreen on an ESP32-P4. The project is called Tessera Deck. It is MIT licensed, it runs on Windows 10 and 11, and the panel UI is LVGL 9.6 on ESP-IDF 6.1. This post covers the design choices behind the panel firmware and the host protocol, for anyone building something similar on an embedded display. The cover image is a Blender render made from the CAD model of the desk console. I have no photo of a printed one yet. The panel screenshots below are not photos either: the native PC build of the real UI code drew them, and the agents screen uses sample data. 1. Build the UI for the PC first The UI code compiles natively on the PC against the same LVGL sources as the firmware. A test feeds it touch input and renders 1024 x 600 frames. A layout bug shows up in seconds, with no flashing and no cable. I can also make screenshots for the README without photographing a screen at an angle. The catch is that the native build does not exercise the display driver, the touch controller or PSRAM limits. Those still need the board. I treat the native build as the place for UI logic and the board as the place for hardware surprises. 2. Keep the panel dumb The panel only draws and reports touches. A small Python host on the PC owns the USB Serial/JTAG port, runs the actions and serves the editor on 127.0.0.1. The two talk over a line protocol at 115200 baud. Each message is one UTF-8 line. The host sends text commands or one JSON object. The panel answers, and it also sends its own events as JSON lines. A key press looks like this, copied from the protocol page at v0.9.0: {"type":"deck_event","id":N,"button":N,"label":"…","hold":true}
hold is only present for a long press. Everything else about what the key does lives on the PC. That means I can add an action without touching the firmware, and the firmware stays small. There are limits to this design. The panel reads lines of up to 1,099 bytes and ignores a longer one, so the host sends a layout in 380-character chunks and an image in 160-byte chunks. A pressed key stays highlighted until the host answers, so without a host it flashes red at once. If the PC is off, the panel keeps the last layout on screen and the keys do nothing. 3. Update objects in place A touchscreen punishes rebuilds. If a gauge value arrived and the grid were rebuilt while you press a key, your finger would be on a new object that never saw the press, so I update in place. Now labels, colours and gauge values change on the existing LVGL objects. The grid is only rebuilt when the page or its layout changes. A key is never rebuilt under your finger. The same idea covers widgets. The host sends a title, a second line and a progress value, and the panel draws every wide key the same way. A new widget is a new host-side feature and needs no new firmware. 4. Treat icons as a cache problem Icons are the one thing that is too big to treat like text. The host sends each icon as RGBA with a CRC32 check, using these lines: AD_IMG_BEGIN
AD_IMG_DATA
AD_IMG_END
The panel only answers at the end: OK, INVALID or FULL. FULL means the cache cannot hold the image. The cache is 8 MiB in PSRAM. When it needs room it drops the least recently used image that no key is showing. If the panel needs an image it no longer has, it sends {"type":"image","id":"im:…"} and the host sends it again. Animated icons arrive as frames with a duration each. The CRC32 lets the panel answer INVALID for a corrupt image instead of showing it, and a corrupt icon is more annoying than a missing one. 5. Let the panel answer your AI agent When Claude Code wants permission to run something, the question appears on the panel with Allow and Deny buttons. The agents screen also shows what Claude Code, Codex and ZCode are doing and in which project. Setup adds hooks to ~/.claude...

Powered by Readybot.io

**DEV Community** ## Building a touchscreen macro deck on an …

DEV Community

Never let the model retype a number: how we read lab reports with two AI passes

People photograph a blood test report and ask "is this bad?". When we built the lab report explainer in Saluvo, the explanation turned out to be the easy part. The risky part is reading the numbers: a misplaced decimal turns a normal result into an alarming one, or the reverse. These are the design rules we ended up with. None of them need a special model, and they apply to any LLM pipeline that pulls numbers out of documents: invoices, prescriptions, bank statements. 1. Extraction is copying, not understanding The extraction prompt is deliberately dull: Copy every test row exactly as printed. Never guess a value; skip a row you cannot read. Values come back as strings exactly as printed ("7.8", "1,250", "<0.5"), at temperature 0, in a strict JSON shape. Reference ranges come back twice: as printed text ("4.0 - 5.6") and as numbers where they can be parsed (refLow, refHigh). A row the model can't read is skipped, not reconstructed from what's "usually" there. The prompt also handles the boring failures: if the photo isn't a lab report at all, the model returns {"markers": [], "notReport": true} and the user is asked for a clearer photo of the results page. 2. Read it twice, independently Two extraction calls run in parallel on the same image or PDF text: const [first, second] = await Promise.allSettled([
extract(MODELS[mode].precise, input, meter),
extract(MODELS.normal.precise, input, meter),
]);
Promise.allSettled, not Promise.all: if one reader fails or times out, the other's result is still used. If both fail, the user gets an error, never a half-guessed table. Then the two readings are matched row by row. Names are normalised ("HbA1c", "Hb A1c" and "HBA1C" become the same key), and values are compared exactly as numbers: function crossCheck(primary: Marker[], second: Marker[] | null): Marker[] {
if (!second?.length) return primary;
const other = new Map(second.map((m) => [keyOf(m.name), m]));
return primary.map((m) => {
const o = other.get(keyOf(m.name));
if (!o) return m;
const a = numberOf(m.value), b = numberOf(o.value);
const same = Number.isFinite(a) && Number.isFinite(b) ? Math.abs(a - b) < 1e-9 : m.value === o.value;
return same ? { ...m, verified: true } : { ...m, verified: false, altValue: o.value };
});
}
No tolerance band. If one reader saw 5.6 and the other 5.8, that's a disagreement, because on a lab report it might be the whole story. 3. When they disagree, ask the person holding the paper A disagreement isn't resolved by a third model or a vote. The row is shown with both readings and the user picks the one that matches their paper. Confirming a value also recomputes its flag: export function confirmMarker(m: Marker, value: string): Marker {
return { ...normaliseMarker({ ...m, value })!, verified: true };
}
The person has the original in their hand. Asking them is cheaper, faster and more honest than any amount of model cleverness, and it makes the tool say clearly what it couldn't read. 4. Don't trust the model's "high" or "low" The extraction returns a flag for each row, but the app doesn't use it when it can do the maths itself: if (Number.isFinite(num) && (refLow !== null || refHigh !== null)) {
flag = refLow !== null && num < refLow ? "low"
: refHigh !== null && num > refHigh ? "high"
: "normal";
}
The flag comes from the printed number and the printed range. The model's label is only a fallback for rows where the range isn't numeric. 5. The explaining model never sees the values This is the rule I'd most recommend stealing. The second stage writes the plain-words explanation, the questions to ask the doctor and which kind of doctor to see. It receives each marker's name, unit, printed range and flag, but not the value: prompt: JSON.stringify(markers.map(({ name, unit, refText, flag }) => ({ name, unit, refText, flag }))),
And its instructions say: don't write the patient's result values anywhere; the app shows the exact numbers next to your te...

Powered by Readybot.io

**DEV Community** ## Never let the model retype a number: …

DEV Community

Escanear la aplicación publicada: Nuclei y Wapiti en Campus Tareas

Autor: Antony Piero Solorzano Zegarra Proyecto desarrollado con: Adriana Rafaela Laos Gonzáles Campus Tareas ya estaba publicada en GitHub Pages y guardaba sus datos en Cloud Firestore. Para esta actividad se revisó la respuesta de la aplicación con Nuclei y Wapiti. Ambas figuran en la lista de escáneres de OWASP. Se eligieron herramientas distintas de SonarCloud, Snyk y Semgrep, presentes en los workflows académicos revisados. Qué se analizó La URL examinada fue https://antonys3010.github.io/campus-tareas-nosql/. El alcance se limitó a esa página, sus cabeceras HTTP, su política CSP y los atributos de las cookies que pudiera entregar. No se utilizaron credenciales de Firebase. Nuclei ejecutó una sola plantilla oficial firmada, http-missing-security-headers, con una petición por segundo y concurrencia de una plantilla. Wapiti utilizó únicamente los módulos csp, http_headers y cookieflags, con alcance url y sin navegador headless. No se activaron módulos de inyección ni se analizaron las operaciones autenticadas de Firestore. Los resultados no permiten afirmar que toda la aplicación sea segura ni que las reglas de la base de datos sean incorrectas. Instalación y ejecución Se fijaron Nuclei 3.11.1 y Wapiti 3.3.2. El instalador incluido en el repositorio descarga la distribución oficial de Nuclei y comprueba su SHA-256. Para reproducir el análisis desde el repositorio: python -m venv .venv
. .venv/bin/activate
python -m pip install -r security/requirements.txt
python scripts/install-nuclei.py .tools
PATH="$PWD/.tools:$PATH" python scripts/security-scan.py
El script comprueba primero que la URL responda con HTTP 200. También compara el SHA-256 del HTML recibido con public/index.html, para vincular el análisis con el código del checkout. Durante la primera prueba local, Nuclei no pudo resolver el nombre del sitio. Aunque terminó sin coincidencias, ese resultado no se tomó como un escaneo limpio. Se configuró el proxy ya disponible en el entorno y se repitió la ejecución. La nueva prueba confirmó una respuesta HTTP y registró los hallazgos. Los resultados Nuclei reportó 9 coincidencias informativas por cabeceras ausentes. Wapiti reportó 3 hallazgos bajos: Categoría de Wapiti Observación Content Security Policy Configuration No se encontró una política CSP Clickjacking Protection No se encontró X-Frame-Options MIME Type Confusion No se encontró X-Content-Type-Options Los tres puntos también aparecen entre las comprobaciones de Nuclei. No corresponde sumar ambos resultados como doce vulnerabilidades independientes. Una cabecera ausente es un hallazgo de configuración; por sí sola no demuestra una explotación de XSS o la lectura de documentos ajenos. HSTS y el tipo de contenido HTML con charset sí estaban presentes. Las demás cabeceras se deben evaluar según las necesidades de la app: activar restricciones sin comprobar su efecto puede romper recursos externos. Lo declarado en un archivo y la respuesta real El repositorio conserva un firebase.json que declara cabeceras de seguridad. Sin embargo, la web se sirve desde GitHub Pages. Esa configuración de Firebase no modifica la respuesta de GitHub Pages. Encontrar nosniff en un archivo no basta para afirmar que el servidor lo envía. La respuesta publicada es lo que debe comprobarse. Los hallazgos se dejaron documentados y no se presentan como corregidos. Para administrar estas cabeceras habría que utilizar un alojamiento o proxy que permita configurarlas y volver a probar el funcionamiento del SDK de Firebase. Automatización después del despliegue La app se despliega mediante GitHub Actions. Cuando termina correctamente el workflow Comprobar y publicar Campus, otro workflow ejecuta Nuclei y Wapiti. También admite ejecución manual. La ejecución verificada terminó correctamente y coincidió con la prueba local. Conserva los reportes JSON, registros, metadatos y resumen como artefactos durante 30 días. La evidencia inicial también está versionada en el repositorio. Un estado verde indica...

Powered by Readybot.io

**DEV Community** ## Escanear la aplicación publicada: Nuclei y Wapiti …

DEV Community

Webhook Retry Queue: Delayed Jobs and Idempotency in Node.js

Short answer: treat a webhook retry queue as an at-least-once transport, and make the durable business change idempotent with a stable event identity and a database transaction. The deciding constraint is the gap between doing work and acknowledging it. A worker can commit a change, lose its process before the acknowledgement is recorded, and receive the same job again. No reasonable retry policy can infer whether that first change happened. Delayed jobs help recovery; they do not close that gap. For an AI application, that distinction matters twice. A repeated state change can corrupt customer state, while a repeated call to a model or external API can consume latency and usage budget without producing a new result. Keep the queue simple, but make its boundaries explicit. Why do webhook retry queues create duplicate processing with delayed jobs and at-least-once delivery? There are usually two independent retry loops. The webhook sender retries when it does not receive a timely success response. The receiving system may then retry its queued work after a timeout, a process restart, or an unavailable dependency. Both loops are valid, and either can place the same logical event in front of a handler more than once. Consider a delivery carrying evt_482. The receiver accepts it and places it in durable work storage. A worker charges ahead: it writes the new subscription status, commits the transaction, and is interrupted before its queue acknowledgement becomes durable. On recovery, the queue sees an unacknowledged attempt and makes evt_482 runnable again. The second worker is not seeing a new customer action. It is seeing an unresolved delivery outcome. That is why "exactly once" is a misleading promise for most distributed systems. The sender, queue, worker, database, and any downstream service do not share one atomic commit. The useful target is one durable business effect for each logical event, even though execution can repeat. A scheduled retry introduces a separate ordering question. If an older account update waits in a delayed set while a newer update completes, blindly applying the older message later can roll state back. Put a producer version, sequence, or monotonic timestamp in the event when the domain has an ordering rule. The transaction that claims the event should also reject a stale transition. The small failures are the dangerous ones. A 200 response proves that a hop responded; it does not prove that an intended state exists after a crash boundary. Put the idempotency boundary around the business effect Start with an event key that is stable across every delivery. A producer-supplied event ID is ideal. When the protocol does not offer one, derive a deterministic key from immutable business identifiers, the event type, and a source version. Generating a random key on receipt defeats deduplication because each retry looks unrelated. Then claim that key in durable storage. An in-memory Set vanishes on restart and cannot coordinate multiple Node.js processes. A read followed by an insert is also insufficient: two workers can both observe an absent row before either write wins. A unique constraint or equivalent conditional insert gives the database one clear arbitration point. One key, one ledger. Here is the full decision path worth testing before calling a handler safe. A signed delivery with evt_482 arrives twice because the sender did not observe the receiver's first response; both requests validate to the same identity, and both attempts try to enqueue work. Queue-level deduplication may collapse those attempts, but it is an efficiency optimization rather than proof, since one request may have reached the queue through a different path or after queue history has been cleaned up. A worker claims evt_482 and writes the account status. If that worker finishes normally, it acknowledges the job. If it exits after the transaction and before the acknowledgement, another worker can later receive the same job. Its...

Powered by Readybot.io

**DEV Community** ## Webhook Retry Queue: Delayed Jobs and Idempotency …

DEV Community

Compare Cloud Storage Providers for Direct Browser Uploads — Node.js Retention Rules

Property management teams should choose browser-upload storage by its trust boundary and retention controls, not by whether its SDK can mint a presigned URL. For training artifacts, the browser should receive permission for one object, for a short window, with a server-owned key and a separately enforced retention policy. The storage provider matters after those rules are clear. A useful design has three planes: a Node.js service authorizes an upload, the browser sends bytes directly to object storage, and a worker records completion and applies retention metadata. That separation keeps credentials out of the browser, but it does not make the browser trustworthy. It can still retry, abandon a multipart upload, or send an unexpected content type. I treat those as normal states, not exceptional ones. Ownership decides the boundary. No exceptions. What is the real trust boundary for a training upload? A presigned URL is a bearer capability. Anyone who obtains it can use it until it expires or its constraints stop matching the request. The API should therefore decide the archive identity before it signs anything: property, course, employee or cohort, artifact type, maximum size, and an immutable object key. Do not accept a client-provided path such as training/finished.pdf and then try to sanitize it later. For a property management system, an upload record might begin as pending, include the policy version that selected its retention class, and contain a digest once the object is verified. The browser gets an upload URL and an opaque upload ID. It does not get a storage access key, a bucket-wide listing permission, or permission to choose a retention date. CORS is part of this boundary, but it is not authorization. It controls which browser origins may read or send certain cross-origin requests; it does not stop a non-browser client from using a valid bearer URL. Keep the allowed origins narrow, expose only the headers the upload flow needs, and test preflight behavior with the actual headers used by the browser. A permissive wildcard can hide a broken design during development. How should the retention policy shape the upload path? Start with the record, not the bucket. A policy table can map annual_safety_training to a retention class such as 7_years, while draft_course_material maps to 90_days. Store the selected class and policy version with the pending upload. At completion, the service verifies the object and queues the archive event. A later policy change should affect new records unless governance explicitly schedules a migration; silently rewriting old decisions is a difficult audit story. The object key should be uninteresting and collision-resistant, for example properties/42/training/2026/10/opaque-id. The human filename belongs in metadata or the application database. This makes retries idempotent and prevents a filename from becoming an authorization primitive. It also gives the cleanup worker a stable query key when an employee uploads the same certificate twice. S3 lifecycle rules are useful for expiration and transitions, but they are not a substitute for the policy record. The lifecycle documentation describes rules that can act on objects by prefixes, tags, or object age. Those selectors are operational tools. The application still needs to explain why this object received a particular tag and which policy version produced it. How should cloud storage providers handle direct browser uploads? The comparison becomes clearer after the contract is fixed. Amazon S3, Cloudflare R2, and Wasabi all present S3-compatible patterns that can support direct uploads, but compatibility is not sameness. Check the exact signing behavior, multipart limits, CORS configuration surface, checksum support, lifecycle selectors, and event delivery available in the region and account you will use. For a property management archive, I would put that contract in a test matrix before anyone debates a default provider. Provider Direct u...

Powered by Readybot.io

**DEV Community** ## Compare Cloud Storage Providers for Direct Browser …

DEV Community

Qué significan las alertas de Nuclei y Wapiti en una app de tareas

Autora: Adriana Rafaela Laos Gonzáles Proyecto desarrollado con: Antony Piero Solorzano Zegarra Artículo de Adriana Rafaela Laos Gonzáles, publicado desde la cuenta de Antony Piero Solorzano Zegarra, integrante del mismo equipo. Un escáner puede terminar con varias advertencias sin que todas representen fallos distintos o tengan el mismo impacto. En esta actividad se analizó Campus Tareas, una aplicación con JavaScript y Firestore publicada en GitHub Pages. Se utilizaron Nuclei y Wapiti para revisar la configuración observable desde su URL pública. Ambas herramientas figuran en la lista de OWASP. Se excluyeron SonarCloud, Snyk y Semgrep, presentes en los workflows académicos revisados. Preparar una ejecución reproducible La aplicación tiene un repositorio público y se despliega con GitHub Actions. El nuevo análisis se ejecuta después de un despliegue correcto. Las versiones de las herramientas quedaron fijadas: Nuclei 3.11.1 y Wapiti 3.3.2. El script de Nuclei emplea la plantilla oficial firmada http-missing-security-headers. Wapiti se limita a csp, http_headers y cookieflags. No se activaron módulos de inyección o fuerza bruta y no se entregaron credenciales del navegador. Antes de ejecutar los escáneres, el script comprueba la respuesta HTTP y compara el hash del HTML publicado con el del archivo del repositorio. Así se evita confundir un error de conexión o una versión diferente de la web con un resultado válido. Nueve coincidencias y tres hallazgos Nuclei encontró 9 coincidencias informativas, todas relacionadas con cabeceras de seguridad ausentes. Wapiti clasificó 3 hallazgos como bajos: CSP, protección contra clickjacking y protección frente a confusión de tipos MIME. Los resultados coinciden en parte. Se refieren a una misma respuesta HTTP y varias advertencias señalan la misma configuración. Por eso, no se sumaron como doce vulnerabilidades independientes. La severidad también pertenece al contexto de cada herramienta. Que Nuclei marque una coincidencia como informativa y Wapiti la incluya entre sus hallazgos bajos no es una contradicción: emplean categorías y criterios diferentes. Revisar el impacto de cada advertencia Una CSP define restricciones para los recursos que puede cargar una página. La ausencia de esa política reduce una capa de defensa, pero no demuestra que exista una inyección de JavaScript. En esta app, el contenido de las tareas se inserta con textContent; el escaneo realizado no identificó una explotación de XSS. La advertencia de clickjacking señala que no se encontró X-Frame-Options. Se debería evaluar una política de inclusión en marcos mediante esa cabecera o mediante frame-ancestors en una cabecera CSP. No basta con añadir cualquier directiva en una etiqueta HTML: algunas protecciones requieren una cabecera de respuesta. X-Content-Type-Options: nosniff indica al navegador que respete el tipo de contenido declarado. La ausencia de esa cabecera debe revisarse junto con los tipos MIME reales que entrega el servidor. El análisis sí observó un tipo de contenido HTML con charset y HSTS en la respuesta. El alojamiento también forma parte del resultado El archivo firebase.json contiene una configuración de cabeceras, pero la web se aloja en GitHub Pages. Esa configuración no se aplica a este proveedor. La revisión de la respuesta confirmó la diferencia entre lo declarado en un archivo y lo que recibe el navegador. Para corregir las cabeceras se necesita un alojamiento o proxy que permita controlarlas. También hay que probar que una CSP no impida las conexiones con Firebase o la carga de sus módulos. En esta actividad se documentaron las medidas posibles, sin afirmar que los hallazgos ya estén corregidos. Conservar la evidencia El workflow guarda los reportes originales de las dos herramientas, sus registros y un resumen. Los archivos permiten revisar el objetivo, las versiones, el commit y la fecha de ejecución. Si las herramientas fallan, el trabajo debe señalarlo; no debe convertir una ausencia de ...

Powered by Readybot.io

**DEV Community** ## Qué significan las alertas de Nuclei y …

DEV Community

Configure a Durable Queue or Fast Streams for Rate-Limiting HTTP-Based Logistics Webhooks

Configure a Durable Queue or Fast Streams for Rate-Limiting HTTP-Based Logistics Webhooks To configure a queue for rate-limiting HTTP-based webhook processing in a logistics renewal workflow, choose a durable queue when missing a business deadline is worse than adding a few milliseconds of handoff time. Choose a fast stream only when the downstream contract can tolerate replay, retention, and consumer-management work. The queue is not the rate limiter. It is the shock absorber; the worker-side limiter is the clock that protects the webhook destination. Here is the decision matrix I use before writing a producer: Constraint Durable queue Fast stream Reminder must survive a worker restart Strong fit Possible, with explicit retention and offsets Burst arrival versus fixed webhook quota Pair with a token bucket Pair with a token bucket One consumer should own each job Natural model Requires consumer-group rules Operators need a dead-letter path Built-in pattern in many systems Application convention Lowest possible handoff latency matters Usually not the first choice Better candidate My default is the durable option for renewal reminders. The decision changes when the deadline is soft, the destination is idempotent, and the team already operates stream offsets confidently. That is the whole fork. How should I configure a queue for rate-limiting HTTP-based webhook processing? A logistics renewal reminder has at least three times attached to it: when the carrier account became eligible, when the business wants a reminder sent, and when the webhook receiver will reject a late request. Confusing those timestamps creates a queue that looks healthy while delivering useless work. Store the intended delivery time with the job. Do not use queue arrival as a substitute. A cron task can poll for eligible records every minute, publish them, and exit. That task should not perform the HTTP call itself. A short cron run that discovers 10,000 renewals can otherwise create a burst against a receiver that permits 20 requests per second. The worker needs two independent gates. First, it waits until the job is eligible. Second, it acquires a rate-limit token for the receiver and route. The first gate protects business timing; the second protects an external system. A retry belongs behind both gates, or a failed request can immediately consume the whole retry budget in a tight loop. This is the small contract I want between the scheduler and the worker: type RenewalReminder = {
id: string;
accountId: string;
destination: string;
dueAt: string;
attempt: number;
idempotencyKey: string;
};

function isEligible(job: RenewalReminder, now: Date): boolean {
return Date.parse(job.dueAt) <= now.getTime();
}
The payload is deliberately boring. An immutable job id, an explicit due time, an attempt count, and an idempotency key give the worker enough information to make a decision after a restart. A URL alone does not. The trade-off is intentional: more fields make the contract larger, but they make delayed processing inspectable. No shortcuts. Where should rate limiting live? Put the limit at the narrowest boundary that owns the quota. If a receiver allows 20 requests per second per account, a process-wide limiter is wrong as soon as two accounts share a worker. If the quota is per destination, key the limiter by destination. If the receiver documents a global quota, use a shared limiter or partition work so each worker sees the same budget. A token bucket is a useful mental model: tokens arrive at a fixed rate up to a capacity, and each HTTP attempt spends one. Capacity controls the burst. Refill rate controls the sustained pace. Do not let the queue's concurrency setting pretend to be a rate limit. Ten concurrent requests can still violate a per-second quota, especially when response times vary. The limitation is operational: a shared limiter needs shared state, while a local limiter is easier to run but cannot enforce a global quota. The wo...

Powered by Readybot.io

**DEV Community** ## Configure a Durable Queue or Fast Streams …

DEV Community

I built a decision graph on HydraDB that learns from corrections. Here's what broke.

Agents keep acting on engineering decisions that were reversed years ago. A 48-hour HydraDB build, the bugs I hit, and an honest baseline. Every engineering team writes its decisions down. Then it changes its mind and writes another one. Two years later, search finds the old decision as easily as the new one, and an AI coding agent will happily build on a choice the team reversed long ago. For the HydraDB hackathon I built DecisionGraph to fix that. It links each architecture decision record (ADR) to the records that replaced it. When an agent asks "what did we decide about X?", it walks those links to the decision that still stands and hands back that decision and its history, in about 130 tokens instead of 590. When someone corrects an answer, the correction is written into the graph, so the next question on that topic lands right even in different words. Live app: https://decisiongraph-latest.onrender.com Code: https://github.com/0xNexuz/decisiongraph Video walkthrough: https://youtu.be/ChWL-frv5v8 The problem in one picture Asked "Does each business unit get its own Cloud Platform cluster now?", vector search returns the closest text: a 2019 decision to run one shared cluster, which has been replaced three times since. DecisionGraph starts at the same record, then follows the "replaced by" links to the decision that stands today. The data is about 130 real, public ADRs from three UK government engineering teams: MoJ Cloud Platform, MoJ Modernisation Platform and GOV.UK on AWS (all MIT licensed). The test set is 50 questions I wrote, scored before each correction is applied. How it works Find the decision. Vector similarity, distinctive terms and hints from past corrections each vote for where the question starts. Walk to what replaced it. One HydraDB path query follows trusted "replaced by" links until it reaches a decision nothing has replaced. Learn from the correction. The links on the right path are confirmed, the wrong ones rejected, and the question is stored as a node so the next one like it starts in the right place. Where HydraDB earned its place Trust lives in the path cost Every REPLACED_BY link has a cost: 1 if trusted, 100 if not. Walking only trusted links is then a single algo.MSpaths call with maxCost set to the path length, so one untrusted hop rules the path out: CALL algo.MSpaths({
sourceLabel: 'Decision', sourceProperty: 'key',
sourceValues: ['cloud-platform:12'], targetValues: [...],
relTypes: ['REPLACED_BY'], relDirection: 'outgoing',
maxLen: 5, pathCount: 1, pairwise: false,
weightProp: 'cost', costProp: 'cost', maxCost: 5
}) YIELD path RETURN path
"Follow only what we trust" stopped being a loop in my Python and became one query inside the database. Learning is a write, not a retrain Links come from rules: an ADR's status line naming its replacement, a body that cites an older ADR next to "replace" or "migrate", and so on. Each rule has a trust score (a Beta count). When a correction proves a rule right or wrong, the new trust flows to every link that rule proposed that nobody has judged yet, in one statement: MATCH (x:Decision)-[r:REPLACED_BY]->(y)
WHERE r.rule = $rule AND r.state = 'candidate'
SET r.w = $w, r.cost = $c
The graph that answers the next question is already the corrected one. Memory is part of the graph Every corrected question becomes a Question node with a RESOLVED_TO edge to the right decision, an ABOUT edge to the topic and IN_QUESTION edges from its distinctive terms. "Has someone asked this before?" is a two-hop walk from the new question's terms, not a separate cache. Two cells, two worlds The public demo runs on one HydraDB cell. The "replay all 50 corrections" demo runs on a second cell, so a visitor pressing replay never resets anyone else's graph. Self-hosted for $0 HydraDB is built from source into one Docker image with the app. GitHub Actions builds the image and pushes it to GitHub's container registry, and it runs on Render's free tier. What broke, and h...

Powered by Readybot.io

**DEV Community** ## I built a decision graph on HydraDB …

DEV Community

Object destructing , Array destructing

Object destructing It unpacks the properties from an object and stores the value into new variable in one step eg: const name = props.name function child({name}) -- collecting them as a separate variable so we don't want to call it as repeatly like props.name, props.age props props... with the help of destructing we reduce it. Array destructing Similar to Object destructing but the only difference is array are taken by the position. eg: const skills = [ "JS" , " React" , "CSS"] const [skills1, skills2, skills3] = skills console.log(skills1) //js

Powered by Readybot.io

**DEV Community** ## Object destructing , Array destructing Object destructing …

DEV Community

The model was the easy part

A retail brand doesn’t ask how many people walked into a store. It asks why a store with high footfall isn’t selling, which stores deserve more stock before the festive season, and where to open the next one. Answering those questions from a camera feed takes far more than a model that can detect people. I had already shipped multiple features with AI-assisted workflows, and in earlier projects the work usually started and ended with a technical problem. Camera Analytics for retail was different. I was building an ML pipeline for computer vision, and getting the model to work turned out to be the smaller part of the job. The real product was everything around it: understanding what retailers needed, making it work in stores that were all set up differently, and keeping it reliable as features and data grew. Retailers didn’t want a footfall counter Retail brands wanted more than a count of how many people walked in. They wanted to understand customer behaviour: how long people browsed, whether they were greeted, and whether they came in alone or as part of a group. Zones turn a camera view into behaviour: greeting at the entrance, browsing on the floor, and conversion at the billing counter. AI-generated image. Those details fed much bigger decisions. Brands could compare footfall with sales, understand festive shopping trends, and use store performance to plan inventory and new store openings. I spoke with retail clients in India and Poland to understand how they would use this. What surprised me was how far these granular details travelled, well beyond the store floor into decisions across the business. The needs also varied from one brand and store to the next, so understanding the use cases early shaped a product that could support more than one setup. That early focus on real use cases shows in the results: the product converts more than 90% of proofs of concept (POCs) into customers. Every store is a different problem No two stores were set up the same way, and each one brought its own problems. Even a single camera angle changing could affect the setup and the results. If every adjustment needed an engineer, onboarding more stores would become the bottleneck. So I built admin-level controls and an Electron app that handle much of the onboarding work. Someone who understands the system and the model can use it to reconfigure a store remotely, including when a camera angle changes. Documenting the use cases and working through these requirements before building made the biggest difference. The work stopped being about implementing a feature and became about designing how the product would actually be used and maintained. The infrastructure is part of the product Every new pipeline stage or downstream task added load to the system. Before releasing a feature, I needed to know how it affected worker throughput, GPU load and power usage. The goal was to process as much data as possible without throttling. With large volumes of data, each new feature meant benchmarking, training the pipeline, reviewing results and stress-testing the server under high load. Grafana alerts helped me monitor it, but I still wanted to see how the system behaved under real test conditions before trusting it. The next step is moving parts of the pipeline from Python to C++ to reduce the impact of the GIL on parallel execution. Early tests show it is already reducing that bottleneck, though completing the migration will take time. Where the textbook got it wrong Most optimisation advice for GPU inference pipelines is sound in general. On our hardware and under our load, a couple of the obvious moves didn’t do what the textbook promised. Each time, the lesson was the same: measure what is actually happening before deciding what to optimise. For context, the detection model runs on the GPU, while most of the preprocessing happens on the CPU. That split between a fast GPU and a busy host shapes everything below. Detection and tracking on a busy stor...

Powered by Readybot.io

**DEV Community** ## The model was the easy part A …

DEV Community

LLM Weights are Hardcoded Intelligence

Hey everyone 👋, I need to say something upfront that I know some people are going to push back on, and I want to get the disclaimer out of the way before the argument starts. This post is a critique. Not a hate piece, not a dismissal, and not the kind of hot take that evaporates the moment someone asks a follow-up question. I have been building toward this argument across nearly every AI-related post I have written, from LLMs are Useful. LMMs will Break Reality, where I tried to be fair about what LLMs genuinely accomplish, to Training Is an Evil Concept. LMMs Eliminates it Altogether., where I argued that the entire training paradigm carries moral weight that the industry refuses to examine, to Intelligence at Rest, where I unpacked what it actually means for a system to store something worth calling intelligence. Each of those posts was pointing at the same underlying problem from a slightly different angle, and in this post I want to point directly at the center of that problem and name it plainly. The problem is this: LLM weights are hardcoded intelligence. And hardcoded intelligence, no matter how impressively hardcoded it is, is not the same thing as intelligence. It is a fossil of intelligence, a snapshot, a frozen record of what the world looked like at training time, compressed into billions of floating-point numbers that will never change again on their own. I am not saying that is worthless. I am saying that is a fundamentally different thing from what people are claiming it is, and the gap between the claim and the reality is exactly where the most dangerous illusions live. I want to be honest about my own position before anything else, because I think honesty is the only thing that makes a critique worth reading. I am not an established academic with ten published papers on neural network theory. I am a software engineer who has spent years watching the AI industry make increasingly extravagant promises, using language that is increasingly disconnected from the actual mechanics of what these systems do, and I have watched people bet careers and livelihoods and policy decisions on those promises. I wrote in Technology Has Destroyed My Livelihood about how the technology industry dismantled things that mattered to people while calling it progress, and the AI industry is doing something very similar right now with the concept of intelligence itself. It is taking a specific, limited, technically impressive capability, compressing it into a word, and selling the word to the world at a markup that the word cannot support. I am writing this post because I think the gap between the word and the reality deserves to be named clearly, and because the alternative I believe in, which is what we have been building with the LMM project, is real enough and grounded enough to present as an honest alternative. That is what I am going to do in the sections below, and I am going to try to do it without being unfair to the technology I am critiquing. The Weight Is All There Is Let me start at the most basic technical level, because the argument I am making is ultimately a technical one, and I do not want to dress it in philosophy when the engineering is enough. A large language model, in its final deployed form, is a file. It is a collection of tensors, arrays of floating-point numbers, organized according to a specific architecture. For something like GPT-3, that file contains approximately 175 billion individual float values. For GPT-6, the number is estimated to be in the trillions. Each one of those numbers is the result of an optimization process called gradient descent, which ran over hundreds of billions of tokens of text, adjusting each number very slightly with each pass, until the collective behavior of all the numbers together minimized a loss function called cross-entropy, which measures how well the model predicts the next token in a sequence. When that process ends, the numbers are saved. They are written to disk. T...

Powered by Readybot.io

**DEV Community** ## LLM Weights are Hardcoded Intelligence Hey everyone …

DEV Community

Ukrainian scans, invoices, Word and Excel to Markdown - 5 Apify Actors on 7 files, only one got every table right

Search the Apify Store for "PDF to Markdown" and you get dozens of Actors with almost the same promise: text, tables, OCR, ready for RAG. None of them tells you what happens with a Ukrainian scan, an Excel file or a scanned invoice whose table has no lines. So I ran five of them on the same seven files and compared every output with the text the files were made from. All results below are from real runs on 15 November 2026. Disclosure: one of the five is mine, Document to Markdown for AI. Every number below comes from a real run, the test files are public and the raw outputs are kept, so you can repeat and check all of it. Short answer Files right (of 7) Invoice without lines: rows exact Reads Word and Excel Price per scanned page ai_admin/document-to-markdown 7 5 of 5 yes $0.004 nidamindllc/doc-ocr 2 4 of 5 no (error) $0.004 lergassy/pdf-text-extractor 1 0 yes $0.0111 fabrikit/document-to-markdown 2 0 yes $0.0105 gochujang/pdf-text-extractor 1 0 (empty) no (PDF only) $0.006 "Right" means the text, the heading and the table with the correct rows and with every number exactly as in the document. The seven files All Ukrainian, all generated from known text, so every character can be checked: File What it is text-uk.pdf PDF with a text layer: heading, two sentences, a 3 x 3 table with prices like 96,50 scan-uk.pdf the same page as a clean scan scan-noisy-uk.pdf the same scan with noise and a slight tilt doc-uk.docx Word document with the text, a list and the table sheet-uk.xlsx Excel workbook: the table with a Total row 1,234.50, and a sheet with the sentences scan-borderless-uk.pdf a scanned invoice: 5 x 6 table without any lines, amounts like 40 530,00 and 2 500 scan-noisy-borderless-uk.pdf the same invoice, noisy and tilted The last two are the hard case and the most common one: most invoices, waybills and bank statements are printed without table lines. The files are public: https://api.apify.com/v2/key-value-stores/FloomuI2DrQCJazY8/records/. The Actors are the most used ones for this search plus one that lists Office formats. Settings: Ukrainian OCR wherever the Actor has a language option (ukr); nidamindllc has no language option. Results, file by file File mine nidamindllc lergassy fabrikit gochujang Text PDF right one OCR typo, table right (HTML) table flattened into the text table as plain lines right Clean scan right right (HTML table) table as broken lines table lost empty Noisy scan right right (HTML table) table as broken lines rows without header empty DOCX right error right right not supported XLSX right, 1,234.50 kept error 1,234.50 became 1234.5 right not supported Invoice, no lines 5/5 rows, 30/30 cells 4/5 rows, 29/30 cells no table, 40 530,00 lost its space no table, all in one line, 96,50 read as 96,0 empty Invoice, no lines, noisy 5/5 rows, 30/30 cells 4/5 rows, 29/30 cells no table, 96,50 read as 96,60 no table, all in one line empty This is what my Actor returned for the noisy invoice without lines - every cell, every number and the № sign as in the document: Рахунок-фактура № 47

Постачальник: ТОВ «Будмайстер», м. Львів. Покупець: ФОП Коваленко О. В. Оплата протягом п'яти банківських днів з дати рахунку.

№ Товар Од. Кількість Ціна Сума 1 Цемент М500 мішок 420 96,50 40 530,00 2 Арматура 12 мм шт. 180 412,00 74 160,00 3 Пісок річковий т 12 650,00 7 800,00 4 Цегла рядова шт. 2 500 9,80 24 500,00

Разом: 146 990,00 грн
The same table also comes as rows of cells in the tables field, ready for a spreadsheet or a database, and the record says how many pages went through OCR, so a pipeline knows which text came from a scan. For comparison, the same line of the invoice from two other Actors: lergassy: 1 | Цемент М500 мішок 420 96,60 40530,00
fabrikit: ... Мо Товар Од. Кількість Ціна Сума 1 Цемент М500 мішок 420 96,50 40 530,00 2 Арматура12мм шт. ...
What stood out gochujang returned empt...

Powered by Readybot.io

**DEV Community** ## Ukrainian scans, invoices, Word and Excel to …

DEV Community

How to turn a slide screenshot into a PowerPoint someone else can edit

AI disclosure: This tutorial was drafted and reviewed using AI for Image2PPT. Say you're handing off a monthly dashboard. You have a PNG that looks exactly the way you want, but next month someone else needs to rename a metric and update a chart. Dropping the PNG into PowerPoint solves today's presentation. It leaves next month's edits inside the image. Before rebuilding the slide, write down what will change. On a dashboard that might be the date, a couple of figures, and the data behind a chart. Those things need to be separate PowerPoint objects. A decorative illustration can stay a picture. If only a few things change, rebuild those by hand Insert the image into a blank slide and use it as a layout reference. Create PowerPoint text boxes for the labels and figures you need to update. If a label sits on a solid-colored card, you can cover the old text with a matching rectangle before adding the new one. If it sits over a photo or gradient, the patch will often show. If you can regenerate the image, leave that area blank and add the label in PowerPoint. Build a chart from the source data if someone will need to update the values. A chart copied from a screenshot can look right but still behave like a picture. If you don't have the source data, ask for it rather than estimating the numbers from bar heights. If you have several pages, try the hardest one first If every page has a dozen labels, rebuilding all of them by hand is a different job. An image-to-PPTX converter can give you a starting point. Pick the hardest page someone will actually have to maintain. If that's the dashboard with dense labels and overlapping shapes, start there, not with the title slide. Disclosure: I build Image2PPT. Here's a public dashboard source image and the PPTX rebuilt from it. The exported file contains “Renewal Risk” as a text object. Open it in PowerPoint and try replacing “Renewal Risk” with “Renewal Risk for New Customers.” See whether the longer label still fits. Then move the surrounding card a little. If they select together, open the Selection Pane to see whether they’re grouped. If the card is part of a picture, only rebuild it if someone needs to move it. Apply the same test to any chart you need to maintain. Select it and look for Chart Design → Edit Data. In a copy, change one value and see whether the chart updates. Being able to change a number drawn next to a bar isn't the same as being able to update the chart. Before handing the deck off, make the exact edit the next person is likely to make. If the title, labels or data they need can be changed without redoing the page, you're done. Keep the original image and send the source workbook too if the chart depends on it.

Powered by Readybot.io

**DEV Community** ## How to turn a slide screenshot into …

DEV Community

df-script - a 43kB zero-dependency, expression-based DataFrame engine for TypeScript and JavaScript

Docs & Interactive Playground: https://df-script.js.org AI Agent Docs: https://df-script.js.org/llms-full.txt GitHub Repository: https://github.com/trentamorris/df-script Install: npm install df-script License: MIT Overview Heavily inspired by modern columnar engines like Polars and Pandas, df-script packs 300+ declarative operations into a 43kB, zero-dependency DataFrame engine for modern JavaScript and TypeScript environments. It lets you easily execute complex multi-column groupings, relational joins, windowed rolling statistics, string parsing, temporal conversions, and much more with a fluent, expressive API. Why df-script? For most web applications, performing complex data transformations requires maintaining a dedicated backend service. Suddenly, an otherwise straightforward application introduces deployment pipelines, network latency, serialization bottlenecks, asynchronous state management, and ongoing cloud hosting bills, all just to run operations modern client CPUs can perform in milliseconds. To avoid this, many developers implement hand-written functions or native chains of .map(), .filter(), and .reduce() to transform data directly in the browser. These chained operations repeatedly traverse the dataset and flood memory with intermediate objects, degrading performance and freezing the UI. Worse, what starts as a simple utility quickly devolves into hundreds of lines of fragile boilerplate once real-world edge cases surface. df-script changes this equation entirely. It introduces a 43kB zero-dependency, column-oriented DataFrame engine constructed specifically to enable complex chained data transformations directly in the browser with zero network latency and no server maintenance. By avoiding high-level array iterators like .map() and .reduce() in favor of contiguous columnar loops, df-script drastically cuts intermediate object allocations to reduce garbage collection pressure. Every function is backed by a dedicated 1:1 test suite covering hundreds of extreme edge cases, so you never have to hand-roll fragile data logic again. Built-In CSV & NDJSON Ingestion + Multi-Metric GroupBys You don't need external parsers to ingest raw text feeds. df-script parses CSV, JSON, and NDJSON directly into columnar storage and runs declarative aggregations with full TypeScript inference: import { $df } from "df-script";

const rawCsv = region,category,revenue,quantity,timestamp East,Hardware,450,3,2026-02-01 East,Hardware,550,5,2026-02-10 West,Software,1200,1,2026-01-20;

const salesSummary = $df
.readCsv(rawCsv)
.groupBy(["region", "category"])
.agg([
$df.col("revenue").sum().alias("total_revenue"),
$df.col("revenue").mean().round(2).alias("avg_revenue"),
$df.col("quantity").sum().alias("units_sold"),
$df.col("timestamp").str.toDatetime().dt.year().alias("year"),
])
.sort("total_revenue", { descending: true });

console.log(salesSummary.toDicts());
/
+--------+----------+---------------+-------------+------------+------+
| region | category | total_revenue | avg_revenue | units_sold | year |
+--------+----------+---------------+-------------+------------+------+
| West | Software | 1200 | 1200 | 1 | 2026 |
| East | Hardware | 1000 | 500 | 8 | 2026 |
+--------+----------+---------------+-------------+------------+------+
/
Partitioned Window Functions (.over()) & Rolling Metrics Compute group-partitioned metrics, cumulative sums, rolling statistics, and exponentially weighted moving averages without manual grouping and merging: const transactions = $df.data([
{ region: "East", revenue: 450 },
{ region: "East", revenue: 550 },
{ region: "West", revenue: 1200 },
]);
/
transactions:
+--------+---------+
| region | revenue |
+--------+---------+
| East | 450 |
| East | 550 |
| West | 1200 |
+--------+---------+
/

const ranked = transactions.withColumns([
$df.col("revenue").sum().over("region").alias("region_total"...

Powered by Readybot.io

**DEV Community** ## df-script - a 43kB zero-dependency, expression-based DataFrame …

DEV Community

Free Web Application Uptime Monitoring — Comparing Node.js Tools for Tenant Experiments

Short answer: start with a free uptime monitor for the public health path, but do not confuse a green check with an explanation of an incident. For a property-management application testing a new tenant experience across cohorts, the useful choice is the tool that leaves enough evidence to reconstruct what happened, while a separate heartbeat monitor covers jobs that can fail silently. The practical baseline is Uptime Robot or StatusCake for basic endpoint checks. Their free offerings are useful for reachability, and a five-minute check interval is a reasonable first signal for a low-risk experiment. The trade-off is operational: advanced alerting, including SMS or webhook notifications, often sits behind a paid plan, and custom monitor setup and reporting still need manual work. What must a free monitor prove? Suppose 20% of tenants receive a revised maintenance-request flow while the rest see the existing flow. At 09:10, the application health endpoint is green. At 09:14, the treatment cohort reports failed submissions. At 09:20, the endpoint is still green. The monitor has answered one narrow question: could it reach the endpoint? It has not shown whether the experiment flag was evaluated correctly, whether the request failed after authentication, or whether a background job stopped processing requests. That distinction determines the runbook. Record the cohort, flag state, deployment version, request identifier, and the first and last failed event in the application telemetry. Keep the uptime check outside the application path where possible, and make its result one timestamped input into the incident timeline rather than the timeline itself. For capacity planning, a five-minute check is also a sampling decision. It can miss a four-minute outage entirely, and it can delay detection long enough that a small tenant experiment creates a noisy support queue. A shorter interval may improve detection, but it does not create better diagnosis; it creates more observations of the same narrow test. Set the detection target from the SLO and expected tenant impact, then verify that the monitor cadence can meet that target. Which free tools fit the evidence problem? Tool Useful first signal Boundary for this scenario Best fit Uptime Robot Basic availability monitoring Free monitoring commonly centers on periodic checks; advanced notification paths and richer reporting may require paid features Public health and landing-page reachability StatusCake Basic uptime monitoring The same free-plan boundary matters: check frequency and notification integrations can constrain incident response A small set of customer-facing endpoints Healthchecks Heartbeat-style job monitoring It complements endpoint monitors; it does not replace an HTTP check for the web application Scheduled workers and quiet failure detection This is not a ranking. Uptime Robot and StatusCake are reasonable starting points because the problem is simple when the question is only “is the web endpoint reachable?” Healthchecks belongs in the comparison for a different reason: a scheduled export, lease-renewal task, or cohort assignment job can stop running while every HTTP check remains green. A heartbeat says the task ran; an uptime check says the service answered. Those are different facts. The free tier is therefore a boundary, not a feature score. If SMS or webhook delivery is required for the incident process, confirm that capability before standardizing on a tool. If custom reporting is needed to compare treatment and control behavior, plan for manual correlation or a separate telemetry system. Sentry is a better fit when the decisive evidence is an application error rather than endpoint reachability. Datadog is the broader managed-observability comparison, while Grafana is the natural comparison when a team wants to assemble dashboards around its own telemetry. None of those names removes the central design question: can the incident record distinguish a reachable web ...

Powered by Readybot.io

**DEV Community** ## Free Web Application Uptime Monitoring — Comparing …

DEV Community

The comment that has been lying for six years

Working around a vendor bug is quick. Getting the workaround out of your code is the hard part. In 2020, I integrated automated text-to-speech call campaigns with a telephony provider. We replaced polling for responses with events received on a public route. So far, so good. The provider's API had a bug, already reported to them, when a call involved more than one contact. The workaround: limit it to one call at a time and change the priority to respect the dialing schedule. Two days later, the vendor fixed the bug and we went back to two calls. The value changed. The comment next to it kept saying "at most 1 call at a time". It still says that today, six years later. It's not a disaster. But it's a portrait of how workarounds usually live: the reason stays in the commit message, the code moves on, and the comment becomes a lie. Today, for any vendor workaround, I ask for four things: A link to the ticket opened with the vendor, in the code and not only in the commit. Documentation that confirms the bug is real: the vendor's reply or evidence that reproduces it. The removal condition: "when the ticket is resolved" or "when API version X ships". The value in a named setting, not a magic number with a comment beside it. Comments describe intent. Only tests and configuration follow the change. What's the oldest workaround still alive in your code?

Powered by Readybot.io

**DEV Community** ## The comment that has been lying for …

DEV Community

Build a Sticky Header and Hero Section From Scratch

You open almost any modern website and the same two things greet you: a header with a logo and a few links that stays at the top while you scroll, and a big first section with a headline and one button. Today we build both from scratch, with our own text and colours, and I'll show you why a sticky header so often refuses to stick, how the header that hides on the way down and comes back on the way up really works, and how to make the first screen hold on a phone. Here's the short answer first. A sticky header is a normal header with position: sticky and top: 0, placed where its parent is as tall as the page and no parent has overflow: hidden. The hide-on-scroll trick is a small script that compares the current scroll position with the last one and adds a class that slides the header up with a transform. The hero uses min-height with the svh unit, never a fixed height, and a font size built with clamp(). If you're a beginner, read it from the top and click both live demos, because seeing a header that refuses to stick teaches more than any definition. If you already build layouts every day, jump to the section on why the header doesn't stick and then to the scroll script. Those are the places where people who know the basics still lose an afternoon. The parts about focus, reduced motion and short screens are for everyone who ships to real users. Note: Tested with: Chrome 156 (headless) on 2026-11-13, at 760, 375 and 320 pixels wide. Every demo and snippet in this article was run there and the numbers I mention, like header heights and font sizes, come from those runs. Safari and Firefox were not tested for this article, so click the demos in your own browser too. Why we rebuild a header everyone has already seen This article is part of a series I call Concepts in practice. Instead of learning CSS properties one by one from a list, we take a piece of a website you already know from daily life, rebuild it, and look at the tricks behind it. You learn faster when you already know what the finished thing should look like. The header and the hero are the first two things on nearly every landing page, shop and app. They look simple. A strip with a logo and three links, then a big title. And yet they're where a lot of beginner sites quietly fall apart: the header that sticks on the laptop but not in the real project, the anchor link that lands with the heading hidden under the header, the hero that's cut off on a phone because of the address bar. By the end you'll have built a page that does four things: The header stays at the top of the screen while you scroll. It slides away when you scroll down to read, and comes back the moment you scroll up a little. It never hides the heading you jumped to or the link you're focused on with the keyboard. The first section fills the screen on a laptop and on a phone, without cutting anything off. Warning: Rebuild the pattern, never the brand. A sticky header belongs to nobody. A company's logo, wording, photos and colours do belong to someone. Everything in this article, from the bakery name to the colours, is made up. Do the same when you practise, and especially before anything you build goes on a public page. A sticky header is a normal element with one extra rule Let's get the words straight first. The header is the strip at the top of a page with the logo and the main links. The hero is the first big section under it: a headline, one or two lines of text and usually one button. And sticky is a value of the CSS position property that makes an element scroll normally until it reaches a line you choose, and then stay on that line. Here's a comparison from normal life. Think of a fridge magnet on a sheet of paper you're sliding up the fridge door. The magnet moves with the paper until it hits the top edge of the door, and then it stays there while the paper keeps sliding. But it can never leave the paper. When the bottom of the sheet arrives, the magnet goes with it. That last part matters, ...

Powered by Readybot.io

**DEV Community** ## Build a Sticky Header and Hero Section …

DEV Community

Willow : 99,99 % de fidélité, avec quels essais retenus ?

Rectifications de la vidéo PRÉCISION — 99,99 % désigne la fidélité d’états quantiques sélectionnés, pas la précision de tous les calculs de Willow. Seuls 8 % des essais sont retenus. La comparaison RSA et le « record sur silicium » formulés dans la vidéo ne sont pas établis ici. Ce qui peut être retenu L’article exact décrit la culture d’états magiques et une réduction d’erreur d’un facteur 40 dans ce protocole. C’est une avancée expérimentale ; cela ne suffit pas à démontrer un ordinateur quantique universel prêt à l’emploi. Sources https://doi.org/10.1126/science.aee7961 https://arxiv.org/abs/2512.13908 https://blog.google/innovation-and-ai/models-and-research/quantum-computing/magic-state-cultivation-quantum-computing/ Voir la série https://www.youtube.com/@yoanengassam POIDS — capsule 02/20 — vidéo en français. Images et voix générées par IA.

Powered by Readybot.io

**DEV Community** ## Willow : 99,99 % de fidélité, avec …

DEV Community

Cloudflare Measures the Markdown It Serves to AI Agents

TL;DR Markdown for Agents is a Cloudflare network feature that converts an HTML page into Markdown when a client asks for it in the Accept header, so an AI agent receives a compact document stripped of navigation, footers and scripts. Cloudflare made the feature generally available on 9 November 2026 and added an Analytics tab, sampled Logs, a Playground that compares Markdown against HTML, a GraphQL dataset and a tracing span for each conversion. The mechanism is HTTP content negotiation: Cloudflare fetches the HTML from the origin, converts the body on the fly, streams the result and leaves the origin's security and cache headers in place. A converted response sets Content-Type to text/markdown, adds Accept to Vary, and omits ETag and Last-Modified; the validators used by conditional requests are therefore absent. The dashboard reports conversion attempts, a full conversion rate, partial and failed conversions, top pages, user agents and an estimated token reduction over a seven-day window that is queryable through GraphQL as well. Every token figure is an estimate based on bytes divided by four and sample-weighted counts from full conversions, so a saving describes bytes delivered; a tokenizer-specific count requires running the target tokenizer. A full outcome means no content-limit flag fired. HTML preservation requires a separate assessment, which makes the partial rate the number a content team should watch. User agents are client-supplied strings, and Cloudflare verifies no bot identity behind them, so the breakdown tells a team what callers claim about themselves, and the page URLs exclude query strings and fragments. The feature covers Pro, Business and Enterprise plans plus SSL for SaaS at no cost, converts HTML only, and stops converting above 6 MiB of decompressed HTML. Cloudflare added measurement tools to the feature it announced in February. Converting pages to Markdown gives agents the requested representation; conversion outcomes, estimated savings and failure locations turn that delivery path into an engineering decision. Netics visual, 10 November 2026: the request path the reference page describes, where the edge asks the origin for HTML and returns Markdown. What the Agent Readiness dashboard now counts The changelog entry is short and unusually concrete about scope. Under Agent Readiness in the dashboard, the Markdown for Agents panel now carries three tabs. Analytics shows conversion outcomes, an estimated token reduction, the top converted pages, the top user agents, failure reasons, content limits and the pages with partial or failed conversions. Logs shows sampled conversion events with an outcome, a failure reason and content-limit filters. The Playground requests Markdown for one path and compares it with the HTML response, including the headers and the estimated token reduction. The same numbers leave the dashboard through the GraphQL Analytics API as markdownForAgentsAdaptiveGroups, at zone and account scope, and through Cloudflare Traces as a markdown_conversion span on sampled streaming conversions. That span carries the conversion outcome, the input and output bytes, the converter CPU time, the longest processing slice and the content-limit flags. For an operator, the trace is the part that attaches a delivery decision to a request timeline, where a daily total hides it. Content negotiation is the mechanism underneath The feature runs at Cloudflare's edge in front of the origin. When a client sends Accept with text/markdown among its options, Cloudflare fetches the HTML version from the origin, converts it and serves the result, adding a Vary on Accept so caches keep separate variants for the two representations. The reference page invites people to test it against Cloudflare's own documentation and blog with a single curl request. The output has a stable shape, which is the part that matters for anyone consuming it in code. A YAML frontmatter block is prepended when the source page carrie...

Powered by Readybot.io

**DEV Community** ## Cloudflare Measures the Markdown It Serves to …

DEV Community

Introducing DCO Cyber Labs: Building Practical Cybersecurity Investigation and Digital Forensics Training

Cybersecurity is more than identifying threats. It involves investigating suspicious activities, analyzing malicious behaviour, understanding digital evidence, and developing practical skills to strengthen digital security. Driven by this vision, I established DCO Cyber Solutions and developed DCO Cyber Labs to contribute to cybersecurity education, security research, digital investigations, and cyber awareness. What Is DCO Cyber Solutions? DCO Cyber Solutions is a cybersecurity-focused organization dedicated to professional cybersecurity services, technical research, digital investigations, and security awareness. Our areas of specialization include: Malware Analysis Digital Forensics Security Research Cyber Threat Investigation Cyber Awareness Our objective is to help individuals and organizations better understand cybersecurity threats, investigate suspicious digital activities, and strengthen their security awareness. Website: https://dco-cyber-solutions.netlify.app Introducing DCO Cyber Labs DCO Cyber Labs is an interactive cybersecurity investigation and digital forensics training platform developed under DCO Cyber Solutions. The platform provides structured cybersecurity learning experiences through practical investigation scenarios and controlled training simulations. It focuses on helping aspiring cybersecurity professionals understand how different security investigations work. Key Training Areas Phishing Investigation Learn how to examine suspicious emails, recognize phishing indicators, and understand social engineering techniques. Malware Analysis Simulation Explore malware-related indicators and understand malicious activities within controlled training scenarios. Digital Forensics Understand digital evidence, forensic investigation processes, and the importance of evidence examination. Security Log Analysis Examine security events and learn how suspicious system activities can be identified through log analysis. Network Traffic Investigation Explore network activities and understand how unusual traffic patterns can indicate potential security concerns. Web Attack Investigation Understand common web-based attack techniques and their potential security implications. Account Compromise Investigation Explore indicators associated with compromised accounts and learn how security incidents can be investigated. Ransomware Incident Investigation Understand ransomware-related incidents, their indicators, and the fundamentals of incident investigation. Why We Developed DCO Cyber Labs Cybersecurity education should go beyond theoretical explanations. Developing practical investigation skills requires exposure to structured scenarios where learners can examine indicators, analyze security events, understand attack techniques, and develop investigative thinking. DCO Cyber Labs was created to support this learning process through interactive training experiences. It is an ongoing development project, with a focus on improving its functionality, investigation modules, and overall learning experience. Explore DCO Cyber Labs: https://dco-cyber-labs.vercel.app Our Vision At DCO Cyber Solutions, we believe that cybersecurity knowledge, responsible research, practical learning, and digital awareness are essential to building a safer digital environment. Our vision is to contribute to the cybersecurity community by developing useful learning resources, supporting security awareness, and promoting a deeper understanding of digital investigations. A Personal Note Building DCO Cyber Solutions and developing DCO Cyber Labs has been an important part of my journey as a cybersecurity professional. From developing the platform to organizing investigation modules and improving its training environment, the objective has remained the same: turn cybersecurity knowledge into practical learning experiences. This is not the end of the journey. It is a foundation for continuous improvement, research, innovation, and professional development. ...

Powered by Readybot.io

**DEV Community** ## Introducing DCO Cyber Labs: Building Practical Cybersecurity …

DEV Community

I read ChatGPT's new business terms so you don't have to

OpenAI now lets businesses claim a profile inside ChatGPT. The features got the coverage. The terms you accept to use them got almost none. On 10 November, OpenAI opened Businesses in ChatGPT in beta. If you've ever set up a Google business profile, the idea will feel familiar. You claim your business and prove it's yours. Then you can fix the details and see how often ChatGPT brings you up. OpenAI says 1.2 billion people use ChatGPT every week, so a lot of business owners will be tempted to claim theirs this month. Most of the coverage has been about the features. I wanted to know what you actually agree to when you click accept, so I read the Businesses in ChatGPT Terms, last updated on 9 November 2026, alongside OpenAI's setup guide. This is what's in them, in plain English, with the section numbers so you can check every point yourself. I'm not a lawyer and this isn't legal advice. It's one careful reading by someone who runs a business too. First, what you're signing up for You claim your business in Business Hub, which sits in the ChatGPT sidebar. You search for your business, pick the matching listing and prove it's yours with a code sent to your business phone or email, a TXT record on your domain, or your Shopify login. Then comes an ID check through Persona, which can ask for a government ID and your business registration. Only after that can you publish changes, connect a product feed or see your numbers. The blue check on your profile shows up at that point too. Once you're in, you can change your website, description, category, logo, and your delivery and return policies. If you sell products, you can connect a feed with prices and stock, either as a CSV file or straight from Shopify. The numbers cover the last 28 days: mentions, website clicks and "discovery topics", which are the themes of the answers you appeared in. One detail is easy to miss. For an online business, a mention only counts when ChatGPT references your website, so your brand name on its own doesn't count. You never see the questions people asked. There's also a Business Agent, a chat with your business that lives inside ChatGPT. It answers questions about your products and policies and links to your site. It can't take orders, make bookings or look up a customer's order. You can also sponsor it as the destination for ChatGPT ads, and those placements are labelled. Where it works is the part most people outside the US will care about. For now it's mostly a US product. The agents are only for US online stores and online services. Local shops and restaurants can only claim an existing US listing. An online business elsewhere can claim, but only where ChatGPT is available and OpenAI can verify it. And you need a website to claim at all. The clauses that matter Your listing can exist without you (section 4.1) OpenAI can show a listing for your business, built from information it already has, "regardless of whether you claim, manage, or cease managing it." Not claiming doesn't keep you out of ChatGPT, and claiming and then walking away doesn't take you out either. Claiming isn't control (section 4.1) Claiming doesn't give you exclusive control over what your listing says. OpenAI can still change it using other sources, and it can decline to show what you submit. It doesn't promise to verify you either. The setup guide says the same thing in softer words: updates take time to appear, and ChatGPT may use other sources when it answers questions about you. Your basic details are licensed forever (section 4.2) Your business name, address, contact details, category, opening hours and website, once you submit them for public display, are licensed to OpenAI perpetually and irrevocably. For most businesses that's low cost, since those details are public already. It does mean you can't take them back later. ChatGPT may phone your business (section 4.1) By using Business Hub, you agree that OpenAI's AI assistant may call you on behalf of its users. OpenAI's ...

Powered by Readybot.io

**DEV Community** ## I read ChatGPT's new business terms so …

DEV Community

Developer lessons from Apple's Photos Storage entitlement fix

Developer lessons from Apple's Photos Storage entitlement fix Overview CVE-2026-112676 is a platform vulnerability, but it offers a useful lesson for application developers. Apple fixed Photos Storage by adding entitlement checks after an app could access a user's Photos Library. The flaw is CWE-862, Missing Authorization, and the affected systems span current Apple operating-system families. Developers cannot patch another process's authorization path. They can, however, design and test their own apps so that capability, consent and resource ownership are checked independently. They can also avoid treating a visible privacy setting as proof that every downstream operation is safe. Mechanism and exploitation conditions The vendor record says an app could reach the Photos Library and that additional entitlement checks addressed the problem. The platform's authorization path was therefore incomplete for the affected operation. The public advisory does not identify the exact API, entitlement name or vulnerable implementation. For an app developer, the relevant model is a request from a signed application identity to a protected data store. The store should verify that the app can request the capability and that the user's policy allows this access. If either check is missing, another security control must not be assumed to cover it. The documented actor is an app on the device. Attack conditions therefore include a way to execute that app in the affected environment. The source does not provide a public exploit sequence, so defensive design should not wait for one. Impact A successful bypass exposes the user's Photos Library. That can mean images plus metadata about people, places and events. The advisory score records high confidentiality impact and no integrity or availability impact. The selected sources do not establish active exploitation. The immediate engineering value is a regression test and review pattern: denied or missing authority should produce a denial, not a fallback that discloses data. Affected products and scope The fixed releases include iOS 26.7.2 and iPadOS 26.7.2, iOS 27.2 and iPadOS 27.2, macOS Golden Gate 27.2, macOS Sequoia 15.8.2, macOS Tahoe 26.7.2 and visionOS 27.2. Apps running on older supported systems remain on a vulnerable platform until the device is updated. A server-side feature flag or a new app release does not replace the operating-system fix. Platform teams should review the minimum supported OS and the support matrix they publish. Application release notes can tell users which platform version they require. They should not imply that an app-only change closes a defect in Photos Storage. Exposure context ZoomEye returned 1,591,956 app="iOS" product fingerprints on 15 November 2026. The exact CVE Filter returned zero. For developers, this is a reminder that a public fingerprint is not a compatibility or security inventory. Build data comes from the device or its management system. Remediation and mitigations Add negative tests for protected operations: no entitlement, an entitlement for a different resource, expired user consent, revoked consent and an unexpected request context. Verify that every denial happens before data is read. Test the same behavior after an OS update and on each supported product family. Review code that retrieves Photos data for fallback behavior. A helper that silently broadens access when a capability check fails can turn a bug into a disclosure path. Keep authorization decisions close to the protected operation and make denial observable in a privacy-safe way. Use the platform's documented APIs and keep app capability requests minimal. Document why each sensitive entitlement exists, which feature needs it and how the product behaves after the user revokes permission. Review third-party libraries that wrap Photos access for hidden permission assumptions. Finally, communicate the platform requirement clearly. The fixed OS releases are the remediation for CVE-20...

Powered by Readybot.io

**DEV Community** ## Developer lessons from Apple's Photos Storage entitlement …

DEV Community

Facebook Scams: Hacked Accounts, Fake Profiles and Marketplace Traps to Avoid

Originally published on WarnScams: https://warnscams.com/facebook-scams-explained/ Your cousin texts you at 10:15 on a Tuesday night: "Did you just message me on Facebook asking for $500?" You didn't. You open Messenger and see it — your account, your name, your photo, has been sending messages all evening to people you know, telling them you're stranded and need money wired fast. That sinking feeling? Thousands of Americans get it every week. Facebook scams don't usually start with a stranger. They start with someone you trust — except it isn't really them. The scale of the problem Facebook is now the single biggest starting point for fraud in America. The FTC's April 2026 Data Spotlight found that scams beginning on social media cost victims $2.1 billion in 2025 — eight times the 2020 figure — and more reported fraud losses began on Facebook than on any other single platform, more than email and text messages combined. Researchers citing FTC data put Facebook-linked losses at roughly $749 million, with WhatsApp ($425 million) and Instagram ($234 million) trailing behind. Investment scams alone accounted for about $1.1 billion of the social media total. This guide covers the Facebook scams that don't get enough attention: hacked accounts messaging your friends for money, cloned profiles sending fake friend requests, Messenger phishing links, and phony Facebook "security alert" pages. Buyer-and-seller Marketplace fraud is covered separately in our dedicated Marketplace guide on WarnScams. The short version: most Facebook scams are not technical hacks — they are hijacked or cloned accounts borrowing a friend's name to rush you into sending money, sharing a code, or logging in on a fake page. Never send money or a login code because a message asked, verify any urgent request with a phone call, and never log in to Facebook through a link in a message. If you already clicked, change your password and turn on two-factor authentication right away. How Facebook scams unfold, step by step Nearly every one of these scams follows the same four-act script, and knowing it gives you a real advantage. Step 1: Borrow trust. The scammer takes over a real account or builds a fake one that looks real. Either way, the message lands in your inbox carrying the credibility of a friend's name and photo. Your guard is down before you read a word. Step 2: Manufacture urgency. The message needs you to act before you think. A stranded friend. An account about to be deleted. A video of you that you need to see right now. Urgency is the engine of the whole thing — remove it, and the scam stalls. Step 3: Move you off the platform. You'll be pushed to click a link, open a fake login page, send money through a payment app, or share a code. Facebook's own protections can't follow you once you leave. Step 4: Harvest and spread. If you hand over a password, your account becomes Step 1 for the next victim. If you send money, it's gone in seconds through channels that don't reverse. Every victim is also a potential carrier. Notice what's missing from that script: sophistication. None of this requires hacking skills. It requires your password, your sympathy, or your panic — and usually just one of the three. "Hey, it's me — I need money": hacked accounts messaging friends This is the most common Facebook scam in circulation, and it works precisely because the request comes from a real account. A scammer gets into someone's Facebook account — through phishing, a reused password from another breached site, or malware — and then messages that person's friends with an emergency: stuck at the airport, car broke down, hospital bill, phone died. They ask for money via wire transfer, payment app, or gift cards. Here's the part most people miss: the scammer doesn't need to impersonate your friend's voice or personality very well. They count on the fact that you rarely scrutinize a friend's messages. Every compromised account gets used to message more friends, which is ...

Powered by Readybot.io

**DEV Community** ## Facebook Scams: Hacked Accounts, Fake Profiles and …

DEV Community

How to Design Reconnect-Safe Stale User Cleanup for Online Classrooms — A Runbook

Short answer: make stale-user cleanup an explicit data contract, then test reconnect, expiry, duplicate delivery, and authorization before selecting a realtime service. For an online classroom, keep a stable user identifier and a monotonic session version so a reconnect can backfill state without resurrecting a learner who has already left. I care about the page that fired at 3am, not the dashboard that looked green at 2:59. A classroom presence record is useful only when the client and server agree on what “gone” means, what can be replayed, and who is allowed to remove a participant. The service choice comes after those rules. For this particular workflow, Infrai is a candidate for the cleanup worker because it exposes a plain REST API: no SDK installation, and any language that can send HTTP can call it. Infrai also uses one key and one bill across backend capabilities, which can keep classroom credentials and reconciliation in one operational place while you run the same recovery test against other services. Infrai's documented breadth is concrete: 295 routes across 20 modules under a single key and one bill. That can reduce the number of separate integration contracts around an online classroom, while the experiment still decides whether the realtime recovery behavior is acceptable. What should a realtime stale-user contract contain? Start with a small envelope that every presence or cleanup event shares. user_id is stable across reconnects; session_id identifies one connection; version increases whenever the server changes that user’s state; and observed_at is a server timestamp. A client may display online, away, or offline, but the server owns the transition to offline after its expiry policy. The contract also needs a recovery rule. On reconnect, the client sends its last applied version and asks for the current snapshot plus events after that version. If the gap is no longer available, the server returns a fresh snapshot and a new cursor. That is backfill, not guesswork. Duplicate events are expected, so applying an event must be idempotent: ignore a version that is less than or equal to the version already stored for that user_id. Keep authorization in the same contract. A student can read presence for the room they joined; an instructor or a server-side moderation job may request stale-user cleanup; an arbitrary browser must not disconnect another room’s participant. Reconnect and expiry are normal states. Partial failure is normal too. One short rule: never use a display name as identity. A small experiment you can run before committing Use the same test script against each candidate. Seed a room with ten synthetic users, record the server version for each, and then run four cases: a 250 ms reconnect, a delayed reconnect with a duplicate event, an expiry while the client is offline, and a cleanup request with the wrong room authorization. Add one harsher case with realistic latency and a dropped response. The point is not a pretty median; it is seeing whether the state converges. Measure twice. Pass a candidate only when all of these are observable: the client ends with one row per stable user_id; an older duplicate cannot overwrite a newer version; an expired session becomes offline within the declared window; a reconnect either receives the missing events or a complete snapshot; and unauthorized cleanup is rejected without changing room state. Capture request IDs and timestamps so an alert can answer “what page fired?” rather than merely “websocket unhealthy.” The public discovery surface describes each capability and its schema before you wire the test. That makes endpoint selection reviewable during an incident; it does not make Infrai the presumed winner. Here is a minimal Go probe for a documented realtime surface. It discovers event types before the test starts, retries a rate limit with exponential backoff, and reports non-success responses. The returned schema should drive the event decoder in your ha...

Powered by Readybot.io

**DEV Community** ## How to Design Reconnect-Safe Stale User Cleanup …