Estado del port
La sala de máquinas. Aquí está, medido y verificable, cuánto del juego de 1988 hemos comprobado y cómo. Si sólo quieres jugar, no necesitas nada de esto: el juego funciona sin leer una sola cifra — tu puerta es Cómo se juega. Esta página es para quien quiera levantar el capó.
Esta página se GENERA de los artefactos del repositorio en cada construcción del sitio: el censo de rutinas, el ledger de cobertura y el registro de bugs. Ni una cifra está escrita a mano. Si mañana se lee una rutina más, el número de aquí abajo cambia solo.
El juego se puede terminar de principio a fin
con las ubicaciones de trama derivadas, no con las canónicas del binario — es la Clase E de las divergencias declaradas · ver la clase E
Cobertura del binario original
202.800 de 202.800 bytes · 0 pendientes
Adjudicado no es verificado: quiere decir que sabemos de quién es cada byte y de qué clase, no que su lógica esté comprobada.
Lectura del binario, fila a fila
- 722 con el cuerpo leído y verificado
- 162 aplazadas con razón escrita (controladores de hardware)
- 1 sin cerrar, y no cierra por estructura
885 filas censadas en total
0 sin explicar.
De qué está hecho el binario
- 75,0 % Código ejecutable
- 14,0 % Textos del juego
- 6,2 % Estado en memoria
- 3,7 % Tablas de datos
- 1,0 % Datos sueltos
- 0,1 % Relleno del enlazador
- 0,0 % Cabecera del fichero
202.800 bytes repartidos en 7 clases de segmento
Pruebas de navegador declaradas
censo con --list · no es un recuento de verdes
826
826 pruebas en 104 ficheros, contadas con --list
- 330 Escritorio
- 6 Espejo del original
- 488 Móvil
- 2 Sitio en producción
Esta cifra dice cuántas EXISTEN, no cuántas pasan. Correrlas cuesta una ventana de máquina, así que el resultado va con su fecha: el 2026-09-12, sobre b083ad30f, se ejecutaron 820 y pasaron 720. Los 0 restantes son una cota superior de defectos —bajo carga hay pruebas que caen por plazo—; el desglose está en /verificacion.
Salas de mazmorra selladas
112 / 112
7 mazmorras × 16 salas · 0 en cola
Notas de ingeniería inversa publicadas
562
562 de 1402 viajan al repositorio público · 840 hablan de nuestro proceso y no se publican
Los bugs del original, y qué hace OpenU5 con cada uno
- 13 Los que OpenU5 arregla
- 13 Los que calca a propósito
- 4 Erratas conservadas como parte del original
- 10 Defectos latentes, sin camino vivo demostrado
- 11 Investigados y descartados: NO son bugs
51 entradas del registro canónico
Lo que NO está verificado
Un estado que sólo enseña lo hecho no es un estado. Estas son las cinco fronteras conscientes, cada una con su detalle más abajo.
- Paridad del flujo aleatorio frente a una ejecución realCofres, objetos y mazmorra: sus registros no se pueden sembrar sin la máquina original, así que se carean dos modelos independientes en vez de DOSBox.leer el detalle
- El movimiento de la IA en combateLa fórmula está derivada del desensamblado y citada; lo que falta es el testigo en vivo, porque su flujo de tiradas no se captura con fiabilidad.leer el detalle
- La ruta de importación de personajes de Ultima IVDerivada y documentada, no portada. Es una frontera de alcance, no un olvido.leer el detalle
- Las desviaciones añadidas a propósitoMúsica (el original era mudo en PC), tiles en alta resolución, cámara suave. No tocan la lógica y están declaradas una a una.leer el detalle
- El motor es repetible medido sobre una partida, no demostrado sobre todasLas mismas teclas reprodujeron la misma partida byte a byte, dos corridas, comparando la trayectoria entera. Eso es lo que se afirma, ni una palabra más.leer el detalle
Esto es lo que hay leído del Ultima V original y lo que lleva dentro OpenU5, con la cifra exacta y el comando que la reproduce. No hay ninguna barra de progreso: hay recuentos sobre artefactos que están en el repositorio y que puedes abrir tú.
Qué mide esta página, y qué no
Conviene decirlo antes de los números, porque es donde se cuelan casi todos los malentendidos:
- Sí mide cuánto del binario original está adjudicado, censado y leído — rutina a rutina, con la profundidad de cada lectura.
- No mide «cuánto del juego funciona». Eso no es un número: es cómo se verifica, donde están los arneses y también lo que no está comprobado.
- No hay una taxonomía de subsistemas en verde/ámbar/rojo. No existe tal artefacto en este proyecto, y fabricar uno para la portada sería inventarse la evidencia.
La lectura del binario
| Bytes del original adjudicados | 202.800 / 202.800 = 100,0 % · 0 pendientes |
| Ficheros del original censados | 25, repartidos en 796 segmentos |
| De ellos, código ejecutable | 152.185 B = 75,0 % |
| Filas del censo | 885 |
| Filas entendidas a profundidad C o E | 722 |
| Filas con el cuerpo leído y verificado | 722 |
| Filas aplazadas con razón declarada | 163 · de las cuales 163 son controladores de hardware |
| Sin explicar | 0 |
| Verificadas heredadas sin cita | 0 |
Por qué «filas» y no «rutinas»
La unidad del censo es la FILA, no la función. Una fila cubre un rango de direcciones y lleva un nombre; y hay filas que contienen más de un punto de entrada — código al que se llega desde fuera, en mitad del rango, y que por tanto es otra función con el nombre de su vecina encima.
Decirles «rutinas» sería la cifra correcta con la etiqueta equivocada, que es exactamente el defecto que esta página existe para no cometer: el número no cambia, lo que cambia es lo que afirma.
Lo que se sabe hoy, con su límite:
- El proyecto tiene un detector (
re/tools/entradas_absorbidas.py) que las encuentra cruzando el censo con el desensamblado, y separa las clases por fuerza de la evidencia: un destino decalldesde fuera es una función sin discusión; uno de salto puede ser una tabla de saltos o un corte mal puesto entre dos filas. - 🔴 Ese detector da una COTA INFERIOR y lo declara: no resuelve el despacho indirecto.
- 🔴 Y su recuento NO está en el censo commiteado, porque el censo no se regenera (eso destruiría los nombres curados). O sea que el número exacto no se puede publicar todavía, y por eso aquí no hay ninguno: hay una etiqueta honesta y un límite declarado.
Lo que no cambia: las 722 filas con el cuerpo leído están leídas. Lo que se acota es qué cuenta como «una».
La única pendiente, que se lee en par
Queda 1 fila de juego pendiente de verificar, y no cierra nunca por estructura — no le falta trabajo, es que su forma no admite el tipo de verificación que se le pediría. El trabajo real pendiente es 0.
Las tres cifras viajan juntas siempre: «1 pendiente» a secas anunciaría una cola de trabajo que ya no existe. El pase de lectura está cerrado, y lo que queda —1 fila— no se va a mover nunca.
Una nota sobre el 722
Ese número aparece en el censo con dos nombres —body_verified y by_depth.E— y es la misma medición, no dos evidencias que se confirmen entre sí. Citarlo dos veces sería contar una cosa dos veces, así que aquí sale una. El generador comprueba en cada construcción que los dos siguen coincidiendo; si divergen, el sitio no se construye.
La cobertura no es la verdad
100,0 % no quiere decir que el juego esté verificado al 100 %. Quiere decir que cada byte de los ficheros que EA distribuyó está adjudicado a un segmento identificado: sabemos de quién es y de qué clase. Es una afirmación de contabilidad, y es más pequeña de lo que parece.
Conviene ver el reparto, porque «el binario» no es todo código:
| Clase de segmento | Bytes | |
|---|---|---|
| Código ejecutable | 152.185 | 75,0 % |
| Textos del juego | 28.347 | 14,0 % |
| Estado en memoria | 12.510 | 6,2 % |
| Tablas de datos | 7575 | 3,7 % |
| Datos sueltos | 2021 | 1,0 % |
| Relleno del enlazador | 146 | 0,1 % |
| Cabecera del fichero | 16 | 0,0 % |
Lo que hay encima de esa base, y que sí es una escala de conocimiento:
- Adjudicado — el byte pertenece a un segmento identificado. Aquí está el 100,0 %.
- Entendido (profundidad C o E) — hay una derivación de qué hace. 722 filas.
- Leído y verificado — alguien recorrió el cuerpo instrucción a instrucción y lo citó. 722 filas.
Las 163 filas aplazadas no son un olvido: llevan su razón escrita, y 163 de ellas son controladores de hardware (temporizador, teclado, EGA, disco) cuya semántica fina no la ejerce ningún subsistema portado.
Los bugs del original
El proyecto lleva un registro canónico de los defectos del juego de 1988, con el grado de evidencia de cada uno y la decisión que se tomó. Repartidos por lo que OpenU5 hace con ellos:
| Categoría | Entradas |
|---|---|
| Los que OpenU5 arregla | 13 |
| Los que calca a propósito | 13 |
| Erratas conservadas como parte del original | 4 |
| Defectos latentes, sin camino vivo demostrado | 10 |
| Investigados y descartados: NO son bugs | 11 |
La distinción que ordena esa tabla no es la gravedad, es si el defecto se nota jugando. Un bug que cambia lo que ve el jugador se calca; uno que corrompe datos o cuelga el juego se arregla y se declara.
La última fila es la que más cuesta mantener y la que más dice: cosas que parecían defectos, se investigaron y resultaron no serlo. Un registro que sólo acumula hallazgos y nunca se retracta no está midiendo, está coleccionando.
Lo entregado con superficie pública
El port no entrega sólo lectura del binario: estas piezas se pueden tocar desde el sitio, y su recuento se deriva del artefacto en cada construcción — una línea por entrega y ni una captura, porque las páginas públicas no llevan imagen del juego.
- Galería de momentos — 10 partidas prefabricadas en el catálogo de /byo, todas disponibles. El catálogo publicado (
demo-byo/public/momentos/momentos.json) se hornea de los defs del motor y es punto fijo: editarlo a mano pone un test rojo. - Tabla de récords y partidas compartidas — 3 endpoints de API la sirven (
demo-byo/functions/api/), y cada partida compartida se puede reproducir en el visor, tecla a tecla. - Partidas grabadas — 7 secuencias de teclas reales que el motor re-ejecuta, cada una con su vídeo en /partidas. No hay montaje: lo que se ve es la re-ejecución.
- Analítica de uso — sin cifra que contar aquí: activada por defecto, con grabación de sesión, y con el rechazo del visitante el SDK ni se inserta (
game/src/web/analitica.ts). Qué se mide y cómo rechazarlo: /privacidad.
Lo que NO está verificado
Un estado que sólo enseña lo hecho no es un estado. Estas son las cinco fronteras conscientes, todas documentadas en las notas de su subsistema. Cada una tiene su tarjeta arriba del todo, en la primera pantalla: aquí está el detalle.
Paridad del flujo aleatorio frente a una ejecución real
Para comparar tirada a tirada contra el juego de 1988 hay que poder poner su generador de aleatorios en un estado conocido. En cofres, objetos y mazmorra eso no se puede hacer desde fuera: la semilla se toca en sitios a los que no se llega sin la máquina original.
Lo que se hace en su lugar es cruzar dos modelos independientes — el derivado del desensamblado y el que ejecuta el motor — y exigir que coincidan. Es una comprobación fuerte y no es la misma: dos modelos que comparten un error de lectura coinciden igual. Por eso está aquí y no en la lista de lo verificado.
El movimiento de la IA en combate
Cómo elige objetivo y hacia dónde se mueve cada criatura está leído en el ensamblador, instrucción a instrucción, y citado en las notas de su subsistema. Lo que no hay es una corrida del original observada al lado de la del clon: el canal con el que se miden esas trazas no captura su flujo de tiradas de forma fiable, y una medición que a veces pierde datos no vale como testigo.
Es un hueco de instrumento, no de conocimiento — pero el proyecto no cuenta como verificado lo que sólo ha derivado.
La ruta de importación de personajes de Ultima IV
El original permite traer el grupo de Ultima IV. Ese camino está leído y documentado, y no está implementado en OpenU5: se decidió dejarlo fuera del alcance, no se intentó y falló.
Se dice aquí porque la diferencia importa: un hueco de alcance se cierra cuando alguien quiere ese alcance; un hueco de verificación se cierra midiendo.
Las desviaciones añadidas a propósito
No todo lo que OpenU5 hace distinto es un fallo por corregir: algunas cosas se añadieron sabiendo que el original no las tenía. La música, porque la versión de PC era muda. El suavizado de los tiles y la cámara, porque un monitor de hoy no es el de 1988.
La regla que las mantiene fuera de la lógica es concreta y comprobable: una partida grabada se reproduce igual con la piel fiel y con la suavizada. Si una de estas desviaciones tocara lo que el motor calcula, esa repetición dejaría de cuadrar.
El motor es repetible medido sobre una partida, no demostrado sobre todas
Éste sostiene a los otros cuatro, y por eso se dice con todas las letras. La medición existe y es buena: la misma lista de teclas produjo el mismo estado byte a byte en dos corridas, comparando la trayectoria entera y no sólo el resultado final.
Lo que no hay es una demostración de que eso valga para toda partida posible. Una medición sobre un caso no es una propiedad del sistema, y la diferencia entre «medido» y «demostrado» es justo la que este proyecto se niega a difuminar.
Cómo se re-mide todo esto
Ninguno de estos comandos necesita navegador, y ninguno tarda más de unos segundos salvo el primero:
python3 re/tools/ledger.py
python3 -c "import json;print(json.load(open('re/ledger/frontier.json'))['summary'])"
El primero recorre el binario y reparte los bytes; el segundo imprime el censo entero, con todos los campos que esta página resume. El registro de bugs es un fichero de texto: docs/bugs-del-original.md.
Todo está publicado bajo GPL-3.0-or-later en github.com/kokoima/openu5.
Caducidad
Estas cifras salen del árbol 85657e7e, el mismo que construyó esta página. Se regeneran en cada construcción del sitio: no hay copia a mano que se pueda quedar atrás. Un documento de estado que no se re-corre es peor que no tenerlo, porque da la sensación de que alguien comprobó.
Estas cifras salen del árbol 85657e7e.
Los comandos que reproducen cada cifra de este panel
python3 re/tools/ledger.py # cobertura y composición
python3 -c "import json;print(json.load(open('re/ledger/frontier.json'))['summary'])"
python3 tools/estado-plan.py # salas de mazmorra
python3 docs/publicacion/web/censo_notas.py # notas que viajan al repo público
cd game && npx playwright test --list # pruebas de navegador DECLARADAS
cd game && npx playwright test -c playwright.mobile.config.ts --list
python3 -c "import json;print(len(json.load(open('demo-byo/public/momentos/momentos.json'))))" # momentos publicados
find demo-byo/functions/api -name "*.ts" | wc -l # endpoints de la tabla de récords
ls game/partidas/*.json | wc -l # partidas grabadas (replays)