You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
150 lines
27 KiB
150 lines
27 KiB
# Sincronización temporal y equidad de respuestas — propuesta v2
|
|
|
|
Estado: investigación y diseño, **6 de octubre de 2026**. Complementa el [perfil multidispositivo](multi-device-profile.md), el [protocolo del motor](format-and-protocol.md) y la [API de plataforma](../platform/api-and-events.md). No existen todavía esquemas, mensajes ejecutables ni runtime para este perfil. Los nombres y límites siguientes son propuestas propias; no describen una integración con los productos citados.
|
|
|
|
## 1. Qué se debe garantizar
|
|
|
|
El servidor mantiene un único estado confirmado, plazos y resultado. Cada juego declara cómo importa el tiempo: por turnos, respuestas dentro de una ventana o reacción. La distribución por proyección y la sincronización de reloj son problemas distintos. Recibir la misma revisión no significa ver la pregunta en el mismo instante.
|
|
|
|
Para «el primero que contesta» no se ordenan respuestas únicamente por llegada al servidor, adquisición del bloqueo SQL o confirmación. Esos órdenes incluyen transporte y carga de servidor. Tampoco se acepta como autoridad un `clickedAt`, un ping o un cronómetro enviado por el navegador.
|
|
|
|
**Límite físico:** una conexión de Internet y un navegador no permiten comprobar exactamente cuándo se mostraron los píxeles ni cuándo pulsó una persona. RTT no revela por separado ida y vuelta; las rutas pueden ser asimétricas. El retardo de renderizado y de la TV también importa. Compensar reduce sesgo bajo condiciones medidas; no acredita igualdad perfecta ni permite compensar un corte arbitrariamente largo. Esta conclusión es nuestra inferencia a partir del modelo temporal de [NTP, RFC 5905](https://www.rfc-editor.org/rfc/rfc5905.html#section-8) y las limitaciones que explican [Riot](https://www.riotgames.com/en/news/peeking-valorants-netcode) y [Photon](https://doc.photonengine.com/fusion/v2/manual/advanced/lag-compensation).
|
|
|
|
El requisito se concreta así: no otorgar una ventaja por el mero orden de transporte; admitir empate cuando la medición no permite distinguir; y neutralizar una ronda afectada por un fallo temporal fuera del presupuesto. Si se exige que la velocidad de red no pueda decidir el resultado, se usa acierto sin clasificación por velocidad y, cuando haga falta, sin tiempo límite. Un ranking exacto de reacción bajo cualquier lag no es una garantía publicable.
|
|
|
|
## 2. Técnicas publicadas por la industria
|
|
|
|
Fuentes primarias consultadas en la fecha indicada. Los artículos históricos describen técnicas; su fecha no acredita la configuración actual de un juego comercial.
|
|
|
|
La guía enlazada de Unity corresponde a 2.4.2 y avisa que ese sitio ya no se actualiza; se usa para explicar el modelo, no para elegir una versión actual del SDK. Remite a la [documentación oficial del paquete](https://docs.unity3d.com/Packages/com.unity.netcode.gameobjects@latest/?subfolder=/manual/index.html). La página de reloj de Photon Fusion Core consultada indica actualización del 19 de agosto de 2026.
|
|
|
|
| Técnica y fuente | Qué resuelve | Aplicación propuesta aquí |
|
|
| --- | --- | --- |
|
|
| Reloj de red y ticks: [Unity](https://mp-docs.dl.it.unity3d.com/netcode/current/advanced-topics/networktime-ticks/) y [Photon Fusion Core](https://doc.photonengine.com/fusion-core/v3/manual/time). | Estiman tiempo de servidor y coordinan eventos; los ticks discretizan simulación/transmisión. | Cuenta atrás y plazos comunes; estimación con calidad y época. Un tick no prueba el instante real de pulsación. |
|
|
| Predicción y reconciliación: [Riot, netcode de VALORANT](https://www.riotgames.com/en/news/peeking-valorants-netcode). | El cliente responde visualmente antes de recibir confirmación y corrige diferencias con la autoridad. | Feedback local de pulsación y estado pendiente; ganador, acierto y puntuación esperan al servidor. |
|
|
| Buffer e interpolación: [Riot](https://www.riotgames.com/en/news/peeking-valorants-netcode). | Suavizan llegadas irregulares, a costa de añadir demora. | Animación pública suave; los controles no esperan a una animación. Presupuesto separado de renderizado y transporte. |
|
|
| Compensación con historial: [Photon Fusion, lag compensation](https://doc.photonengine.com/fusion/v2/manual/advanced/lag-compensation). | Consulta posiciones pasadas para juzgar una acción respecto a la vista del atacante; tiene consecuencias para otros jugadores. | Inspiración para conservar contexto temporal. Rebobinar hitboxes no resuelve directamente quién respondió antes a una pregunta. |
|
|
| Lockstep con espera y rollback: [GGPO, documentación del SDK](https://github.com/pond3r/ggpo/blob/master/doc/README.md). | Esperar inputs introduce demora; predicción, restauración y resimulación la ocultan en juegos deterministas. | Perfil futuro para acción continua. Una respuesta desconocida no se predice y un resultado anunciado no se revierte como una animación. |
|
|
| Cambiar la regla de puntuación: [Kahoot, cálculo de puntos](https://support.kahoot.com/hc/es/articles/115002303908-C%C3%B3mo-funcionan-los-puntos). | Publica puntuación por tiempo y un modo de precisión sin efecto de velocidad. | Ofrecer acierto dentro de ventana o sin reloj cuando la equidad importa más que ordenar milisegundos. No atribuimos a Kahoot un protocolo de compensación no documentado. |
|
|
|
|
La reducción de latencia mediante ubicación de servidores, rendimiento y colas pequeñas complementa estas técnicas; Riot explica esos factores. No copiamos su frecuencia de simulación ni la convertimos en requisito para todos nuestros juegos. Un quiz necesita mensajes de ronda e inputs discretos; emitir 128 actualizaciones por segundo no elimina el trayecto de red.
|
|
|
|
## 3. Propiedades temporales del juego
|
|
|
|
La propiedad propuesta `synchronization` pertenece al paquete y se publica/versiona con las reglas. Cada modo temporal declara `interaction.modes[].synchronizationProfileId`, que debe referenciar un perfil existente; la sala fija ese perfil y sus límites antes de «listo». Omitir la extensión no concede mecánicas de reacción ni compensación por inferencia. El perfil no cambia automáticamente al medir ping. Un anfitrión no modifica retrospectivamente compensación, desempate ni puntuación.
|
|
|
|
| Modelo propuesto | Regla temporal |
|
|
| --- | --- |
|
|
| `turn-based` | Orden por reglas/actor y revisiones. El lag no cambia un resultado de velocidad que el juego no tenga. Plazos expresos siguen el reloj de servidor. |
|
|
| `simultaneous-window` | Respuestas privadas independientes; se evalúan tras la recogida. Acierto sin ventaja por llegada. Permite ventana amplia o ausencia de límite. Es la base recomendada para el primer quiz. |
|
|
| `reaction-compensated` | Estimación temporal acotada, intervalo de incertidumbre y empate entre candidatos indistinguibles. Experimental hasta superar pruebas; no se anuncia como medición exacta. |
|
|
| `real-time` | Necesita contrato propio de tick, input, simulación, predicción/interpolación y posible rollback. Queda pendiente; no se habilita por declarar `TVBoard`. |
|
|
|
|
Fragmento ilustrativo, no paquete instalable ni presupuesto aprobado:
|
|
|
|
```json
|
|
{
|
|
"synchronization": {
|
|
"profileVersion": 1,
|
|
"profiles": [{
|
|
"id": "quiz-window",
|
|
"model": "simultaneous-window",
|
|
"scoring": "correctness",
|
|
"roundDurationMs": 10000,
|
|
"prepareTimeoutMs": 10000,
|
|
"collectionGraceMs": 250,
|
|
"presentationChange": "between-rounds",
|
|
"onTimingFailure": "void-round"
|
|
}]
|
|
}
|
|
}
|
|
```
|
|
|
|
Un perfil de reacción exige además versión del estimador, presupuesto máximo de compensación/incertidumbre, vigencia y mínimo de muestras, fuentes de estímulo admitidas, regla de empate y límite de reinicios. Se prueban valores por juego, infraestructura y dispositivos; no hay un ping universal que garantice equidad. Perfiles/localizaciones con distinta dificultad o duración de lectura requieren validación de contenido además de red.
|
|
|
|
El perfil multidispositivo fija por jugador una fuente autorizada de estímulo: su vista completa, su TV personal o la TV común. `presentationProfile`, fuente, vínculo/generación y política temporal quedan registrados por ronda. Tener varias pestañas no multiplica fuentes, respuestas o presupuestos. No se asume que todos miran la misma pantalla porque usan `TVBoard`; una TV personal remota tiene otra ruta.
|
|
|
|
En reacción, el servidor aplica esa selección a **todas** las suscripciones del asiento, incluidas nuevas pestañas, web/app simultáneas, reconexiones, snapshots y outbox pendientes. Las conexiones secundarias reciben solo una vista de espera/control sin el estímulo, o se rechaza su suscripción si el paquete carece de esa proyección segura. No se puede leer la pregunta en `player-full` y reclamar compensación por otra TV más lenta. Antes de entregar se revalida la generación de la fuente y del mando activo; cambiar de fuente exige el punto seguro de la sección 7. Esto limita rutas de nuestra plataforma, pero no acredita dónde mira una persona ni impide que un cliente manipulado retransmita contenido.
|
|
|
|
## 4. Reloj, medición y autoridad
|
|
|
|
Se proponen intercambios técnicos `time.probe`/`time.sample`, negociados en el binding v2 y permitidos también en TV pasiva. Llevan nonce de un solo uso, `clockEpoch` y marcas del mismo dominio temporal. Se acotan frecuencia, bytes y duración; no son comandos de juego, no incrementan revisiones y no contienen información personal. Un `serverTime` aislado de bienvenida sirve como referencia inicial, no como protocolo completo.
|
|
|
|
En red, `serverTimeMs`, `startAtMs`, `answerDeadlineAtMs`, `collectUntilMs`, `ingressAtMs` y `stimulusReleaseAtMs` son enteros seguros de milisegundos transcurridos desde el origen de `clockEpoch`, no fechas Unix ni cadenas ISO. `c0`/`c3` usan milisegundos monotónicos del cliente; `s1`/`s2`, los del servidor en esa época. La estimación calcula su diferencia de origen. No se restan marcas de distintas épocas/conexiones tras una resincronización. Las fechas operativas duraderas y `issuedAt` de plataforma siguen siendo UTC con `Z`; el tiempo del reloj de ronda es una excepción explícita a esa convención.
|
|
|
|
El cliente usa una fuente monotónica de intervalos: en web, `performance.now()`; en la futura app, un adaptador Dart validado que normaliza unidades/época y detecta suspensión. No se compara el reloj civil del teléfono como autoridad. El [perfil web/nativo](../platform/client-communication-profile.md) conserva el mismo intercambio y reglas, sin dar más crédito por ser Flutter. Con `c0` envío cliente, `s1` recepción servidor, `s2` envío servidor y `c3` recepción cliente, estima:
|
|
|
|
```text
|
|
offset servidor-cliente ≈ ((s1 - c0) + (s2 - c3)) / 2
|
|
RTT de transporte estimado ≈ (c3 - c0) - (s2 - s1)
|
|
```
|
|
|
|
Es un intercambio inspirado en las cuatro marcas de [RFC 5905](https://www.rfc-editor.org/rfc/rfc5905.html#section-8), no ejecutar NTP dentro del navegador. Las marcas se normalizan a unidades comunes de esa época. Se filtran muestras viejas, valores imposibles, colas atípicas y deriva; se conservan distribución, jitter, incertidumbre y frescura, no una precisión ficticia. El reloj visual converge gradualmente; suspender/reanudar una pestaña obliga a resincronizar antes de otra ronda.
|
|
|
|
La estimación cliente sincroniza la presentación; **no autoriza puntuación**. El servidor mide asimismo desafíos/acuse con sus propias marcas y nonce, sin descontar un tiempo de procesamiento que declare el cliente. Conserva un historial acotado de calidad por conexión y ruta de pantalla/controlador. Un acuse no prueba que la persona vio el contenido. Usar mínimo/percentil bajo, varias muestras y congelar el presupuesto antes de revelar limita inflar un pico, pero un cliente puede demorar sistemáticamente acuses: no elimina el engaño. Por eso hay topes, incertidumbre y límites de publicación del perfil de reacción.
|
|
|
|
La partida tiene una autoridad temporal por época, con lease/fencing en caso de varias réplicas. Todos sus ingresos, plazos y estimaciones se normalizan al mismo dominio; nunca se comparan relojes monotónicos de procesos distintos. Se guardan fechas duraderas y estado/generación de ronda para recuperación; [Go documenta que la parte monotónica no se serializa](https://pkg.go.dev/time#hdr-Monotonic_Clocks). Cambio de autoridad o salto de reloj que exceda el presupuesto invalida la ronda de reacción aún sin resolver y crea otra época antes de reanudar, sin adjudicar derrota. Las mediciones efímeras se rehacen; la configuración y resoluciones confirmadas permanecen. Otros perfiles recuperan plazos según su política declarada; si no pueden demostrar admisión correcta, tampoco inventan un resultado.
|
|
|
|
## 5. Protocolo de ronda y distribución
|
|
|
|
Estados propuestos: `preparing → armed → open → collecting → resolved`, con salida `void` por fallo de equidad. Reglas y motor definen la transición; workers duraderos ejecutan plazos con generación y autorización actuales. Requiere una ampliación explícita del contrato de lifecycle v2: no se inventa un callback en el SDK v1.
|
|
|
|
El estado actual viaja en `game.snapshot.context.timing`; `round.prepare`, `round.armed`, `round.open`, `round.resolved` y `round.void` son eventos visibles dentro de `game.snapshot.events`, filtrados por proyección, **no sobres WSS independientes**. Un snapshot basta para recuperar una ronda sin reproducir eventos pasados. El cliente comunica preparación mediante `time.ready` y recibe `time.readiness`, ligados a `clockEpoch`, ronda/generación, suscripción y fuente vigentes. Son acuses técnicos acotados y no prueban visualización física ni permiten a la TV ejecutar una jugada. La autoridad confirma la transición de reglas después de validar esa preparación y las mediciones.
|
|
|
|
1. **Preparar.** `round.prepare` identifica ronda/generación, contrato, recursos públicos y política temporal. Todas las fuentes/controladores necesarios precargan assets y acreditan disponibilidad técnica dentro del plazo; el servidor comprueba también muestras frescas. Una persona con mala conexión no pierde puntos por no llegar a esta barrera. Tras un número acotado de intentos se aplaza/cancela sin resultado, o se propone otra regla compatible y se confirma fuera de la ronda.
|
|
2. **Armar.** `round.armed` distribuye `clockEpoch`, `roundId`, generación, `startAtMs`, `answerDeadlineAtMs` y `collectUntilMs`. Se programa cuenta atrás con antelación. No contiene pregunta secreta, solución ni clave utilizable antes de tiempo. Preparar o armar no concede una oferta de respuesta.
|
|
3. **Abrir.** La transición confirmada publica `round.open` y las ofertas propias. Se registra cuándo el servidor libera el estímulo hacia cada fuente autorizada. Si la pregunta depende de imágenes, texto o audio nuevos, también su entrega pertenece al presupuesto temporal. Programar `startAtMs` no hace que ese contenido llegue simultáneamente: la liberación y renderizado siguen teniendo retardo. Precargar texto secreto y ocultarlo con CSS permitiría leerlo antes; cifrar y enviar la clave después traslada el problema a la entrega de la clave.
|
|
4. **Recoger.** El jugador envía una respuesta mediante `game.command` con `commandId`, `controlGeneration` y oferta/precondición que identifica ronda/generación. Actor y canal se derivan en servidor; la marca cliente, si existe para diagnóstico, no decide validez/posición. Primera respuesta válida por asiento/ronda, protegida con unicidad y recibo duradero. `game.ack` con recibo `applied` solo se emite tras confirmar respuesta sellada, recibo y outbox en una transacción; estar en una cola no equivale a estar aplicada. No anuncia todavía acierto, respuesta ajena o ganador.
|
|
5. **Cerrar y resolver.** Al vencer `collectUntilMs`, una transición confirma evaluación, empate/puntos y outbox juntos, después de la barrera de ingresos descrita abajo. La ventana de recogida permite esperar inputs en tránsito; no se proclama ganador por el primer acuse. No se publican respuestas/corrección antes del cierre si permitirían copiar. TV recibe el resultado público; cada jugador recibe su salida autorizada, todos con la misma revisión y ronda.
|
|
|
|
`answerDeadlineAtMs` es el objetivo visual; `collectUntilMs` es el cierre efectivo de admisión en servidor. La gracia se fija y aplica a todos, está acotada y **no demuestra** que una respuesta recibida en ella se pulsó antes del objetivo. No se valida con `clickedAt`. El perfil de ventana puntúa acierto, sin premio por milisegundos; si el presupuesto no cubre la entrega/estabilidad, se aplica la política de incidente de la sección 7. Una ventana sin límite evita convertir la demora de red en velocidad puntuable, aunque sigue necesitando política operativa de desconexión.
|
|
|
|
En el primer punto confiable de recepción se asigna `ingressAtMs`, antes de esperar bloqueo de sala o cola de reglas. Solo registros internos autorizados pueden suministrarlo. La recepción y su identidad se persisten de manera recuperable para no perder una respuesta llegada a tiempo al caer el nodo; el cierre drena ese ingreso duradero o usa una barrera que demuestra que no quedan candidatos anteriores. No basta comparar el momento del commit. Fallar esa garantía neutraliza la ronda; nunca se sustituye por la fecha afirmada por el cliente. Hay que medir también cola del proxy/transporte y del ingreso antes de la marca.
|
|
|
|
La admisión usa una única generación de autoridad vigente; una réplica con lease vencido no puede agregar candidatos. La barrera de cierre sella esa generación y drena todos los ingresos admitidos hasta el límite antes de resolver. Pasar de `open` a `collecting` no invalida las ofertas de respuesta ni incrementa su época de precondición antes de procesar esos candidatos: una respuesta puntual no se rechaza por haberse retrasado SQL. Una caída entre recepción y persistencia que impida demostrar completitud se trata como incidente, nunca como prueba de que nadie respondió. La transferencia de mando se serializa con esa misma barrera.
|
|
|
|
Las respuestas simultáneas usan precondición de ronda y revisión propia de actor, según el modelo de [concurrencia del motor](../game-engine-proposal.md#10-concurrencia-sin-conflictos-innecesarios). Que otro responda no invalida todas las ofertas pendientes ni fuerza a resincronizar por una revisión global ajena. Los recibos sobreviven a cierres y cambios de presentación; reintentar no cambia el instante de ingreso ya registrado ni permite elegir otra respuesta.
|
|
|
|
Todos los mensajes de ronda se envuelven en la revisión/suscripción/proyección negociada del perfil multidispositivo. Las mediciones y créditos por jugador no se difunden al tablero. `game.snapshot` incluye el estado temporal autorizado y el tiempo actual: reconectar no reproduce cuenta atrás antigua, no reinicia el plazo y no vuelve a conceder respuesta. Ningún animador, idioma o notificación retrasa el habilitado de controles respecto al contrato.
|
|
|
|
## 6. Reacción compensada: propuesta experimental
|
|
|
|
Esta variante queda pendiente de fixtures y pruebas adversariales. No se habilita como forma inicial de quiz ni como ranking competitivo por haber documentado el algoritmo. La industria compensa con compromisos; no hemos encontrado en las fuentes una garantía general de orden humano exacto con navegadores no confiables.
|
|
|
|
Se congela antes de abrir el estimador y el máximo de compensación de cada ruta. Una desconexión o aumento de RTT durante la pregunta no concede más crédito. Una ruta por encima del máximo permitido no se trata como una respuesta lenta perdedora: aplica la política de ronda neutral, aplazamiento o variante aceptada. El servidor reduce sesgo según la fuente fijada:
|
|
|
|
| Fuente de la pregunta | Trayectos que afectan a comparar reacción |
|
|
| --- | --- |
|
|
| Una TV física común para todos | La revelación en esa TV es común; se estima el trayecto ascendente de cada móvil. Usar `RTT/2` implica simetría aproximada y exige incertidumbre. |
|
|
| Vista completa individual que revela al recibir contenido | Bajada del estímulo + renderizado + subida de la respuesta. Para el mismo dispositivo, descontar aproximadamente un RTT puede estimar reacción mejor que descontar solo medio RTT; no cubre jitter ni pantalla. |
|
|
| TV personal con móvil distinto | Bajada y renderizado de su TV + subida de su móvil. El RTT del móvil por sí solo no describe esa cadena. |
|
|
| Contenido público previamente conocido con apertura programada | Incertidumbre del reloj/apertura y subida del input. Solo sirve cuando conocer antes ese contenido no permite ventaja. |
|
|
|
|
Para fuente individual, `reactionEstimateMs = ingressAtMs - stimulusReleaseAtMs - estimatedDisplayDelayMs - estimatedInputDelayMs`. Cada componente tiene tope y margen; no se resta ciegamente el RTT a todos los casos. Para TV común, su demora compartida no define el orden relativo: se compara ingreso menos subida estimada. El retardo de pantalla física no medido impide prometer precisión extrema. Mezclar TV remota y vista completa en reacción requiere presupuestos de presentación validados; si no los hay, el paquete rechaza esa combinación o emplea ventana sin clasificación por velocidad.
|
|
|
|
La ruta de pantalla incluye el [dispositivo externo y su vía de acceso](multi-device-profile.md#televisores-y-dispositivos-externos): receptor Cast directo, app de TV, Silk, HDMI o duplicación. En duplicación, el acuse/reloj del navegador no mide cuándo aparece su imagen en la TV; tampoco lo mide el RTT del mando. No se aplica una compensación fija tomada de otra plataforma. Para fuentes individuales sin presupuesto de presentación validado se usa ventana sin premio por velocidad o se rechaza esa combinación de reacción. Una TV común conserva la revelación compartida, pero su demora puede afectar plazos y preparación. Cambiar de receptor/vía exige nueva generación y preparación entre rondas.
|
|
|
|
Cada respuesta correcta obtiene un **intervalo estimado**, no un instante demostrado: `[estimate - uncertainty, estimate + uncertainty]`, acotado al dominio válido. Un ganador único solo se declara si su límite superior es menor que el límite inferior de todas las demás candidatas. Si no, comparten empate quienes aún podrían ser primeras: las candidatas cuyo límite inferior no supera el menor límite superior del conjunto. No se usa orden de socket, ID de persona o commit para romper ese empate. La política de puntos compartidos/desempate por nueva pregunta pertenece al juego.
|
|
|
|
Ejemplo bajo hipótesis simplificadas: reacción real de A a 400 ms, B a 350 ms, y subidas de 20/100 ms hacen llegar sus inputs a 420/450 ms. El orden de paquetes daría ventaja a A. Compensar recuperaría estimaciones 400/350 ms si las subidas fueran conocidas; con incertidumbre ±40 ms los intervalos se solapan, de modo que este perfil declara empate. Es ilustración matemática, no medición de nuestro sistema.
|
|
|
|
Se espera hasta el cierre de recogida antes de confirmar ganador; cualquier optimización de cierre temprano necesita demostrar que ningún candidato admitido pendiente puede cambiar el conjunto. Retardo deliberado, pestaña suspendida, hardware y proveedores externos siguen siendo limitaciones. Commit/reveal puede impedir cambiar una respuesta tras ver otras, pero no prueba el instante físico de reacción; no se presenta como solución de latencia.
|
|
|
|
Los agentes IA reciben el estímulo solo al abrir y usan decisiones duraderas. La latencia de un modelo no equivale a tiempo humano ni a RTT de navegador. Un juego de reacción humano/IA necesita reglas declaradas de demora/dificultad y ensayos propios; sin ese perfil aprobado no admite agentes en carreras de velocidad. Juegos por turnos y acierto en ventana conservan las validaciones normales del [perfil virtual](virtual-player-profile.md).
|
|
|
|
## 7. Cambio de presentación y comprobación
|
|
|
|
El recorrido invitación → TV personal + mando siempre ofrece «Jugar solo en el móvil». Conserva membresía, asiento, datos autorizados, comando pendiente y recibo; cierra el vínculo personal al confirmar `Mobil` y obtiene snapshot `player-full`. No repite la invitación ni afecta a las TVs de otros jugadores.
|
|
|
|
En turnos el cambio usa la barrera de suscripción habitual. En rondas temporizadas se puede solicitar siempre y se ejecuta en el punto seguro definido por el perfil; para reacción, entre rondas. Fuente y crédito temporal no se sustituyen a mitad de una pregunta ni se reinicia su reloj. Si se pierde la TV durante una ronda y no hay fuente válida, se neutraliza según política antes del cambio. En reacción la neutralización afecta a la comparación completa, no se inventa una derrota para el jugador. Los reinicios están acotados; al superarlos se detiene sin ganador o se acuerda otro perfil, sin suspensiones de reputación automáticas por una mala red.
|
|
|
|
Una declaración cliente de «lag» no anula por sí sola una ronda. El perfil debe definir criterios observables por servidor, motivo de incidente, presupuesto acumulado de reintentos y salida al agotarlo, con pruebas de desconexión deliberada para evitar repetir hasta acertar. Los contadores no se reinician al reconectar, cambiar TV o transferir mando. Una ronda anulada que haya revelado contenido se sustituye por otra pregunta/estímulo y generación; nunca se repite el mismo secreto como si nadie lo conociera. Se conservan puntuaciones de rondas ya resueltas; detener la comparación pendiente sin ganador no revierte resultados confirmados. Cuando no se pueda continuar con equidad, se pausa/cancela según la política publicada, sin inventar victoria o derrota por calidad de red. Esta política de incidentes es requisito de publicación, aún sin esquema ejecutable.
|
|
|
|
Para una ronda temporizada sin resolver, esta política prevalece sobre `sharedDisplay.onLoss: continue`: no se continúa una carrera sin su fuente fijada. Fuera de esa ronda rige el fallback multidispositivo. El cambio de mando web/Flutter usa además la generación y barrera del [perfil de comunicación](../platform/client-communication-profile.md#continuidad-del-mando-entre-conexiones); no transfiere presupuestos temporales a otra ruta a mitad de la pregunta.
|
|
|
|
Antes de habilitar este perfil se necesitan esquemas/fixtures de negociación, reloj/época, ronda y comandos; persistencia de ingresos/plazos; estimador versionado y pruebas con respuestas de tiempos conocidos. La matriz de red incluye RTT, jitter, asimetría, pérdidas/retransmisiones y bloqueo de cabeza de cola, reconexión, cambio de nodo, carga SQL/proxy y deriva. Se ensayan TV común, varias TVs personales, Desktop/Mobil y cambio a móvil completo, con diferentes frame rates, pestañas en segundo plano y dispositivos reales.
|
|
|
|
Se prueban timestamps/pings falsos, acuses retardados, doble respuesta, replay de otra ronda/época, segunda pestaña o app que intenta leer antes desde otra fuente, cambio de perfil/ruta tras revelar, secretos precargados, cierre concurrente, transición a recogida con respuestas en cola y respuesta perdida después de commit. El resultado no debe variar solo por retrasar el procesamiento SQL después de `ingressAtMs`. Se ensayan neutralizaciones repetidas sin reiniciar cuotas y sin reutilizar preguntas reveladas. Dentro del presupuesto validado, la compensación y los empates deben cumplir los vectores publicados; fuera de él, el fallo debe acabar en la salida neutral prevista. No basta comprobar que dos pantallas muestran una cuenta atrás parecida.
|
|
|
|
Las métricas separan tiempo de red, cola, reglas/commit, fanout y renderizado estimado; se comparan puntuaciones por rangos de conexión y fuente sin guardar contenido privado innecesario. La [capacidad](../platform/capacity-and-scaling.md) se prueba con ráfagas de respuestas simultáneas y probes acotados. Mantener la misma revisión autoritativa no acredita por sí solo equidad de reacción.
|