Skip to content

fix(knockout): aplicar tabla del Anexo C para el sembrado de terceros#28

Open
mverab wants to merge 1 commit into
mainfrom
fix/third-place-seeding-annex-c
Open

fix(knockout): aplicar tabla del Anexo C para el sembrado de terceros#28
mverab wants to merge 1 commit into
mainfrom
fix/third-place-seeding-annex-c

Conversation

@mverab

@mverab mverab commented Jun 30, 2026

Copy link
Copy Markdown
Owner

Problema

El constructor del cuadro de octavos (assign_third_slots en scripts/update_qualified.py) no aplicaba la tabla de combinaciones del Anexo C del Reglamento de la FIFA. En su lugar usaba un backtracking ingenuo de satisfacción de restricciones que encuentra una asignación válida (respeta "ningún tercero juega contra un primero de su propio grupo"), pero no la asignación oficial.

Con los 8 terceros clasificados reales — grupos {B, D, E, F, I, J, K, L} — el backtracking producía un emparejamiento incorrecto.

Emparejamiento correcto (Anexo C)

Slot Primero 3.º correcto Match Antes (erróneo)
1A MEX 3E (ECU) M79 ✅ ya correcto
1B SUI 3J (ALG) M85 ❌ SWE
1D USA 3B (BIH) M81 ❌ ALG
1E GER 3D (PAR) M74 ❌ BIH
1G BEL 3I (SEN) M82 ✅ ya correcto
1I FRA 3F (SWE) M77 ❌ PAR
1K COL 3L (GHA) M87 ✅ ya correcto
1L ENG 3K (COD) M80 ✅ ya correcto

Los 4 errores forman una rotación cerrada de terceros sobre los slots: M74 B→D, M77 D→F, M85 F→J, M81 J→B.

Impacto real

M74 ya se jugó (GER–PAR, con Paraguay avanzando). Como reconcile une resultados con partidos por par de equipos {GER, PAR} (nunca por sede/fecha), la lectura errónea del slot {GER, BIH} no coincidía y el resultado quedaba atascado con match_id: null.

Cambios

  • Nuevo data/annex_c_third_place.json: las 495 combinaciones del Anexo C (parseadas de la tabla oficial), indexadas por las 8 letras de grupo ordenadas → {etiqueta_slot: letra_grupo}.
  • assign_third_slots reescrito: primero intenta la tabla del Anexo C (_assign_from_annex_c). Si la combinación no existe o el cuadro no trae etiquetas reales de ganador (1A..1L), cae al backtracking previo (_assign_third_slots_backtrack), preservando el contrato de retorno {match_id_str: letra_grupo} que usa resolve_slot.
  • Regenerados data/tournament.json y docs/data/*.json (byte-coherentes entre data/ y docs/data/): el cuadro de octavos ahora muestra M74=GER/PAR, M77=FRA/SWE, M81=USA/BIH, M85=SUI/ALG.
  • Reconcile vuelve a mapear GER–PAR a M74 con la orientación correcta (match_id null → 74, añadido round: "round_of_32").
  • Nuevos tests (tests/test_annex_c.py, 9 casos): el archivo tiene 495 combinaciones; todas son biyecciones válidas; la fila real coincide con el emparejamiento esperado; assign_third_slots sobre el cuadro real da {74:D, 77:F, 79:E, 80:K, 81:B, 82:I, 85:J, 87:L}; GER enfrenta al grupo D (no B); y GER–PAR reconcilia a match_id 74.

Verificación

  • 67 tests en verde (58 previos + 9 nuevos).
  • predictions/pre-tournament/*.json intactas (regla inviolable respetada).
  • docs/data/*.json byte-coherentes con data/.

No fusionar automáticamente — abierto para revisión.

El constructor del cuadro de octavos (assign_third_slots en
scripts/update_qualified.py) NO aplicaba la tabla de combinaciones del
Anexo C del Reglamento FIFA. Usaba un backtracking ingenuo de
satisfaccion de restricciones que encuentra UNA asignacion valida (que
respeta "no jugar contra tu propio grupo") pero NO la asignacion oficial.

Con los 8 terceros clasificados reales ({B,D,E,F,I,J,K,L}) el backtracking
producia un emparejamiento incorrecto. Segun el Anexo C el emparejamiento
correcto es:
  1A(MEX) vs 3E(ECU) -> M79
  1B(SUI) vs 3J(ALG) -> M85   (antes erroneo: SWE)
  1D(USA) vs 3B(BIH) -> M81   (antes erroneo: ALG)
  1E(GER) vs 3D(PAR) -> M74   (antes erroneo: BIH)
  1G(BEL) vs 3I(SEN) -> M82
  1I(FRA) vs 3F(SWE) -> M77   (antes erroneo: PAR)
  1K(COL) vs 3L(GHA) -> M87
  1L(ENG) vs 3K(COD) -> M80
Es una rotacion cerrada de 4 terceros sobre los slots
M74 B->D, M77 D->F, M85 F->J, M81 J->B.

Impacto real: M74 ya se jugo (GER-PAR, PAR avanzo). Como reconcile une
resultados con partidos por par de equipos {GER,PAR}, la lectura erronea
del slot {GER,BIH} no coincidia y el resultado quedaba con match_id null.

Cambios:
- Nuevo data/annex_c_third_place.json: 495 combinaciones del Anexo C
  (parseadas de la tabla oficial), indexadas por las 8 letras de grupo
  ordenadas -> {etiqueta_slot: letra_grupo}.
- assign_third_slots reescrito: intenta primero la tabla del Anexo C
  (_assign_from_annex_c). Si la combinacion no existe o el cuadro no trae
  etiquetas de ganador reales (1A..1L), cae al backtracking previo
  (_assign_third_slots_backtrack), preservando el contrato de retorno
  {match_id_str: letra_grupo}.
- Regenerados data/tournament.json y docs/data/*.json (byte-coherentes):
  bracket de octavos ahora M74=GER/PAR, M77=FRA/SWE, M81=USA/BIH,
  M85=SUI/ALG.
- Reconcile vuelve a mapear GER-PAR a M74 con la orientacion correcta
  (match_id null -> 74, anadido round round_of_32).
- Nuevos tests (tests/test_annex_c.py, 9 casos): el archivo tiene 495
  combinaciones, todas son biyecciones validas, la fila real coincide,
  assign_third_slots sobre el cuadro real da {74:D,77:F,79:E,80:K,81:B,
  82:I,85:J,87:L}, GER enfrenta al grupo D (no B), y GER-PAR reconcilia a
  match_id 74. 67 tests en verde.

No se modifico ninguna prediccion (predictions/pre-tournament/*.json
intactas).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant