Auditabilidad de los partidos

Cada vez que se cierra un partido en ProdeCity, generamos un snapshot inmutable con las predicciones del grupo y un hash SHA-256 que lo identifica de forma única. Una vez creado, el snapshot no se modifica nunca.

El hash es un código de 64 caracteres que funciona como huella digital del contenido. Si una sola coma del contenido cambia, el hash cambia por completo.

Vista pública del partido

Cualquiera puede consultar la auditoría pública de un partido en prodecity.com/auditoria/{uuid-del-partido} . Vas a ver:

  1. Los datos del partido: equipos, fase, fecha del kickoff, momento exacto del cierre.
  2. El conteo total de predicciones y de comodines que se activaron al cierre del partido.
  3. El hash SHA-256 del snapshot.

La vista pública es un fingerprint del partido: sirve para confirmar que cuántas predicciones se cerraron y a qué hora, sin exponer datos personales.

Vista del grupo

Si pertenecés a un grupo, podés ver la auditoría del grupo para un partido en app.prodecity.com/auditoria/{uuid-del-partido}/{uuid-del-grupo} . Iniciando sesión vas a ver:

  1. La lista completa de predicciones del grupo: nombre del usuario, marcador que predijo, si usó comodín, momento en que cargó la predicción.
  2. El hash SHA-256 propio del snapshot del grupo.

Es exactamente lo que se reveló al grupo en la app al cerrarse el partido. La auditoría del grupo es privada: solo los miembros pueden verla.

Para qué sirve

El hash te permite confirmar que el snapshot publicado coincide exactamente con el que se generó en el cierre del partido. Cuando un grupo tiene webhook configurado (Discord, Telegram o URL propia), el hash también se postea al canal en el momento del cierre — comparando ese hash con el que devuelve la auditoría, cualquiera puede verificar que la información del partido es la misma que se selló al cerrarse.

Cómo verificar el hash

El hash se calcula con SHA-256 sobre el payload del snapshot, normalizado de manera reproducible (keys ordenadas alfabéticamente de forma recursiva, listas conservan su orden). Cualquiera puede recalcularlo en cualquier lenguaje. Ejemplo en Python:

import json, hashlib, urllib.request

url = "https://api.prodecity.com/api/v1/public/audit/{uuid-del-partido}"
data = json.load(urllib.request.urlopen(url))

def normalize(v):
    if isinstance(v, list):
        return [normalize(x) for x in v]
    if isinstance(v, dict):
        return {k: normalize(v[k]) for k in sorted(v.keys())}
    return v

canonical = json.dumps(
    normalize(data["data"]["payload"]),
    ensure_ascii=False,
    separators=(",", ":"),
)
computed = hashlib.sha256(canonical.encode()).hexdigest()

assert computed == data["data"]["payload_hash"]