Reproducibilidad
docs.stripe.com · auditado el 2026-07-27 · AgentFit v3.4.0 · rúbrica v4 · Claude Opus 5
Una puntuación que no se puede repetir no es una medición. Así que aquí está la prueba que le debemos: auditamos el mismo sitio seis veces en un día —tres pidiéndole a un modelo de lenguaje que aplicara una rúbrica de documentación y tres ejecutando AgentFit— y publicamos lo que registramos, incluido lo que nos resulta incómodo.
Preguntar a un modelo · 3 ejecuciones
78 · 80 · 65 15 puntos de dispersión
Tres agentes independientes, el mismo prompt público, el mismo modelo, el mismo día. Ninguno sabía de los otros ni de por qué se le preguntaba.
Ejecutar AgentFit · 3 ejecuciones
57 · 57 · 57
0 puntos de dispersión
eabbb2f6abcdea473b600dc4ee8e25282fd002344f1e8425519caa32ff858b01
un sha256, tres archivos
Tres auditorías en vivo seguidas, tres archivos JSON, una sola suma de comprobación. No es caché: cada ejecución volvió a salir al sitio.
Lee las columnas de arriba abajo, no de lado a lado. La rúbrica de la izquierda tiene 26 criterios; AgentFit tiene 28, y las dos los ponderan de forma distinta: una especificación legible por máquina vale 25 puntos a la izquierda y 17 aquí. 57 no es «la respuesta correcta» y 78 no es «incorrecto». La afirmación de esta página es más estrecha, y es la única que los datos sostienen: uno de estos dos procedimientos devuelve el mismo número cada vez, y el otro no.
Dónde discreparon las ejecuciones
Las tres ejecuciones del modelo hicieron el trabajo con seriedad: consultaron URL en vivo, recorrieron los criterios uno por uno e informaron lo que encontraron. Según nuestro propio recuento en las transcripciones —que no publicamos—, cada ejecución hizo entre 36 y 47 llamadas a herramientas y ninguna inventó un hecho. Tome ambas afirmaciones como nuestra lectura de las ejecuciones, no como algo que los archivos de más abajo le permitan comprobar. Aun así terminaron separadas por 15 puntos, y once de ellos están en una sola categoría.
| Categoría | Máx. | A | B | C | Dispersión |
|---|---|---|---|---|---|
| A — Descubrimiento | 18 | 13 | 13 | 12 | 1 |
| B — Artefactos de página | 22 | 12 | 13 | 12 | 1 |
| C — Especificación legible por máquina | 25 | 20 | 21 | 10 | 11 |
| D — Contenido | 20 | 18 | 19 | 18 | 1 |
| E — Renderizado e higiene | 15 | 15 | 14 | 13 | 2 |
| Total | 100 | 78 | 80 | 65 | 15 |
Aquí se mezclan dos clases de desacuerdo. Los pequeños —A5, B3, B5, B6, D1, D3, D6, un punto por aquí y por allá, en ambas direcciones— son lo que cabría esperar de tres lectores atentos de la misma página: uno encontró las pestañas de SDK en el DOM y los otros dos concluyeron que solo existen dentro de una carga JavaScript. Si eso es ruido de medición ordinario, tres ejecuciones no pueden decirlo; ahí estamos suponiendo. En los resúmenes publicados solo se ve el desacuerdo de D1; el resto proviene de nuestra propia comparación de las tres transcripciones. El desacuerdo grande es de otra naturaleza, y es la razón de ser de esta página.
Los demás criterios de la categoría C puntuaron exactamente 10 puntos en cada una de las tres ejecuciones. Toda la brecha de once puntos son dos criterios.
C1a: los mismos hechos, tres puntuaciones distintas
El criterio C1a —de la rúbrica de 26 criterios del modelo; AgentFit fusiona descubrimiento y validez en un único C1— pregunta si la API tiene una especificación legible por máquina a la que un agente pueda llegar. Las tres ejecuciones establecieron exactamente los mismos dos hechos sobre docs.stripe.com:
- las ubicaciones convencionales — /openapi.json y sus hermanas — devuelven 404;
- una especificación OpenAPI válida y completa está publicada en el repositorio de GitHub de Stripe.
Nadie se equivocó. Nadie alucinó. Puntuaron 0 de 8, 3 de 8 y 4 de 8.
| Criterio | A | B | C |
|---|---|---|---|
C1a · spec discoverable | 3/8 | 4/8 | 0/8 |
C1b · spec valid | 7/7 | 7/7 | 0/7 |
E5 · terms of use | 3/3 | 2/3 | 1/3 |
El desacuerdo no es sobre el sitio. Es sobre una pregunta que la rúbrica nunca hizo: ¿cuenta como publicada una especificación que vive en el dominio de otro y exige un salto más? Es una bifurcación real sin respuesta obvia, y cada ejecución llegó a ella sola, en mitad de una tarea larga, sin una regla que consultar. Tres ejecuciones, tres políticas.
A partir de ahí se propaga en cascada. C1b puntúa la calidad de la especificación encontrada. La ejecución que decidió que GitHub no cuenta no tenía nada que validar y puntuó 0 de 7. Las dos que la descargaron puntuaron 7 de 7 — y luego informaron de un número distinto de rutas, 414 y 136, porque el repositorio de Stripe contiene más de un archivo de especificación y eligieron archivos distintos (spec3.json y spec3.yaml). Dos ejecuciones coincidieron en la puntuación por razones opuestas.
E5 — «¿se indican las condiciones de uso?» — salió 3/3, 2/3 y 1/3. Una ejecución encontró en el pie de página un enlace a stripe.com/legal/ssa. Otra rechazó ese enlace y en su lugar dio por válida la directiva Content-Signal del robots.txt. La tercera buscó /terms, /legal y /privacy en el host de la documentación, obtuvo tres 404 y puntuó lo que vio. Tres lecturas defendibles de una misma línea de la rúbrica.
La autocomprobación también varió
El prompt incluye un ancla de calibración: una tabla de sitios medidos anteriormente en la que Stripe aparece con 56, medido el 13 de mayo de 2026. Está ahí precisamente para detectar la deriva. Esa misma tabla explica por qué el sitio aquí es docs.stripe.com: Stripe ya figuraba en el ancla de calibración de otra persona antes de que nosotros ejecutáramos nada, así que el sitio se eligió por nosotros y antes del experimento.
Las tres ejecuciones la usaron. Las tres advirtieron su propia desviación: +22, +24, +9. Las tres reexaminaron entonces sus criterios, razonaron sobre lo que podría haber cambiado desde mayo y concluyeron que el ancla estaba obsoleta y que su propio número era mejor. Tres veces, de forma independiente, en la misma dirección, con tres números distintos.
Esta es la parte que nos parece más instructiva. No es descuido: es el aspecto que tiene el trabajo concienzudo cuando al procedimiento todavía le queda un parámetro libre. Una autocomprobación cuyo veredicto cambia entre ejecuciones no es una autocomprobación.
Da la casualidad de que el ancla queda a un punto del 57 de AgentFit. No leas nada en ello: es una medición manual, con otra rúbrica, de otro mes, y no es prueba de que 57 sea la puntuación verdadera.
Por qué el código responde lo mismo
Nada ingenioso. Cada criterio es una petición más una regla, y ambas están escritas antes de que empiece la auditoría.
| Criterio | Resultado | Petición | Registrado |
|---|---|---|---|
| A1 · índice llms.txt | presente 3/3 | GET /llms.txt → 200 | Stripe Documentation |
| C1 · descubrimiento de la especificación | ausente 0/8 | lista fija de URL, sin respuesta | — |
| D2 · realismo de los ejemplos | presente 5/5 | página de endpoint muestreada → 200 | placeholder_ratio = 0.00, 0/3 blocks |
| E6 · accesibilidad | parcial 1/4 | página de inicio → 200 | a11y: 3 violations (e.g. button-name) |
D2 es el del aprendizaje automático. Dentro de la auditoría corren dos clasificadores pequeños: uno puntúa cuán realista es un ejemplo de código, el otro juzga la completitud de una página de endpoint. Son grafos ONNX con pesos congelados compilados dentro del binario. La misma entrada da el mismo tensor y el mismo flotante, siempre. El determinismo no exige evitar los modelos; exige evitar los modelos cuya salida no puedes fijar.
C1 es justamente la bifurcación que las tres ejecuciones tomaron de forma distinta, y AgentFit puntúa aquí 0 sobre 8. Nuestra regla no es «GitHub no cuenta»: es una lista fija de lugares donde mirar —diecisiete rutas convencionales en el host auditado, un enlace api-catalog según RFC 9727 y cualquier enlace a una especificación hallado en la página de inicio que descargamos—. En docs.stripe.com ninguna de esas rutas devolvió una especificación y esa página no llevaba tal enlace, así que no se encontró nada. Una regla que siguiera un salto más hasta el repositorio de un proveedor no sería menos correcta. La nuestra simplemente está fijada antes de que empiece la auditoría, se aplica igual a todos los sitios del corpus y su baremo está publicado en la página de la rúbrica. Toda la diferencia está ahí: no una respuesta mejor, sino una respuesta fija. Cómo se puntúa C1.
Compáralo con una ejecución en vivo
El repositorio es privado y no publicamos binarios, así que no vamos a decirte que lo compiles: no puedes. Lo que se puede comprobar sin nosotros es más estrecho, y preferimos decirlo con exactitud. Los archivos de arriba los escribió una compilación de línea de comandos en nuestra máquina el 27 de julio de 2026. El servicio público es otra compilación, ejecutándose en otro sitio, y te entregará su propio informe del mismo sitio web. Si el procedimiento es el que decimos, los dos coinciden en cada puntuación. Aquí está cómo hacer esa comparación y cuánto vale.
Sin ejecutar nada (sin cuota)
El conjunto de datos público lleva el identificador de ejecución de la última auditoría válida de cada host. Toma el de Stripe, vuelve a leer esa ejecución desde la API, reduce ambos documentos a los campos puntuados y compáralos:
$ RUN=$(curl -s https://agentfit.dev/dataset.csv \
| awk -F, '$1=="docs.stripe.com" && $3=="true" {print $7; exit}')
$ curl -s https://agentfit.dev/static/reproducibility/agentfit-run1.json \
| jq -S '{total_score, max_score, categories,
criteria: [.criteria[] | {id, status, score, max}]}' > ours.json
$ curl -s https://agentfit.dev/api/public/audit/$RUN \
| jq -S '.report | {total_score, max_score, categories,
criteria: [.criteria[] | {id, status, score, max}]}' > theirs.json
$ diff ours.json theirs.json
El 27 de julio de 2026 ese diff no imprimió nada: 200 líneas, ninguna salida. Dos compilaciones distintas, dos máquinas distintas, los mismos 28 veredictos.
Ejecutarlo tú mismo (una vez por sitio y día)
Pega https://docs.stripe.com en el formulario de la página principal. Al terminar, la dirección dice /r/<identificador>. Pon ese identificador en lugar de $RUN y ejecuta los mismos dos comandos. Fíjate en qué añade y qué no: la auditoría sigue saliendo de nuestros servidores, así que lo tuyo aquí es la petición y el momento, no el punto de salida.
Una auditoría del mismo sitio por red cada 24 horas. Un segundo intento devuelve 429 y ningún identificador de ejecución — a propósito, para que el servicio no pueda usarse como martillo contra la documentación ajena. Si topas con la cuota, el camino anterior no exige enviar nada. El servidor MCP comparte esa cuota: pedirle a un agente que audite otra vez el mismo sitio el mismo día choca con el mismo muro. Y delante de ese hay un segundo muro que no es tuyo en absoluto: dos auditorías del mismo host en diez minutos, de quien sea, agotan una reserva compartida, y quien llame después recibe 429 con el código rate_limited en lugar de site_quota. Ese se despeja solo en diez minutos.
Sin curl ni jq
Abre agentfit-run1.json en una pestaña y la página del informe de la ejecución, /r/<identificador>, en otra. Deciden siete números: los seis totales por categoría y el total. Están impresos aquí, así que puedes hacerlo sin salir de esta página.
| Categoría | Puntuación | Máx. |
|---|---|---|
| A — Descubrimiento | 11 | 14 |
| B — Elementos de página | 11 | 21 |
| C — Contrato de API | 4 | 17 |
| D — Contenido | 16 | 23 |
| E — Renderizado e higiene | 15 | 21 |
| F — Capacidad de agente | 0 | 4 |
| Total | 57 | 100 |
Tres cosas van a diferir, y deben hacerlo
- auditor — la etiqueta de compilación de lo que escribió el informe. La nuestra dice agentfit/v3.4.0, porque esa era la compilación local de aquel día; un informe reciente dirá lo que esté desplegado ahora. Nombra al binario, no a la medición, y por eso la comparación de arriba lo descarta.
- evidence_snippet — las palabras que el sitio le sirvió a la máquina que fue a buscarlas. Nuestras tres ejecuciones salían de una dirección a la que Stripe respondía en alemán; la ejecución del servicio recibió inglés. El 27 de julio esa era toda la diferencia: B1, B3 y E1 llevaban texto distinto bajo una URL idéntica, un código de respuesta idéntico y una puntuación idéntica. El fragmento registra la entrada, no el veredicto.
- El orden de las claves. Nuestros archivos son lo que escribió la herramienta; la API devuelve el mismo objeto tras pasar por Postgres, que guarda las claves de la más corta a la más larga. Comparar los dos documentos byte a byte no lleva a ninguna parte y no diría nada sobre las puntuaciones: jq -S pone ambos en el mismo orden, y eso es lo que hace que el diff signifique algo.
Una coincidencia significa una sola cosa: el mismo procedimiento, sobre el mismo sitio, devolvió el mismo veredicto desde otra compilación y en otra máquina. No significa que 57 sea correcto; esta página no lo sostiene en ningún sitio. Y depende del sitio auditado: si docs.stripe.com ha cambiado desde el 27 de julio de 2026, los números se mueven, y eso es el instrumento funcionando, no fallando. Mira la fecha audited_on en la fila del conjunto de datos antes de sacar conclusiones de una discrepancia.
Estos archivos están congelados y no los regeneramos en cada versión. Dos razones: la suma de comprobación de esta página se toma sobre estos bytes exactos, y cada número de la prosa de arriba salió de ellos — una pieza que se refresca sola no podría sostener ninguna de las dos cosas. El hilo de alarma está en el lado vivo, no dentro del archivo congelado: la columna 9 de la fila del conjunto de datos que acabas de leer es rubric_version, y mientras esta página siga en pie tiene que valer 4. La pieza es anterior a esa columna y no la lleva, así que el número con el que compararla es el impreso en esta frase — lo afirmamos en vez de dejarte encontrarlo, que es una garantía más débil, y por eso queda escrito. Si algún día esa columna dice otra cosa, la regla cambió después de escribirse esta página: la comparación campo a campo queda anulada y lo que tienes delante es un documento histórico. Preferimos que la página lo diga en voz alta a que se vuelva a ejecutar en silencio hasta coincidir.
Dos de los 28 criterios, D2 y C3, los decide un clasificador pequeño en vez de una regla. Están compilados dentro del binario y se versionan con él: no hay servidor de modelos, y el reentrenamiento de nadie mueve una puntuación ya publicada.
Lo que no estamos afirmando
- No afirmamos que 57 sea lo correcto. No publicamos una puntuación verdadera para docs.stripe.com, porque nadie la tiene. Publicamos un procedimiento y su resultado. Y la reproducibilidad es una condición necesaria, no suficiente: echo 57 también es perfectamente reproducible; lo que no es, es sensible al sitio. Para juzgar si la nuestra lo es, mire /browse: allí el mismo procedimiento reparte sitios reales por todo el rango.
- No estamos comparando dos números. Rúbricas distintas: distinto número de criterios, distintos pesos. La comparación tiene sentido dentro de cada columna, no entre ellas.
- Esto es un sitio, un día, un modelo, tres ejecuciones. Es una demostración, no un estudio, y no prometemos repetirla con regularidad.
- El modelo es Claude Opus 5, el mismo que ayudó a construir esta página y buena parte de este servicio. Mostramos una variabilidad que reprodujimos en la herramienta que nosotros mismos usamos cada día; léelo teniéndolo presente. No decimos que los modelos de lenguaje sean malos en esto. Decimos que no conseguimos que uno devolviera el mismo número dos veces.
- El determinismo es una propiedad del procedimiento, no una promesa sobre internet. Nuestras tres ejecuciones salieron de una máquina en un día, y el sitio sirvió a esa dirección cuerpos de página en alemán — visible en las pruebas de B1 y E1, y una de las ejecuciones del modelo registró lo mismo. Cambia el punto de salida y cambias la entrada. Misma entrada, misma salida: esa es toda la garantía.
En qué es realmente bueno un modelo aquí
Nada de esto vuelve inútiles las ejecuciones del modelo: las convierte en otro instrumento. El diagnóstico de cada una de las tres es bueno por sí mismo: por qué una especificación ausente perjudica a un agente, qué publicar en su lugar, cuáles de las páginas de Stripe sobrevivirían a una lectura sin navegador. Eso es explicación, y un modelo explica de maravilla.
Un modelo de lenguaje es excelente explicando qué arreglar. Es un mal instrumento para medir si lo arreglaste. Nosotros vamos de lo segundo. AgentFit es el instrumento; lleva su número a un modelo y pregúntale qué hacer con él. Esa es la división del trabajo correcta, y es la que usamos.
Los datos
Las seis ejecuciones se sirven desde este sitio. Los tres informes de AgentFit son los archivos que escribió la herramienta, byte a byte: sobre ellos se calcula la suma de verificación. Los tres archivos del modelo son nuestros:
Las transcripciones en bruto no se publican. Para la columna del modelo obtiene resúmenes estructurados que escribimos después a partir de esas transcripciones: la puntuación final, los totales por categoría y las notas por criterio citadas arriba. Las puntuaciones y los totales son el resultado propio de cada ejecución; la redacción de las notas es nuestra.
- tres informes de AgentFit y la suma de comprobación —
run1.json·run2.json·run3.json·sha256.txt - tres ejecuciones del modelo, como resúmenes que escribimos a partir de las transcripciones —
runA.json·runB.json·runC.json - el prompt de la columna del modelo, fijado al commit que ejecutamos —
ai-ready-audit
No se filtró nada: ni una ejecución ni un sitio. Tres auditorías del modelo y tres de la herramienta, sobre el único sitio que la tabla de calibración del prompt ya nombraba; no ejecutamos ningún otro ni descartamos nada. Si una cuarta ejecución hubiera dado 57, también la habríamos publicado y esta página sería más corta.
Gratis, sin registro, unos 30 segundos. 28 criterios, evidencia HTTP bajo cada uno, un enlace de informe compartible — y el mismo número mañana si nada ha cambiado.