# Cómo no repetir trabajo ya hecho

El número de candidatos del diff **no baja cuando corriges**: el alineador vuelve
a reportar lo mismo en cada pasada. Sin un registro, cada sesión re-adjudica lo
que la anterior ya miró. Esto es lo que lo evita.

## Antes de tocar nada

```bash
cd ~/git_projects/astro_vedabase/scripts/scan_audit
python3 build_ledger.py                 # reconstruye ledger.jsonl y resume
python3 build_ledger.py --abiertos teachings-of-lord-caitanya
```

`ledger.jsonl` da un estado por candidato. **Solo se trabaja sobre `ABIERTO`.**

| estado | qué significa |
|---|---|
| `APLICADO` | el texto del repo que reportaba ya no existe, o figura como `old` en `corrections.jsonl` |
| `AUDITADO` | pertenece a una cubeta cerrada (ver abajo) |
| `DESCARTADO` | ya se descartó en `dismissed_entries.json` o en `descartadas*.md` |
| `VERIFICADO` | lectura del impreso ya comprobada por imagen: **no volver a proponerla** |
| `RUIDO` | cae en una clase de ruido confirmada |
| `ABIERTO` | lo único pendiente |

## Después de decidir — SIEMPRE

Escribe el veredicto en `verdicts.jsonl`, **también cuando la decisión es "no
tocar"**. Es lo único que impide que la próxima sesión lo vuelva a mirar:

```jsonl
{"repo":"petalled","scan":"petaled","estado":"APLICADO","razon":"impreso p.312, adjudicado por imagen","fecha":"2026-08-07"}
{"repo":"into","scan":"in","estado":"DESCARTADO","razon":"ruido del alineador, el impreso dice 'into'","fecha":"2026-08-07"}
```

`build_ledger.py` lo lee y ese candidato deja de salir como `ABIERTO`.

## Cubetas cerradas — no reabrir

- **SYNONYMS (word-for-word) de CC, SB, ISO y BG.** Corrida hasta el final
  (158/158 lotes + 107/107 del bucket `OCR_NOISE`). Dejó **2.100 correcciones**
  con `field=synonyms` en `corrections.jsonl` (sb 1.264 · cc 755 · iso 37 ·
  bg 17). Ver `SYNONYMS_AUDIT_HANDOFF.md`.
- **Índice del impreso contra lo servido**: HECHO en tqk, pop, ej, los 17 libros
  pequeños (2026-08-07) y, volumen por volumen, en **SB y CC** (2026-08-08).
  SB: 96 títulos cuadran, 4 divergían (sb/6/1 tenía el título de la edición
  REVISADA, sb/3/7 una errata 'Inquires', sb/1/14 un artículo de más, sb/9/24
  una coma de menos) — corregidos. CC: 57 cuadran, ninguna divergencia.
  OJO al parsear: el índice del SB numera con palabras (CHAPTER ONE) y el del CC
  con cifras (Chapter 1); y el índice lista tambien SUBSECCIONES, así que el
  título bueno es el de la página de APERTURA del capítulo, no el del índice.
- **Continuidad de numeración** de SB, CC, BG, ISO y NOI: 20.317 referencias,
  cero huecos y ningún capítulo ausente (2026-08-07). No repetir.
- **Número del título contra la referencia**, 17 libros en prosa × 5 idiomas:
  cero desajustes tras corregir tlc 19-21 (2026-08-07).
- **content/en contra el repo**, en los dos sentidos y en todo el corpus: solo
  salieron nod 9, nod 10 y kb/31, ya arreglados (2026-08-07).

### Rediff completo contra el repo actual — 2026-08-13

Los candidatos de `out_surya/` estaban generados entre el 19-jul y el 4-ago, y el
repo habia recibido correcciones despues. Se rehizo el diff entero (21 libros,
35.441 paginas de OCR) contra el repo del 13-ago: **4.654 candidatos**, de los
que 79 no estaban adjudicados. La corrida anterior quedo archivada en
`out_surya_hasta_2026-08-04/`.

De los 79: **10 aplicados** sobre la imagen del escaneo, 2 verificados como
errata del impreso, 42 ruido y 25 clasificados en la cubeta de TLC de abajo.
Hoy el ledger esta a **cero abiertos en los 21 libros**.

Aplicados (todos con su pagina en `corrections.jsonl`): `cowsrom`->`cows from`,
`isund`->`is sound` (x2, el repo se contradecia dentro del mismo parrafo),
`literatures`->`scriptures` (x2), `foodstuffs`->`food` (x3), `nor`->`or`,
`lower than`->`one lower than a`.

Verificados como errata del papel, no tocar: `harrassed` (KB) y **`a cit`** en
CC Antya 2.16 — el impreso dice «is the present Ambikā, a cit in the Vardhamāna
district» y tres lineas mas abajo «In this city». Va a PRINT_ERRATA.

### Deriva repo<->D1 en ingles: medida, arbitrada y en gran parte cerrada

**La muestra de doce que dio 83% estaba sesgada** —eran justo las referencias
que yo acababa de tocar—. Medido de verdad sobre las 20.580 referencias
inglesas con `verificar_paridad.py`: **431 divergentes, el 2,1%**.

De los bloques que difieren, 79 son estructurales y no hay nada que hacer:
colofones que el repo guarda sueltos y D1 pega al ultimo verso, titulos de
capitulo que en D1 viven en otra columna, y huecos. Los 717 restantes eran
deriva de verdad.

**Como se arbitran sin abrir 365 imagenes.** El diff de Surya compara repo
contra ESCANEO y esta a cero abiertos, asi que el escaneo desempata. Buscando
cada variante dentro de su contexto —tres palabras a cada lado; con la palabra
suelta «one» sale en todas las paginas— quedo: 621 bloques donde el escaneo
respalda al repo, 34 donde respalda a D1, 62 indecisos.

**Cruzar SIEMPRE con verdicts.jsonl antes de tocar.** De los 34 «repo
equivocado», 25 ya estaban adjudicados y el repo es correcto a proposito:
`a cit` de CC Antya 2.16 es errata del impreso verificada por imagen y el OCR
dice «city». El OCR no es prueba.

**Lo aplicado.** 431 -> 184 referencias divergentes. En D1 entraron 621 bloques
por contexto y 34 tokens corruptos sin contexto (`Vedānta-sūtrass`, `elderlyly`,
`Nāmārtha-sudhābhidhabhidha`, y la ese larga de bbd/1: `sarvofya`, `tofmāt`).
En el repo se arreglaron 7 destrozos que **no eran criterio editorial sino daño
de sustituciones automaticas anteriores**: `foodstuffstuff` (un reemplazo
aplicado dentro de si mismo), `hisother` por «his mother», `Śrīpādṅkarācārya`
que se comio «a Śa», `appearsfrom`, `homogenousoneness`, `virāṭaa-rūpa`.

Que la misma enfermedad —sufijos duplicados, espacios comidos— aparezca en los
dos lados dice que hubo pasadas de reemplazo en bloque sin ancla de contexto.
Merece una barrida propia: buscar `(\w+)\1` y palabras pegadas en los dos
almacenes.

**Lo que queda, 152 bloques en 114 referencias:** 58 donde el escaneo respalda
al repo pero el REPLACE literal no casa porque el contexto atraviesa una
cursiva —el repo normaliza y las quita, D1 las conserva—, y para eso hace falta
emparejar tolerando el marcado; 58 donde las dos variantes salen en el escaneo
y hace falta la imagen; 32 «repo equivocado» que hay que cruzar con los
veredictos antes de nada; y 4 sin rastro.

Herramientas: `clasificar_deriva.py` (separa estructural de real y guarda el
contexto), `arbitrar_deriva.py` (desempata con el escaneo), `empujar_deriva_d1.py`
(`--ancho N` para el contexto).

### Estado al cierre del 15-ago

Deriva repo<->D1: de 431 referencias a **132**, y la automatizacion ha
convergido (tres vueltas seguidas dan el mismo numero).

    79 bloques  estructurales — colofones, titulos de capitulo y huecos. NUNCA
                convergen: es como esta repartido el contenido, no un error.
    30 bloques  «repo equivocado», de los que 27 YA estan adjudicados y el repo
                es correcto a proposito. Cruzar con verdicts.jsonl SIEMPRE.
    26 bloques  las dos variantes en la misma pagina -> imagen, una a una
    16 bloques  «D1 equivocado» que resisten el emparejado automatico
     1 bloque   sin rastro en el escaneo

**Los tres arbitros, y por que hicieron falta los tres.** Cada uno resuelve lo
que el anterior no puede, y el orden importa:

  arbitrar_deriva.py       busca la variante en TODO el libro. Resuelve la
                           mayoria, pero deja «las dos aparecen» en 53: claro
                           que «or» y «nor» estan los dos en el CC.
  arbitrar_por_pagina.py   busca en SU pagina. Para eso hubo que arreglar el
                           localizador, que exigia el contexto literal: ahora
                           prueba ventanas deslizantes cada vez mas cortas y
                           localiza 47 de 47, frente a 2 de 5.
  leer_palabra_impreso.py  no comprueba hipotesis: LEE. Localiza el contexto
                           izquierdo y mira que palabra viene detras.

El tercero es el que encuentra lo que los otros dos no pueden ver: cuando la
palabra del impreso no es NI la del repo NI la de D1, uno de los dos esta roto.
Asi salieron `heis`, `towardmaterial`, `prembilasaarta` y `Maharastraprovince`
en el repo — y el UNICO caso de toda la auditoria en que el impreso da la razon
a D1: «This action was typical of Indra» (CC Madhya 9.279), donde el repo ponia
«is».

**Cinco reemplazos en bloque encontrados, todos sin buscarlos.** Salieron del
cruce entre los dos almacenes, no de una barrida:

    sufijos duplicados   foodstuffstuff, Vedānta-sūtrass, elderlyly
    la ese larga         sarvofya, tofmāt, profaktānāṁ  (aſ leido como of)
    «the» -> «previous»  cc/adi/7/74, la fila entera
    «the» -> posesivo    «In his Anubhāṣya» por «In the Anubhāṣya»
    «are» -> «were»      sb/4/1/15, cuatro veces en la misma fila

**Al aplicar, dos reglas que costaron sangre.** Una: exigir que el patron
aparezca UNA sola vez en el campo — es lo que permite bajar el contexto hasta la
palabra sola sin romper nada. Dos: no tocar clases sistematicas a partir de una
instancia; `motorcars` (230 en el repo), `tranquillity` (106) y `girlfriend`
—donde el impreso escribe las dos formas— piden decision de corpus.

### Cubeta ABIERTA: los 25 de TLC — NO es «el repo esta modernizado»

**Correccion de lo que escribi el 13-ago.** Al ver la p.129 del impreso —que
escribe «Avatar», «Avatars», «Srimad Bhagwatam», «Shakshat», «Parsuram»— di por
hecho que la primera edicion translitera al modo bengali y que el repo lo habia
modernizado en bloque. Contando el libro entero, con limites de palabra, eso
**no se sostiene**:

    forma              repo  scan  |  forma            repo  scan
    vyasadeva            34    32  |  vyasdeva            0     2
    sanskrit              9     8  |  sanscrit            0     1
    sannyasa             11     8  |  sannyas             1     2
    avatara              27    10  |  avatar              3    16
    narayana             29     8  |  narayan            26    46
    garbhodakshayee      15    10  |  garbodakshayee      0     5

En la mayoria de los terminos el repo y el impreso **coinciden**: `vyasdeva`,
`sanscrit` o `bibhava` aparecen una o dos veces en el escaneo y ninguna en el
repo, que es el perfil del ruido de OCR, no el de una forma editorial. Donde si
hay diferencia de reparto es en `avatar(a)` y `narayan(a)`, y ahi **el impreso
se contradice a si mismo**, que es justamente la excepcion que la regla admite.

Conclusion: no hay criterio de libro que decidir ni pasada en bloque que hacer.
Son 25 sitios sueltos y se adjudican como todos los demas, uno a uno contra su
imagen. Siguen marcados AUDITADO para que no salgan como abiertos, pero la
razon es esta y no la que puse.

### Los cuatro que faltaban por imagen — cerrados

Se miraron los cuatro. Tres eran divergencias reales y estan aplicadas:
`direction`->`directions` (KB 86, p.286), `interaction`->`interactions`
(KB 87, p.343) y `with`->`from` en «unalloyed service from Govinda»
(CC Madhya 2.78, mad1 p.251).

El cuarto salio al reves y conviene recordarlo: en CC Madhya 9.155 el OCR leia
`unneccessarily` y **la imagen desmiente al OCR** — el papel escribe
`unneccesarily`, igual que el repo. Es errata del impreso y se conserva. Junto
con `a cit` de CC Antya 2.16 son las dos entradas nuevas de PRINT_ERRATA, y las
dos son de las que el propio documento reconoce como punto ciego: no salieron de
una divergencia con el texto digital —que ya traia la lectura del papel— sino
del OCR del escaneo.

## Clases de ruido confirmadas (ya filtradas por el script)

Palabra partida por el salto de página con la cabecera en medio · transliteración
sánscrita en blockquote (el diff la excluye a propósito) · etiquetas de cita
(`Bg. 4.7`, `Bs. 5.40`) · `sb`→`bhag` · `disciplic`→`discipline` (falso 23/23 en
CC, 9/9 en KB) · OCR `rn`→`m` (varna→vama) · palabra funcional suelta · números
de página y romanos.

Salen **vacías** y no hay que repetirlas: restos de HTML, entidades, ligaduras
tipográficas, llaves y guiones bajos. El corpus está limpio de marcado.

## Lo que el diff NO puede ver (comprobado 2026-08-08)

`diff_align_surya.py` normaliza antes de comparar: pasa a minusculas, **quita
diacriticos**, unifica comillas y borra el marcado de cursiva/negrita. Todo eso
es invisible para los candidatos y hay que buscarlo por separado.

- **Mayusculas**: barridos los 16 libros con escaneo. Solo TLC divergia, y mucho
  — el impreso de 1968 escribe `Holy Name` 73 veces y `holy name` CERO; el repo
  lo tenia todo en minuscula (179 ocurrencias, ya corregidas). Los demas libros
  cuadran con su impreso. **No repetir este barrido.**
  Ojo: en TLC `Spiritual Master` alterna en el impreso (111 vs 16), asi que ahi
  no cabe un cambio en bloque.
- **Diacriticos**: comparada la densidad impreso/repo en los 16 libros. El unico
  que salta es `easy-journey-to-other-planets` (impreso 0.01/1000 vs repo
  8.47/1000) y es **FALSA ALARMA**: la imagen de la p.30 muestra que el impreso
  SI los usa (`Śrī Kṛṣṇa`, `Bhagavad-gītā`); lo que falla es el OCR de ese
  escaneo, que va a doble pagina. No perseguirlo.
  TLC si carece de diacriticos de verdad (confirmado en cinco imagenes).
- **Cursivas**: barrido HECHO (2026-08-08). Dos angulos:
  1. *Mal formadas* — pares de asteriscos cuyo contenido empieza o acaba en
     espacio, que Markdown no renderiza. Hay que emparejar los asteriscos EN
     ORDEN por linea; una regex simple casa el cierre de una cursiva con la
     apertura de la siguiente y da 145.000 falsos positivos. Resultado real:
     **5 casos** en todo el corpus servido, ya corregidos. Saltar las lineas
     que empiezan por '* ' (son vinetas de lista, no cursivas).
  2. *Uso incoherente* — un termino en cursiva 100 veces y redondo 2. Salen 9
     terminos y 16 ocurrencias, casi todas legitimas: versos en blockquote,
     titulos de seccion y comienzos de frase. Poco rendimiento, no insistir.
  Quedan 3 en letters/1971 y 1972: asteriscos sueltos que abarcan parrafos
  enteros. NO tocados: no hay escaneo del impreso de esas cartas contra el que
  adjudicar.

- **Comillas**: el alineador tambien las normaliza. El corpus usa comillas
  RECTAS casi siempre; las curvas aparecen en bolsas y resultan ser la **huella
  de lo transcrito hace poco**: ssr/3 (112 curvas frente a 10 rectas, capitulo
  restaurado del impreso de 1977), lob/preface (16, sustituido por el de 1984),
  krp/2 (12, «Who Is Crazy?»). NO es un defecto: es un marcador de procedencia
  util para saber que paso por transcripcion manual. No normalizar sin motivo.

## Caza de huecos en SB y CC — HECHA (2026-08-09), resultado limpio

`huecos_sbcc.py` compara, capitulo a capitulo, las palabras que sirve el repo
con las del tramo de paginas del escaneo. 194 capitulos del SB y 50 del CC.

**No hay texto perdido.** Todos los capitulos salen entre 0,95 y 1,02 salvo dos,
y los dos son artefactos, no huecos:
- `sb/8/2` (0,618): el tramo de paginas se calcula del propio alineador y aqui
  abarca material de los capitulos vecinos. Comprobado: el impreso marca 8
  PURPORT en ese tramo y el repo sirve 10 significados. No falta nada.
- `sb/7/10` y `cc/madhya/9` salian a 0,17 y 0,47 con el rango min..max; se
  arreglo usando el GRUPO CONTIGUO mayor de paginas (un candidato suelto en otra
  parte del volumen disparaba el rango). Ojo con eso al reutilizar el script.

TRAMPA: el repo no marca los significados con la palabra PURPORT — son la prosa
que sigue a la traduccion en negrita. Un `grep PURPORT` da cero y hace creer
que el capitulo entero ha perdido los significados. Paso el 2026-08-09.

## Decisiones tomadas el 2026-08-09 (no volver a plantearlas sin motivo nuevo)

- **KRP**: el impreso de 1970 son cuatro piezas y se sirve una. «Who Is Crazy?»
  esta transcrita y el usuario decidio NO publicarla. Por coherencia tampoco se
  publican las otras dos: «About the Author» es material editorial de la BBT que
  el sitio no sirve en ningun libro, y «Introduction to the Bhagavad-gita As It
  Is» duplica la introduccion del BG, que ya se sirve completa. El libro queda
  como esta, y esto queda escrito para que no se re-abra cada vez que el barrido
  del indice lo senale.

- **tlk (Teachings of Lord Kapila)**: el packer lo genera pero NO esta en el
  catalogo en vivo (33 packs). Se mantiene fuera: publicarlo anadiria a las apps
  un libro que hoy no se ofrece. `upload_packs.sh` ya lo salta solo, porque
  comprueba cada pack contra el catalogo antes de subirlo.

- **Resumenes de capitulo**: su procedencia es el scrapeo de vedabase.io, pero su
  CONTENIDO ya se auditó contra los escaneos (58 entradas corregidas, 258
  cambios) y se volvio a verificar por muestreo el 2026-08-07. NO se van a
  rederivar desde cero: el coste es alto y el texto ya coincide con el impreso.
  Los dos scrapers siguen desactivados con un refuse en su primera linea.

## La capa de texto del PDF: segundo motor de OCR (2026-08-09)

Los PDF de `scan_vedabase` llevan **texto embebido** de un motor DISTINTO de
Surya. `pdftotext` lo extrae y da una segunda lectura independiente de cada
pagina. Se cachea en `capa_texto/` (43 MB, ignorado por git, se regenera solo).

Sirve incluso donde Surya falla: en p0125 la capa leia `Hiranygarbha` y Surya
`hiranyagarbha`; la imagen dio la razon a la capa.

### Lo que NO prueba, y costo un revert entero

La capa confirma lo que dice **esa pagina**, no lo que el alineador creia
senalar. Dos trampas, ambas comprobadas:

1. **La sustitucion es de fichero, la prueba es de pagina.** El primer pase
   aplico la evidencia de una pagina a TODAS las apariciones del fichero.
   Resultado: 227 de 644 pares eran ingles contra ingles (`what`->`not`,
   `may`->`many`, `words`->`word`, `toward`->`towards`) y `kb/86` recibio 405
   sustituciones. Hubo que revertir repo y D1.
   **Remedio, obligatorio:** garantia de recuento — solo se sustituye si el
   fichero tiene tantas ocurrencias como casos senalo el alineador. Mas los
   guardarrailes de diccionario y de sanscrito. De 985 "confirmados" quedaron
   342 sustituciones.

2. **El alineador se equivoca de pagina y los dos motores coinciden sobre el
   texto que no es.** Es el 3 % que sobrevive a los guardarrailes y solo la
   imagen lo detecta. Casos reales:
   - TLC cap.3: la "prueba" de `teachings` era el **titulillo** de la pagina.
   - SB 4.7.26: el cambio dejo «Even though You appear in the material energy,
     But. You are always free», que no es texto.
   - SB 3.23.17: cruzo la TRADUCCION («with coral daises») con el SIGNIFICADO
     («coral and diamonds») de la misma pagina.
   - LOB texto 17: el impreso dice `attached` pero la «tt» quedo sin tinta y
     los DOS motores leyeron `a ached`.

### Regla que queda

Un cambio de **una palabra** con recuento cuadrado y guardarrailes se puede
aplicar sin imagen. Un cambio **multipalabra** va SIEMPRE a imagen: ahi es donde
el desajuste de pagina rompe la frase. Y todo lo adjudicado por imagen se anota
`VERIFICADO` con la cita de pagina, para que no vuelva a proponerse (267 al
cerrar el 2026-08-09).

## Deshacer no es sustituir al reves (2026-08-09)

El primer borrador de `deshacer_imagen.py` revertia con una sustitucion
`scan`->`repo` en todo el fichero. Para 7 casos daba 12 sustituciones: habria
vuelto a tocar todos los `satisfied` del significado de sb-3.28.16 — el mismo
destrozo que se estaba reparando. **Se restaura el fichero desde git y se le
devuelven solo los pares confirmados.** Nunca a base de sustituir.

## Paridad: comparar palabras, no porcentajes (2026-08-09)

`verificar_paridad.py` compara repo contra D1 palabra por palabra y **dice cual
difiere**. El comparador anterior usaba `SequenceMatcher.ratio() < 0.9995`, y un
0,9995 escondia las 405 sustituciones de `kb/86` (significado de 190 KB).

Excluye de LOS DOS lados el verso (`> ...`), la glosa palabra-por-palabra (mas
de 3 guiones largos) y el devanagari/bengali: viven en las columnas
`verse_text`, `synonyms` y `devanagari`, no en `translation`/`purport`.
Contarlos daba 300 divergencias fantasma.

**kb/86 no cabe en una sentencia SQL** (190 KB -> `SQLITE_TOOBIG`). Se arregla
con REPLACE anclados al contexto, y las anclas hay que sacarlas con posiciones
de caracter: unir palabras con espacios falla en cuanto la frase cruza un salto
de linea.

## Divergencias repo <-> D1 anteriores a esta sesion — SIN ADJUDICAR

Al comparar salieron 18 divergencias que **no vienen de ningun pase de hoy**.
Estan en `divergencias_preexistentes.json` y NO se han tocado. Varias huelen a
texto de la edicion REVISADA colado en D1, que es justo lo que vedabase.cc no
debe servir:

| ref | D1 sirve | repo dice |
|---|---|---|
| cc/madhya/8/288 | golden-complexioned | **white-complexioned** |
| cc/adi/13/61 | trunks and sub-trunks | branches and sub-branches |
| cc/adi/5/41 | aphorism (x6) | verse |
| cc/adi/17/281 | constitute | are |
| kb/29 | Indian | India |
| kb/74 | hairs (x3) | hair |
| tlc/0d | alone, ... (16 bloques) | only, ... |

Pendiente: adjudicarlas contra el escaneo como todo lo demas.

## La clase `op=delete` no se puede aplicar en automatico (2026-08-11)

`op=delete` son los candidatos en los que el repo tiene texto y el escaneo no.
Se quedaron 289 sin procesar durante toda la auditoria porque todas las colas se
construian a partir de pares `repo -> scan`, y estos tienen el `scan` vacio.

Adjudicados uno a uno sobre la imagen dieron 196 NO_ESTA / 47 ESTA /
31 DISTINTO. Pero el ensayo del aplicador demostro que **ese primer veredicto no
basta para borrar**. En una muestra de 14 supresiones, cuatro dejaban la frase
rota:

| caso | quedaba |
|---|---|
| cc-adi-4.60 quita `śakti` | `*hlādinī-,*` — guion colgando |
| cc-adi-1.3 quita `Kṛṣṇa` | «the Supreme Personality of Godhead, Himself,» |
| cc-adi-2.18 quita `aggregate of` | «the Supersoul of the total living entities» |
| cc-adi-6.74 quita `Like the previous verse` | `"**, this verse appears` |

El patron es siempre el mismo: **el OCR parte los compuestos con guion, se pierde
en la cursiva y falla en las lineas en negrita de la traduccion**. Ahi el texto SI
esta impreso y el NO_ESTA es un falso positivo.

Reglas que quedan:

1. Un NO_ESTA **nunca** se aplica solo. Hace falta una segunda pasada por imagen
   que vea **como quedaria la frase** y responda SUPRIMIR / CONSERVAR.
2. Ante la duda, CONSERVAR. Sustituir una grafia es reversible mirando el
   fichero; borrar texto no deja rastro de que hubo algo.
3. Borrar no es sustituir: hay que cerrar la costura. `aplicar_supresion.py`
   absorbe los `*...*` y los `(...)` que se quedan vacios y arregla la
   puntuacion **solo en la juntura**, nunca en el resto del parrafo.
4. Triaje automatico antes de mirar: guion colgando, asteriscos descompensados,
   nombre propio a media frase, toca linea en negrita. Marco 62 de 152. Pero las
   90 «limpias» tampoco son fiables — entre ellas estaba quitar «The word» de
   «The word *asura* refers to...» —, asi que se verifican TODAS.

## La clase `op=insert`: lo que le FALTA al texto digital (2026-08-11)

Cerrada la clase `delete` (texto que la digital anadio), queda la espejo: 258
candidatos `op=insert`, texto que el ESCANEO trae y el repo no. Nunca se habia
mirado, por el mismo motivo que la otra: las colas se construian con pares
`repo -> scan` y aqui el `repo` viene vacio.

Cuatro filtros, en este orden, y cada uno tumba una tanda:

| filtro | quita | por que |
|---|---|---|
| el texto YA esta en el fichero | 58 | el alineador no cruza verso, glosa y significado |
| etiqueta «TEXT N» del impreso | 58 | el impreso rotula los versos, el repo no |
| cobertura de palabras >= 85 % | 58 | el OCR lee las columnas en otro orden y trocea el verso |
| ruido (`puurport`, `ix`, numeros) | 8 | titulillos y foliacion |

Quedan **76 huecos reales** por adjudicar sobre la imagen.

Lecciones:

1. Comparar por CADENA CONTIGUA no vale para el verso. El OCR salta lineas y el
   fragmento no aparece literal aunque el verso este entero. Hay que medir
   cobertura de palabras.
2. La etiqueta «TEXT 12» y el titulillo («Madhya-lila, Ch. 23», «82 Perfect
   Questions») se pegan al texto y disfrazan de hueco lo que no lo es.
3. Un hueco confirmado es mas grave que una insercion: significa que hay texto
   de Prabhupada que no se esta sirviendo. Pero por lo mismo, un FALTA falso
   mete texto inventado en el libro. Ante la duda, YA_ESTA.

## `content/en` no es una copia del repo — y esta mas cerca del impreso

Al sincronizar las 116 supresiones salio que los 96 ficheros de `content/en`
YA divergian del repo. Y en que direccion: **85 de 96 supresiones acercan el
repo a lo que `content/en` ya decia**, sin haberlo consultado nunca. Es una
corroboracion independiente de toda la campana.

Los 11 restantes son casos en que `content/en` tambien arrastra la insercion
(cc/adi/7/17, cc/adi/13/82, cc/adi/17/7, cc/madhya/6/255, 8/257, 8/258, 8/5,
8/68, 9/68, 10/136, 10/143). No es el impreso: es otra copia digital.

## `ref_de()` no distingue idioma — trampa abierta

Las traducciones viven en `translations/<idioma>/...` con el MISMO nombre de
fichero, y `ref_de()` las mapea a la misma referencia que la inglesa. Tocar la
version rusa de `cc-madhya-9.47` y sincronizar habria escrito ruso en la fila
INGLESA de D1. No llego a pasar, pero el camino estaba abierto:
`sincronizar_diff.py` ya filtra `translations/`.

## Los PDF ClearScan mienten: texto en modo INVISIBLE (2026-08-11)

Dos de los escaneos NO son imagenes de la pagina sino PDF tipo **ClearScan**, con
fuentes sintetizadas: la *Bhagavad-gita* 1972 (Macmillan) y el *Sri Isopanisad*
1969. Y llevan tramos de texto marcados con modo de render invisible (`3 Tr`).

Al renderizarlos con `pdftoppm` esos tramos salen **en blanco**. Justo donde el
alineador reporta una supresion. Un adjudicador miro la pagina 470 de la Gita a
600 dpi, vio el hueco, y concluyo —razonablemente— que el impreso tenia un
defecto de composicion: «and become ___ blissful». Se quito «eternally».

Era falso. Revelando el texto invisible, la pagina dice
«and become **eternally** bliss-». Revertido.

Receta para revelarlo:

```
mutool merge -o p.pdf <pdf> <pagina>
mutool clean -d p.pdf pc.pdf
python3 -c "d=open('pc.pdf','rb').read(); open('pv.pdf','wb').write(d.replace(b' 3 Tr', b' 0 Tr'))"
pdftoppm -f 1 -l 1 -r 400 -png pv.pdf out
```

La sustitucion conserva la longitud del stream, asi que el PDF sigue siendo
valido. La pagina 470 de la Gita tenia 3 tramos invisibles; la 407, 7; la 78 del
Isopanisad, 1. Los volumenes del Caitanya-caritamrta tienen 0 — esos si son
escaneos normales.

**Regla:** antes de dar por bueno un HUECO EN BLANCO en la Gita 1972 o el
Isopanisad 1969, revelar el texto invisible. En los demas libros no hace falta.

Comprobado: de todas las adjudicaciones de la sesion, solo 5 salieron de esos
dos PDF. Cuatro eran transcripciones de palabras que se leen bien
(`all blissful` -> `all-blissful`, `are` -> `is`) y no dependian de ningun
hueco. La quinta era `bg/8/18`, ya revertida.

## Insertar texto puede duplicar la frase siguiente

Al restaurar el hueco de `sb/3/31/14` («for the reason that») quedo:

    ...material senses for the reason that He is above the influence of material
    nature, for He is above the influence of material nature and cannot...

El guardarrail de «ya insertado» comparaba el literal de lo que se iba a meter
con lo que venia detras. No caso porque lo que seguia era la MISMA frase con
otro arranque. Ahora se compara tambien el NUCLEO (las ultimas palabras), que es
lo que se repite cuando la variante cambia solo el principio.

## Cierre de la auditoria (2026-08-11): 9.535 candidatos, 0 abiertos

Los tres arreglos que llevaron de 507 abiertos a 0 no estaban en el texto sino
en las herramientas:

1. **El titulillo pegado al texto.** 219 candidatos no se habian adjudicado
   nunca porque la lectura del escaneo no era texto del libro sino la cabecera
   de la pagina («purusas or» -> «purusahs or the sky beyond the universe 49»).
   Con eso delante nadie puede decidir. `quitar_titulillos.py` los reconoce sin
   lista a mano: son la primera o la ultima linea de la pagina y se repiten en
   muchas paginas del mismo libro.

2. **RUIDO no era terminal en el ledger.** Solo lo eran APLICADO, DESCARTADO y
   VERIFICADO, asi que los cierres «alguien miro la imagen y coincide con el
   repo» seguian contando como abiertos. 271 -> 130.

3. **La clave del `scan`, tres veces.** El campo existe en tres formas: la sucia
   del alineador (con titulillo), la limpia de los lotes y la transcrita de los
   aplicadores. SOLO la sucia cierra el candidato. Esto costo dos pasadas: 216
   correcciones sin registrar por la manana, y 101 de 103 sin cerrar por la
   tarde.

Estado final de D1: 259 correcciones llegaron, 78 de 80 supresiones llegaron, y
51 casos donde D1 dice una tercera cosa — divergencias ANTERIORES a este
trabajo, listadas en `divergencias_d1_anteriores.json`, sin tocar.

## D1 tambien hay que barrerlo: cinco filas quedaron rotas (2026-08-11)

El barrido de integridad mira el REPO contra git. D1 no lo miraba nadie, y ahi
tambien se rompe: un `REPLACE(campo, viejo, nuevo)` con un ancla mal escogida
deja la frase duplicada o truncada. Cinco filas salieron asi de las
sincronizaciones de hoy:

    cc/madhya/9/1    «saved the elephant from the clutches saved the elephant
                      from the Mahaprabhu saved the elephant from the clutches»
    cc/madhya/9/360  «no es aceptada por Sri philosophical speculation is not
                      accepted by Sri Caitanya Mahaprabhu»
    sb/5/26/40       el colofon de Honolulu, tres veces seguidas
    cc/madhya/8/69   «transcendental bliss activities performed the Lord is
                      worshiped with pure love, transcendental bliss is awakened»
    sb/7/9/34        la nota al pie duplicada en los sinonimos

Como se detectan sin mirarlas una a una: se buscan n-gramas de 6 palabras que se
repitan a menos de 15 palabras de distancia, y se compara con el MISMO fichero
del repo. Si la repeticion esta en D1 y no en el repo, es dano.

    de 283 refs tocadas hoy -> 97 con la deteccion suelta (4-gramas, sin
    comparar con el repo: casi todo falsos positivos, «in front of the»)
                            ->  5 comparando contra el repo

**Regla:** despues de cada tanda de sincronizacion, pasar esta comprobacion. El
barrido contra git no la sustituye: son dos copias distintas y cada una se
rompe a su manera.

## El diff completo: que regiones cubre y cuales no (2026-08-11)

Cerrada la auditoria, esto es lo que se ha comparado de verdad y con que
herramienta:

| region | pasada | candidatos |
|---|---|---|
| prosa (translation + purport) | `diff_align_surya.py` | 6.860 |
| glosa palabra por palabra | `diff_align_surya.py --synonyms` | 2.675 |
| verso en transliteracion | `diff_verso.py` (NUEVO) | 578 utiles |
| devanagari / bengali | `diff_verso.py --indio` (NUEVO) | ver abajo |

Base: **cero paginas de PDF sin OCR** en los 21 libros con escaneo. Los tres
libros del repo sin OCR —lectures-and-conversations, letters,
life-comes-from-life— no tienen escaneo porque no son libros impresos.

### El verso: por que nadie lo habia mirado

`diff_align_surya.py` lo salta a proposito en CC y SB (`VERSE_STRUCTURED`): el
repo lo formatea distinto y alinearlo metia ruido en cada frontera. Cierto, pero
dejaba sin comparar la parte mas delicada del corpus.

`diff_verso.py` lo compara. Cuatro filtros, cada uno sacado del ruido del
anterior, llevan de 1.577 candidatos a 16 utiles:

  separacion de palabra   'sva-janam' / 'svajanam': el guion se vuelve espacio
  titulillo               por frecuencia: lo que se inserta en muchos versos
  confusion del OCR       y/v, i/l, n/u, rn/m — no es divergencia, es el escaneo
  rareza en el corpus     la forma del repo aparece UNA vez y la del escaneo es
                          comun. Este es el que de verdad separa

De los 16: tres erratas reales, y todas con la MISMA firma —el fichero se
contradice a si mismo, porque el indio y la glosa dicen una cosa y la
transliteracion otra—, que es la unica excepcion que admite la regla del
impreso:

    cc/madhya/12/154-155   sankoca -> santosa   (bengali সন্তোষ, glosa santosa)
    cc/madhya/9/289        ek -> ei             (bengali এই, glosa «*ei*—this»)
    cc/adi/13/7            pacne -> pache       (bengali পাছে, glosa pache)

Siete eran SANDHI legitimo (grhnanty, smasrv, sarvesv, phalgv, dharmesv,
trtiyo, asv) o particion tipografica del compuesto (naksatran-indoh, que el
devanagari escribe नक्षत्राणीन्दोः). El tokenizador las troceaba.

### El indio: se puede comparar, pero rinde poco

Surya lee el bengali bien (parecido 1,000 en la prueba). Pero comparar caracter
a caracter saca sobre todo `ँ` frente a `ं` —distincion vedica real que el OCR no
distingue— y fallos de ligadura. 31 candidatos en el Isopanisad, ninguno
accionable sin verificacion manual masiva.

### Y una trampa que costo cara

Cuatro corridas del alineador de julio (`out_surya2..5`) estaban en carpetas que
el ledger no leia: 459 candidatos que nadie habia visto. Al incorporarlas
aparecieron ocho erratas reales —entre ellas «Thus end the Bhaktivedanta
purports to the EIGHTEENTH CANTO» en sb/6/18/78, cuando el Bhagavatam tiene
doce— pero tambien 97 candidatos sacados de la edicion INDIA de Easy Journey
(~1960), que es otro texto. `books.json` ya la declaraba en `no_repo_match`; el
ledger no miraba ese campo. Ahora si.

**Regla:** si se generan carpetas de salida nuevas, hay que anadirlas a
`OUT_EXTRA` en `build_ledger.py` — y el filtro de `no_repo_match` es
obligatorio, no opcional.

## La coherencia interna: el indio contra su propia transliteracion

El repo lleva cada verso DOS veces —en escritura india y en transliteracion— y
tienen que decir lo mismo. Compararlos entre si no necesita el escaneo, y por
tanto no hereda el ruido del OCR, que en devanagari y bengali es inservible: el
61 % de las lineas del Caitanya-caritamrta no casan letra a letra con el OCR sin
que el texto difiera en nada.

`coherencia_verso.py` translitera el indio del propio fichero y lo compara con la
linea latina que el fichero ya trae. De 13.904 discrepancias crudas a 71
accionables, por este orden:

| filtro | de | a | por que |
|---|---|---|---|
| b = v | 13.904 | 6.927 | el bengali NO distingue b de v: la misma letra ব |
| vocal doblada | | | 'prakasiyaa' sale de juntar la matra con la 'a' implicita |
| anusvara m = n | 6.927 | 6.823 | el indio usa UN signo; la transliteracion elige m/n/ng/ny |
| **una sola letra** | 6.823 | **54** | si difieren en mas, es sandhi o compuesto partido |

Y un fallo propio que costo una vuelta: el bloque de consonantes indico tiene
DOS letras extra (ऩ en 0x29 y ऱ en 0x31) que mi tabla no contaba, asi que todo
salia desplazado a partir de la 'ma'. Corregido, el transliterador da 1,000
exacto en el caso de control.

### Lo que encontro: seis corrupciones en la escritura india

Nadie las habia mirado nunca, y ninguna se veria leyendo el ingles.

    cc/adi/4/264    আস্বাদিল (pasado)  -> আস্বাদিব (futuro)   «I shall taste»
    cc/adi/4/265    শিখাইল             -> শিখাইব              «I shall teach»
    cc/madhya/4/2   গৌড়ভক্তবৃন্দ        -> গৌরভক্তবৃন্দ         34 veces গৌর en el escaneo, 0 গৌড়
    cc/antya/16/147 বহু দূরে           -> রহু দূরে            «rahu dure—leaving aside»
    cc/madhya/10/143 ষুয়ায়            -> যুয়ায়              ষুয়ায় no es palabra bengali
    bg/2/9          परन्तप             -> परन्तपः             faltaba la visarga
    bg/18/44        कृषिगौरक्ष्य         -> कृषिगोरक्ष्य          गौ por गो, «vaca»
    bg/18/66        त्वा               -> त्वां                faltaba el anusvara

Todas comparten la firma de siempre: **el fichero se contradice a si mismo**, que
es la unica excepcion que admite la regla de respetar el impreso. Y aqui la
parte corrompida era, casi siempre, la ESCRITURA INDIA — la que nadie lee.

**Regla:** `sincronizar_diff.py` tiene que mirar las cinco columnas de D1
(purport, translation, synonyms, verse_text, devanagari). Le faltaban las dos
ultimas y las correcciones del verso y del indio no llegaban.

## El modo `--fine`: por que no produce nada, y por que eso es el resultado

`diff_align_surya.py --fine` conserva diacriticos y puntuacion como tokens, para
cazar lo que la normalizacion estandar hace invisible. Nunca se habia corrido.
Corrido sobre los 21 libros: **24.035 candidatos, ninguno accionable.**

Los dos ejes que pretendia auditar fallan por el mismo motivo — el OCR no llega:

**Diacriticos** (11.811 casos donde las letras coinciden y solo cambian las
marcas). Los mas frecuentes:

    5468  kṛṣṇa  -> krṣṇa      el escaneo se come el punto de la ṛ
     744  ṭhākura -> thākura
     172  parīkṣit -> parikṣit
     132  śrīla   -> śrila

**Puntuacion** (7.090 casos). Los mas frecuentes:

    1346  ,  -> (nada)          el OCR se come comas
     972  -  -> —               largo del guion
      78  godhead -> god - head particion de linea del impreso

Ni uno solo es una divergencia del texto. Es exactamente por esto que la pasada
estandar normaliza las dos dimensiones fuera: no es descuido, es que el escaneo
no puede testificar sobre ellas.

**Conclusion util:** para diacriticos y puntuacion, el unico testigo valido es la
IMAGEN leida por una persona (o un adjudicador mirando el pixel), nunca el texto
del OCR. Que es justo el metodo que se ha usado todo el dia para las
transcripciones.

---

## Publicacion (12-ago). Tres trampas que costaron tiempo

**1. `$VAR` con varias palabras no se parte en zsh.** La herramienta de shell
corre zsh, y zsh NO hace *word splitting* de una expansion de parametro sin
comillas. Esto:

    WR="env -u CF_API_TOKEN npx wrangler"
    $WR r2 object put ...            # -> «command not found», exit 127

busca un ejecutable llamado literalmente `env -u CF_API_TOKEN npx wrangler`. Los
63 ficheros dieron FALLO y el comando escrito a mano funcionaba: esa contradiccion
es la firma del problema. Igual con `for id in $IDS`, que recorrio UN solo elemento
con los 21 ids pegados. Lo que si se parte en zsh es la sustitucion de comandos,
`$(cat fichero)`. Solucion: funcion de shell (`wr() { env ... npx wrangler "$@"; }`)
o array.

**2. `build_all.py` publica lo que encuentre en `frontend/data`, no lo del
catalogo.** El catalogo en vivo tenia 33 packs; despues de `finish_packs.sh` tenia
34. El nuevo era `tlk` (Teachings of Lord Kapila) con `verse_count: 0`, y ademas su
cache de D1 se habia descartado por vieja (14-jun). Habria aparecido en las apps un
libro vacio. Un `sync` de correcciones no debe cambiar la superficie publicada:
se quito del catalogo con `jq 'del(.packs[]|select(.id=="tlk"))'` y se volvio a
subir. **Comparar siempre la lista de ids antes y despues**, no solo el numero.

**3. Las descargas se sirven en `vedabase.cc/downloads/`, no en
`downloads.vedabase.cc`.** El segundo host no resuelve y `curl` devuelve `000`,
que parece un fallo de la subida cuando en realidad los 63 ficheros estaban bien.

**Y un recordatorio del orden.** `build_pack.py <id>` solo sabe de los libros de
`index.json`: `sb-3`, `cc-adi` y demas subpacks no existen ahi, los genera
`build_all.py` partiendo `sb` y `cc`. Pero antes de construir nada hay que
refrescar `frontend/data` desde D1 (`cache_to_d1md.py` + `refresh_*_from_d1.py`),
o los packs salen con el texto de la fecha del ultimo refresco. `finish_packs.sh`
encadena los cinco pasos en el orden correcto y sube los packs ANTES que el
catalogo; usarlo en vez de ir a mano.

---

## Verificar los ebooks publicados. Cinco falsos negativos

Comprobar que el fichero se subio (un 200) no comprueba nada del contenido. Lo
que hay que preguntar es si el EPUB, el PDF y el MOBI que sirve vedabase.cc
dicen HOY lo que dice el repo. Herramienta: `verificar_ebooks.py`.

**Las sondas salen del diff de git, no de `corrections.jsonl`.** El ledger no es
fiable como indice de lo cambiado: las correcciones de Easy Journey de este dia
quedaron fechadas el 3-ago, y las hechas a mano no estan. Del diff se cogen
lineas que el repo dice ahora y no decia ayer, exigiendo que sean
DISCRIMINANTES (si el cambio es solo un diacritico, una comparacion que ignora
diacriticos no prueba nada) y UNICAS en su fichero.

**Cinco cosas hacian parecer que faltaba texto que si estaba.** Las cinco son de
la extraccion, no del libro; conviene reconocerlas antes de acusar al generador:

  1. `pdftotext` SIN `-layout` pierde palabras en las lineas muy justificadas.
     `...attachment for Krsna consciousness` salia `...attachment for
     consciousness`. Con `-layout` aparece. Costo 15 libros en falso.
  2. El numero de pagina se cuela dentro del parrafo: `...stood before` **351**
     `Krsna...`. Se quitan antes las lineas de solo numero y las que se repiten
     mucho (los titulillos), y se compara sin digitos.
  3. La ultima linea de un parrafo en NEGRITA se pierde al extraer (cambio de
     fuente): `engaged in discharging` sin `devotional service`. En la pagina
     renderizada esta entera.
  4. El devanagari del PDF **no se puede recuperar**: las conjuntas no llevan
     mapeo inverso y salen descolocadas (`कृ गनो क्ष्` por `कृषिगोरक्ष्य`). El PDF
     tiene un 11 % menos de caracteres devanagari que el EPUB solo por esto.
  5. La normalizacion «exacta» usaba `\W`, y en Python las matras y el virama no
     cuentan como caracter de palabra: se borraban, y 'गो' y 'गौ' quedaban
     iguales. Hay que conservar todo lo que sea letra (L*) o marca (M*).

**Para el devanagari del PDF no hay comprobacion textual. Se mira la pagina:**

    pdftoppm -f <pagina> -l <pagina> -r 130 -png libro.pdf /tmp/pag

Asi se confirmaron bg 2.9 (परन्तपः con visarga), bg 18.44 (कृषिगोरक्ष्य con गो) y
bg 18.66 (त्वां con anusvara), mas los dos parrafos truncados de sb-3.25.24 y
sb-4.13.8-9.

---

## Los packs de la app. Dos huecos que el refresco desde D1 no cubre

El sha256 del catalogo cuadrando con el del pack solo dice que el fichero es el
que el catalogo anuncia. No dice que su CONTENIDO sea el de hoy. Comprobado el
contenido, aparecieron dos huecos, y los dos por la misma razon: hay partes del
pack que `refresh_verses_from_d1.py` / `refresh_prose_from_d1.py` no tocan.

**1. La escritura india no viaja en el volcado.** `cache_to_d1md.py` reutiliza la
cache de los ebooks, y esa cache trae cinco columnas —ref, verse_text, synonyms,
translation, purport— pero NO `devanagari`. `refresh_verses_from_d1.py` lo dice en
su cabecera: «devanagari/title -> PRESERVED (D1 dump has no devanagari)». O sea
que **ninguna correccion en devanagari o bengali ha llegado nunca a los packs**.
Eran 10, y se aplicaron a mano sobre `frontend/data` con ancla unica:

    bg/18/44 गौ->गो · bg/18/66 त्वा->त्वां · bg/2/9 परन्तप->परन्तपः
    bg/6/8 समलोष्ट->समलोष्ट्र · cc/adi/4/264 আস্বাদিল->আস্বাদিব
    cc/adi/4/265 শিখাইল->শিখাইব · cc/antya/16/147 বহু->রহু
    cc/antya/2/160 নবদ্বীপে->নবদ্বীপ · cc/antya/1/156 করিয়াছে->করিয়াছ
    cc/madhya/4/2 গৌড়->গৌর

Al medirlo salian 1.499 «divergencias»; 1.489 eran tipografia —el repo usa la
danda devanagari `।` y el pack la bengali `৷`, y el pack repite el numero de
verso—. Hay que comparar SOLO letras y marcas (categorias L* y M*), o el ruido
tapa los diez casos reales.

**2. Las secciones introductorias salen de otro fichero.** `build_pack.py` toma
prefacios, prologos e introducciones de `packer/prose-chapters.json` (14 libros),
y ese fichero no lo refresca nadie: `refresh_prose_from_d1.py` escribe en
`frontend/data`, que para esas claves se ignora. Resultado: sirven el texto de la
edicion revisada. Con texto realmente distinto del de D1: tlc (0a, 0b, 0c, 0d),
nod 0a, ssr 0b y bg 0a. En tlc se ve a simple vista —el pack dice «Lord Caitanya»
y «Kṛṣṇa», y el impreso «Lord Chaitanya» y «Krishna»—.

**Y un desajuste de claves en la cache de los ebooks.** El repo y D1 coinciden:
`prologue.md` es `tlc/0b` e `introduction.md` es `tlc/0d`. La cache de
`regen_books` los trae AL REVES, y de ahi pasa al EPUB, al PDF y al MOBI: el
capitulo titulado «Prologue» lleva dentro la Introduccion. El pack no lo hereda
porque su contenido viene de `prose-chapters.json`.

**Como se comprueba un pack.** Es SQLite comprimido: `gunzip -c x.vbpack.gz > x.db`
y luego la tabla `content` (key, lang, title, devanagari, text, synonyms,
translation, purport, blocks) mas el indice FTS5 `search`. El texto va en HTML:
sin quitar las etiquetas, `<em>māyā</em>` normaliza a «emmayaem» y 17 de 21 packs
parecen no llevar la correccion. Y el gzip no es determinista —dos compilaciones
del mismo contenido dan sha distintos—, asi que para saber si un pack cambio de
verdad hay que comparar la HUELLA DE `content`, no la del fichero. Aqui eso
redujo «los 33 cambian» a los 4 que cambiaban de verdad, y evito obligar a cada
app a rebajarse 70 MB.

---

## 392 correcciones que nunca llegaron a D1, y como aparecieron

**No se buscaban.** Al cargar la tabla `notes` se comprobo lo obvio: que el ancla
de cada nota existiera en el texto de D1, porque sin ancla la nota no tiene donde
colgarse. Doce no aparecian. No era que el ancla estuviera mal — **era que la
correccion no estaba en D1**. En `sb/7/7/15` el repo decia `darmān` y D1 seguia
con `dharmān`; en `nod/21`, `Yushiṣṭhira` frente a `Yudhiṣṭhira`.

Auditadas las 2.792 correcciones vivas del ledger contra D1: **389 no habian
llegado**, mas 15 donde D1 decia una tercera cosa. 370 de ellas eran de una sola
tanda, la del 9 de agosto: se escribieron en el repo y no se sincronizaron. El
sitio llevaba desde entonces sirviendo el texto sin corregir en esos puntos.

**Por que la verificacion diaria no lo veia.** `verificar_correcciones_d1.py`
recibe `--fecha` y por omision mira el dia. Comprueba muy bien lo de hoy y no
mira nada de ayer. Una correccion que falla el dia que se hace se ve; una que se
queda atras no se vuelve a mirar nunca. Por eso `empujar_todas_d1.py` recorre el
ledger entero sin filtro de fecha, y conviene pasarlo de vez en cuando.

**Dos anclajes, no uno.**

  `empujar_todas_d1.py` — ancla por la palabra, exigiendo que aparezca una sola
  vez en la fila. Coloco 288.

  `empujar_con_contexto_d1.py` — para lo que sale repetido (`appeared` tres veces
  en el mismo purport y solo una cambia). Se toma del repo el tramo alrededor de
  la correccion, se reconstruye como estaba ANTES, y se busca en D1: en cuanto
  aparece una sola vez ya se sabe cual es. Anchuras crecientes (4, 8, 15, 30
  palabras) y se para en la primera que basta, para mover lo minimo. Coloco 82,
  con cero cambios colaterales.

**El fallo que costo la mitad de esos 82.** La primera version reconstruia el
tramo uniendo palabras con espacios, y eso rompe justo el caso mas frecuente:
cuando lo que cambia esta DENTRO de una palabra compuesta. En `*sarva-darmān` la
palabra de la izquierda es `*sarva-`, y al volver a unir salia `*sarva- darmān`,
que no existe en ninguna parte. Hay que cortar por indices de caracteres y
respetar el texto tal cual.

**Y el mismo `sd()` de siempre.** El de `empujar_todas_d1.py` reducia a
`[A-Za-z0-9]`, con lo que el devanagari desaparecia entero y las diez
correcciones de escritura india salian como «sin ancla» aunque ya estuvieran
puestas. Es la tercera vez que este fallo aparece en un fichero distinto: cuando
se copie una funcion de normalizacion, mirar si el texto puede ser indio.

**Resultado:** 390 de las 404 colocadas y verificadas en vivo, mas dos que ni
siquiera figuraban en el ledger y aparecieron por las anclas. Quedan 14 en
`sin_colocar.json` que necesitan mano: son sustituciones donde D1 y el repo
difieren demasiado alrededor como para anclar con seguridad.

## Los ultimos catorce, y un defecto del repo

De las 404 que no habian llegado, catorce no se pudieron colocar ni con treinta
palabras de contexto. Mirandolas una a una salieron tres cosas distintas:

**Dos se aplicaron sin problema** una vez visto que D1 decia una tercera cosa,
no la vieja: `cc/adi/13/61` («merged the two trunks into one» por «branches») y
`sb/8/8/41-46`, que es el mas llamativo — el colofon de D1 decia «the Tenth
Canto, Tenth Chapter» en un verso del canto OCTAVO, capitulo octavo. Corrupcion
evidente, del mismo tipo que la de `sb/6/18/78`.

**Una ya estaba bien de otra forma:** `sb/3/20/23` — el ledger pedia «from his
buttocks» -> «from his backside» y D1 ya decia «from the backside».

**Y una es un defecto NUESTRO, no del impreso.** En `tlc/28` el repo trae
`Durbasamaniwanted` y `Durbasamaniwas`, con las palabras pegadas. Eso no se
propaga a D1: hay que arreglarlo en el repo mirando la pagina. Un barrido de todo
el corpus —token raro que al partirse da dos palabras frecuentes, restringido a
los libros y a funcionales de cuatro letras o mas— devuelve 337 resultados y 336
son palabras inglesas normales (`Thereafter`, `Elsewhere`, `Everywhere`). El de
`tlc/28` es el unico caso real, asi que no hay un problema sistematico.

**Aviso sobre ese barrido:** buscar «mayuscula + palabra funcional» sin filtrar
da 4.977 falsos positivos, porque `am`, `is` y `as` son terminaciones sanscritas
comunes: `Bhāgavat`+`am` sale 3.735 veces. Hay que excluir las funcionales de
dos y tres letras, y dejar fuera transcripciones, cartas y `legacy-vedabase-site`.

**Queda pendiente de mirar con la imagen:** `cc/madhya/9/79`, donde el repo trae
una `Kumbhakoṇam` y una `Kumbhakonṇam` —la correccion se aplico a una sola de las
dos ocurrencias— y hay que decidir si el impreso las escribe distinto o fue un
despiste.

---

## Revisar las 77 erratas con lupa. Un falso positivo y siete mal situadas

De donde salio. El usuario miro la imagen de `sb/1/2/20` y dijo: «pone sattva,
pero un poco faint». Tenia razon. A 600 ppp la letra tiene el trazo diagonal de
una **v** cursiva, no el hombro de una **r** —se compara con la «r» de «or the
mode» en la misma linea—. La `v` habia salido debil y en su dia se leyo como `r`.

**Y eso no era solo un sobrante de la lista: habiamos CAMBIADO EL TEXTO** hacia
algo que el impreso no dice. `sattra-guṇa` restaurado a `sattva-guṇa` en el repo
y en D1, y la entrada retirada. Quedan 76.

**Lo que el automatismo no puede hacer.** En ese caso **el OCR de Surya tambien
leyo «sattra»**, asi que la comprobacion «¿esta la forma impresa en el OCR de esa
pagina?» daba que si. Para un glifo con el trazo debil no hay verificacion que
valga: solo el ojo sobre la imagen ampliada. Las 76 se han mirado una a una.

**Siete estaban mal situadas**, todas por la misma causa —la palabra buscada
existe tambien en otro sitio—:

  · `cc/madhya/1/220` y `cc/madhya/3/28` apuntaban al PDF de **Adi-lila**; la
    segunda caia ademas en un pie de lamina («binds Me as her son»)
  · `sb/5/3/3` al canto 1 y `sb/4/30/18` a otro volumen del canto 4
  · `kb/64` y `kb/81` compartian una pagina del volumen 1 que no era de ninguna
  · `ekc/4` y `sb/5/18/17` caian en la ocurrencia de otro capitulo

**Dos comprobaciones que lo cazan de raiz, y que conviene pasar siempre:**

    # el volumen del escaneo tiene que corresponder a la seccion del ref
    cc/adi -> adi*   cc/madhya -> mad*   cc/antya -> ant*   sb/N -> SBN.*
    # y dos erratas distintas no pueden compartir pagina
    SELECT sub, page, COUNT(*) FROM ... GROUP BY sub, page HAVING COUNT(*) > 1

**Un aviso sobre los recortes.** En `mad1.pdf` la capa de texto NO esta alineada
con la imagen: la linea que el PDF situa en y=241 aparece bastante mas abajo. Por
eso las imagenes publicadas son la PAGINA ENTERA y no una banda. Una banda guiada
por coordenadas puede caer en cualquier sitio y no hay forma de saber que PDFs lo
padecen sin mirarlos.

**Lo que salio de mirar, y no sabiamos.** El impreso se contradice a si mismo mas
de lo que pensabamos: en `cc/madhya/3/28` los sinonimos ponen `sun-god` y la
traduccion `son-god`; en `cc/adi/1/97` la glosa dice `space` y la traduccion
«pots and plates»; en `cc/madhya/20/246` la lista de avataras imprime «(1) Yajña»
y cuatro lineas despues «Yaja»; en `sb/8/19/13` conviven `enmity` y `emnity`; en
`kb/86`, `abdomen` y `adbomen`. Ninguna se ha tocado —la contradiccion no esta
dentro de la misma frase, que es lo unico que la regla admite— pero son los casos
mas discutibles de la lista y conviene tenerlos localizados.

## El campo `synonyms` no lo cotejaba nadie (15-ago)

El diff de Surya, la paridad repo/D1 y el arbitraje por pagina miran la
traduccion y el significado. La lista `palabra—glosa` no la miraba ninguno. Y es
justo donde los reemplazos masivos hicieron mas dano, porque una glosa de dos
palabras se rompe sin que salte nada:

    bg/3/14      «parjanyāt—from rain»    el impreso: «from rains»
    sb/3/8/30    «śṛṅgam—peas»            el impreso: «peaks»
    cc/adi/7/64  «prabhu kahe—the Lnnord replied»
    sb/3/31/17   «vivthere is—in the abdomen»   la clave era «vivare»: are -> there is

62 divergencias en 20.293 filas. 53 las gana el repo; nueve las gana el impreso
contra el repo, entre ellas una restauracion de «foodstuffs» que se paso de
sitio (`cc/madhya/3/82`, donde el papel dice «anna—food»).

**Tres trampas al comparar este campo**, cada una costo una pasada en falso:

1. Comparar por conjuntos no vale. El `.md` entero partido por `;` no tiene los
   mismos limites que el campo de D1: salian 40.000 falsos positivos.
2. La subcadena sola tampoco. «from rain» ES subcadena de «from rains», asi que
   la divergencia de `bg/3/14` se colaba. Hace falta limite de palabra detras.
3. La clave no se puede partir por guion normal. `re.split(r'[—–-]', ...)`
   dejaba «mokṣa-vāñchā» en «mokṣa» y luego no habia contraparte en el repo:
   16 casos en falso. Solo raya y semirraya.

**Y una al aplicar en D1.** El campo lleva marcado pegado a la raya
(`*vatsa*—cows`, `<em>vatsa</em>—cows`), asi que el patron del par entero no
casa nunca. Hay que sustituir SOLO la glosa, anclada en la palabra sanscrita
para no tocar otra glosa igual del mismo verso.

**Como se arbitra sin abrir imagenes.** Anclar en el par de significados mas
largo del propio verso —es unico en el libro— y leer desde ahi. El conteo sobre
el libro entero engaña con glosas cortas: «food» sale 32 veces en el
Caitanya-caritamrta y no dice nada de `cc/madhya/3/82`.

## `content/en` es un cuarto almacen, y estaba alimentando el buscador (15-ago)

Se sabia que habia tres almacenes de texto que no se alimentan entre si —el
repo, D1 y `vedabase-pwa/frontend/data`—. Hay un cuarto: `astro_vedabase/
content/en`, un export ANTERIOR a toda la campaña de correccion contra
escaneos. El propio `reingest_en_preserve_links.py` avisa de ello y aborta,
porque reingerirlo haria retroceder 497 correcciones.

Lo que nadie habia mirado es que ese directorio SALE hacia los artefactos de
busqueda. `build_verse_snippets.py` y `build_topic_verses.py` leian de ahi, asi
que el buscador y el panel de temas mostraban texto sin corregir mientras la
pagina mostraba el corregido:

    verse_snippets.json   422 de 20.304 fragmentos no coincidian con la pagina
    topic_verses.json      35 de 2.821 versos

    cc/madhya/9/306   fragmento «very much pleased»  pagina «very pleased»
    cc/madhya/9/141   fragmento «Veṅkaṭa Bhaṭṭa»     pagina «Vyeṅkaṭa Bhaṭṭa»

Los dos scripts leen ahora la traduccion de D1. **Nada debe volver a construirse
desde `content/en` sin comprobar antes contra D1.** Y ninguna reserva
silenciosa: `build_verse_snippets.py` falla si D1 no responde, porque caer de
vuelta a la copia vieja es justo el fallo que esto arregla.

## Dos trampas al comprobar palabras compuestas contra el escaneo

1. **El plural rompe la comparacion.** Si la forma hallada es «girlfriends» y la
   clase es «girlfriend», comparar `hallada == junto` da falso y se busca en el
   impreso la contraria SIN plural. Resultado: la aparicion se da por indecisa.
   Hay que construir la contraria conservando el plural.
2. **El contexto izquierdo falla al abrir seccion.** Cuando la palabra abre el
   significado, el OCR mete «purport» entre el final de la traduccion y el
   texto, asi que el contexto de cinco palabras del repo no aparece seguido.
   Con tres palabras si. Probar 5, 4, 3 y 2 en cascada.

## Las 108 divergencias repo/D1: casi todas eran del comprobador (15-ago)

El balance llevaba meses en 108 «divergencias irreducibles», clasificadas como
79 bloques estructurales y 25 que pedian mirar la imagen. Al cotejar el corpus
entero de otra manera resulta que **la mayoria las producia el propio
comprobador**, y las que no, se arreglaron todas. El balance esta en 0.

**Cuatro errores del cotejo, cada uno con su cifra de falsos positivos:**

1. **Diff posicional en vez de multiconjuntos.** El `.md` ordena verso, glosa,
   traduccion y significado; D1 son cuatro campos que se concatenan en otro
   orden. Un diff posicional marca el cambio de sitio como divergencia: los 10
   primeros «falta en D1» eran eso y nada mas.
2. **Comparar contra tres campos y no cinco.** Sin `verse_text`,
   `cc/adi/3/summary` salia con 427 palabras «que faltan en D1» y estaban ahi.
3. **Quitar los encabezados secundarios.** D1 guarda `## Servitorship` DENTRO
   del significado. Quitarlos del lado del repo daba 35 falsos positivos en el
   Nectar of Devotion y 8 en el Science of Self-realization: los libros enteros.
4. **No saber donde vive el colofon.** El repo lo guarda en su propio fichero
   (`bg-N-colophon.md`) y D1 lo pega al ultimo verso del capitulo: 18 falsos
   positivos, uno por capitulo de la Gita. Al arreglarlo, cuidado: hay que
   pegarselo SOLO al ultimo verso. Pegarselo a todos volvia divergentes los 653.

**Y lo que si era real, que estaba tapado debajo:**

  - 14 tramos que D1 no servia, entre ellos una frase entera de `cc/madhya/9/1`
    y «The Supreme Absolute» en `cc/madhya/6/172`
  - 10 tramos duplicados en D1 —`sb/3/15/4` repetia la misma linea tres veces,
    `cc/adi/13/61` decia «the trunks of the trunks of»— y un `PUPORT` suelto
  - 25 palabras cambiadas en la introduccion del Bhagavatam, incluida
    «pers oes» donde el papel dice «perfect guide». Iban dentro del bloque
    estructural de `sb/0b` y por eso no las veia nadie
  - 3 sitios donde el equivocado era el repo: `sb/5/1/19` (Brahmā con macron),
    `sb/3/26/57` (semina) y `cc/madhya/9/64` (Vyeṅkaṭa)

**Dos trampas tecnicas que costaron tiempo:**

  - **El UPDATE grande falla en silencio.** El significado de `kb/86` son 190 KB
    y D1 corta por encima de ~100 KB: el `UPDATE` devuelve sin error y no
    escribe nada. Hay que trocear (`SET campo = campo || '…'`) y COMPROBAR
    despues. Yo di por aplicada una correccion que no lo estaba.
  - **La regular de repeticion no sirve.** `((\w+ ){1,12}?)\1` sobre un campo de
    50 KB hace backtracking exponencial: diez minutos sin terminar una sola
    referencia. Hay que alinear con `difflib` sobre la lista de palabras y solo
    entonces buscar el tramo como cadena literal.
  - **Y otra vez el limite por la IZQUIERDA.** Sustituir `ṛṣṇa` por `Kṛṣṇa` sin
    `(?<![\wĀ-ỿ])` casa dentro de `Kṛṣṇa’s` y produce `KKṛṣṇa’s`. Es la tercera
    vez que este fallo aparece con otra forma. Los dos limites, siempre.

## El balance de 0 abiertos no cubre lo que corriges HOY (15-ago)

`build_ledger.py` da 0 ABIERTOS en los 21 libros, pero se construye sobre la
lista de candidatos ya generada: **no vuelve a pasar el diff**. Si una
correccion de hoy mete en el repo algo que el papel no dice, el balance sigue en
0 y no se entera nadie. Y hoy la mitad de las correcciones no nacieron de leer
el impreso, sino de cotejar el repo contra D1.

`verificar_cambios_contra_escaneo.py` cierra ese hueco: coge los pares
`old -> new` que se añadieron a `corrections.jsonl` desde una fecha y busca en
el OCR cual de las dos formas trae el papel. Resultado de los 64 de hoy: 62
respaldados, **0 contra el papel**, 2 que el OCR no distingue y estaban ya
comprobados a mano.

**Otra vez el limite de palabra, ahora al CONTAR.** Sin `(?![\w])`, «vibration»
cuenta dentro de «vibrations» y «universe» dentro de «universes»: la forma vieja
y la nueva salen empatadas y el caso se da por indeciso. Pasaba en 7 de los 10
que quedaban. Al ponerlo, 9 se resolvieron solos.

## Cobertura de los escaneos: un libro sin escanear

De los 27 directorios del repo, 21 tienen OCR. Cinco de los seis restantes no
son libros impresos (`lectures-and-conversations`, `letters`, `translations`,
`scripts`, `legacy-vedabase-site`). El sexto si lo es:

    life-comes-from-life    19 capitulos, sin PDF en scan_vedabase

Nunca se ha cotejado contra el impreso porque no hay con que. No esta en
`books.json` ni aparece en el balance, asi que **no figura como pendiente en
ningun sitio**: el balance de 0 abiertos no lo incluye. Si aparece el escaneo,
hay que darlo de alta en `books.json` y pasarle el diff.

Lo que si esta completo: las 51 series de paginas suman ~35.000 y **no falta
ninguna** —numeracion contigua en todas—, asi que el OCR de lo que hay escaneado
no tiene huecos.

## `content/en` alimentaba CINCO artefactos, no dos (16-ago)

El 15-ago saque de ahi `build_verse_snippets` y `build_topic_verses`. Faltaban
tres, y estaban igual de desfasados:

    topic_trees     63 versos de 4.070 con texto distinto del que sirve la web
    featured         2 de 31, y uno era `sb/1/1/1` con una traduccion ENTERA
                     distinta: «O my Lord, Śrī Kṛṣṇa, son of Vasudeva» donde la
                     pagina dice «I offer my obeisances unto Lord Śrī Kṛṣṇa»
    chapter-names   77 titulos de 309: «The Deliverance of Dvivida Gorilla»
                     donde el libro dice «Deliverance of Dvivida Gorilla». El
                     indice de navegacion no coincidia con el titulo del capitulo

**La leccion no es «arreglar estos tres».** Es que un directorio marcado como
inservible —`reingest_en_preserve_links.py` ABORTA si intentas reingerirlo—
seguia siendo la entrada de cinco constructores, y nadie lo habia mirado porque
el aviso estaba en el script que LEE de ahi hacia D1, no en los que leen de ahi
hacia los artefactos. Cuando marques una fuente como vieja, busca todo lo que
sale de ella, no solo lo que entra.

Los cinco leen ahora la traduccion de D1. Y ninguno cae en silencio a la copia
vieja: `build_verse_snippets` FALLA si D1 no responde, y los otros cuatro avisan
por pantalla. Una reserva silenciosa a la fuente mala es justo el fallo.

**Lo que `content/en` si aporta y por eso no se borra:** la estructura de
secciones, el devanagari y la transliteracion, que no han cambiado. Solo la
traduccion venia desfasada.

## La regla que cerraba 2.314 candidatos en bloque (17-ago)

`build_ledger.py` tenia un conjunto `CERRADAS` que daba por terminados TODOS los
candidatos de tipo «sinonimos» del Bhagavatam, el Caitanya, el Gita y el
Isopanisad —2.314 de 7.896— porque la auditoria de glosas se habia dado por
cerrada al 100%. El balance salia en 0 abiertos sin que nadie mirara ninguno.

Al desactivarla con `--sin-cubetas` quedan **1.180 abiertos**:

     909  OCR_NOISE   erratas del OCR en sanscrito: «nradadhmatuh» por
                      «pradadhmatuh», «samsavah» por «samsayah»
     222  REVISAR     de los que 125 son compuestos que el repo parte con guion
                      —«antah-yāmī», «vraja-indra»— y el OCR lee unidos
      49  el resto

De los 42 en que repo y escaneo dicen palabras REALMENTE distintas salieron
**tres errores del repo** que llevaban ahi sin que nadie los viera:

    sb/1/14/20  «svidyanti—perspiring»       el impreso dice «lamenting»
    sb/1/18/2   «sammumoha—was overwhelmed»  el impreso dice «became overwhelmed»
    sb/1/19/16  «yām yām—wherever»           el impreso dice «whichever»

**La leccion.** Cerrar una cubeta entera por su nombre no es lo mismo que
adjudicarla. Mientras la regla estuvo puesta, cualquier candidato NUEVO de esa
cubeta se cerraba solo. Si vuelves a poner una regla asi, deja tambien la manera
de desactivarla y pasala de vez en cuando.

**Dos trampas al arbitrar glosas contra el escaneo:**

1. **El conteo por libro entero mezcla versos.** `avatīrṇa` se glosa «descended»
   en unos versos y «advented» en otros; contar sobre el libro daba
   `cc/adi/7/9` por erroneo cuando el diff simplemente habia alineado su glosa
   con la de otro verso. Hay que anclar en el bloque de significados del propio
   verso.
2. **El OCR confunde v con m.** En `sb/1/13/42` lee «protāḥ women» donde el
   papel casi seguro dice «woven», que es lo que significa la palabra. En el
   Bhagavatam el OCR escribe «omer» por «over» 18 veces y «gimen» por «given».
   Cuando la lectura del escaneo sea semanticamente absurda, sospecha del OCR
   antes que del repo, y pide la imagen.

## 17-ago (tarde) — las 1.138 glosas: cerrar con prueba, no por parecido

Al abrir la cubeta quedaron 1.138 candidatos de tipo «sinonimos». Se cerraron
560 con pruebas comprobables (`cerrar_glosas.py`) y de los que quedaban salieron
**59 divergencias reales** aplicadas al repo y a D1.

**Las cuatro pruebas que sirven, y por que cada una sola no basta:**

- **Reordenamiento.** La misma glosa figura como «sobra en el repo» y como
  «falta en el repo» dentro del mismo verso. No falta nada: cambia de sitio.
- **Compuesto.** Un lado partido y el otro entero. Ojo: juntar las letras a
  secas NO basta, porque el sanscrito cambia la juntura —«ati»+«autsukya» da
  «atyautsukya»—. Por eso la regla de juntar y comparar daba cero.
- **Frecuencia.** Solo vale si la forma del escaneo no esta atestiguada en
  ninguna parte. Con la proporcion sola se cerraba «arjuna»/«arjunah», y las dos
  son palabras reales: que una forma sea frecuente no dice que sea la de ESTA
  linea.
- **Parecido.** Solo vale junto con la anterior. Con el parecido solo se cerraba
  «anuṣṭup»/«anuṣṭabh» (sb/3/12/45), que son las dos formas reales del mismo
  metro y son divergencia de verdad.

**El recuento incluye la aparicion que examinas.** «pradadhmatuh» x1 contra
«nradadhmatuh» x1 parece un empate y no lo es: el impreso trae la buena en la
linea del verso y la mala en la glosa, en la misma pagina. Cuando las dos estan
a menos de 500 caracteres, la pagina se desmiente sola y no hace falta nada mas.

**Surya conserva la puntuacion.** El OCR llega como «clave—glosa; clave—glosa»,
con guiones largos y diacriticos. Trocear el impreso usando las claves del repo
—que es lo que hacia `comparar_glosas.py`— sobra y ademas miente: una clave que
el impreso NO tiene se lleva por delante la glosa siguiente. Leelo entero con
`glosas_impreso.py`.

**Tres maneras de inventarte divergencias que no existen** (las tres pasaron):

1. **Clave repetida en el mismo verso.** «svādu» sale dos veces en sb/1/1/19,
   «relishing» y «palatable», y asi lo trae tambien el impreso. Guardando solo
   la primera salian dos divergencias, ademas INVERTIDAS. Empareja la primera
   con la primera.
2. **Ancla ambigua.** Las ultimas cuatro palabras de la transliteracion pueden
   casar en mas de un sitio, y entonces el bloque sale del verso de al lado.
   Exige que el ancla case UNA sola vez: prueba la linea entera y ve acortando
   hasta dar con una ventana inequivoca.

   Lo que NO sirve es validar el bloque despues comparando la estructura de
   claves. Se midio: un bloque equivocado casaba el 71% de las claves del repo y
   dos bloques correctos —cc/adi/5/111 y cc/antya/1/41— solo el 57%, porque los
   versos contiguos comparten particulas y el impreso agrupa las claves a su
   manera («sveta-dvipa nama» donde el repo pone dos). La metrica apunta al
   reves de lo que necesitas.
3. **Verificar con un patron que acaba en `;`.** `wrangler d1 execute --command`
   parte la sentencia por el punto y coma, asi que `LIKE '%…;%'` da error y
   parece que el UPDATE no se aplico. Estaba aplicado. Quita el `;` del patron o
   pasa el SQL con `--file`.

**Y una correccion propia:** di por bueno «forwardss» -> «forward» en
cc/madhya/9/39 comparando con OTROS versos donde el impreso pone «forward». El
de ese verso pone «forwards». Verifica en el bloque del verso, no en el libro.

**Lo que sigue pendiente, con su razon:**

    sb/1/13/42   protāḥ    «women» por «woven»: el OCR confunde v con m
    sb/3/12/45   anuṣṭup   el impreso da «anuṣṭabh» y «triṣṭubh»; la
                           transliteracion del propio repo dice «'nuṣṭub»
    sb/1/14/19   aśru      aśru es lagrima; «fearful» por «tearful» es t leida f
    sb/1/16/19   anāmayam  «hail and hearty» por «hale and hearty»
    sb/1/19/32   atithi    atithi es huesped; «the great» no cuadra
    sb/2/4/22    sarasvatī «godless» es «goddess» con la dd leida dl

Los seis necesitan la imagen de la pagina. No los adjudiques sin ella.

**Tres fallos mios al APLICAR, no al detectar** (los tres se colaron y se
arreglaron despues; si repites esto, evitalos de entrada):

1. **Reemplazo posicional mal contado.** En sb/1/14/42 «na» sale tres veces y el
   impreso da «not, not, nor». Cambie el PRIMERO en vez del tercero, porque
   contaba apariciones de la cadena vieja y no de la clave. Cuenta las claves.
2. **Singular/plural tratado como palabra truncada.** El filtro que descarta
   «demon» leido «mon» tiraba tambien «cows»/«cow» y «well-wishers»/«well-wisher»,
   que son diferencias de texto de verdad. Excluye la `s` final de esa regla.
3. **REPLACE en D1 cambia TODAS las apariciones.** En el .md cambie una de las
   tres «na» y en D1 se cambiaron las tres. Despues de tocar glosas, compara el
   CAMPO ENTERO entre repo y D1, verso a verso, y reescribelo desde el repo
   donde no cuadre. Con comparar la cadena nueva no basta.

**Lo que no se puede arbitrar con el escaneo: la separacion con guion.** El
impreso trae «in-quired» porque partio la palabra a final de linea, y «non-
violence» quiza de verdad. Las dos tienen la misma forma y no hay manera de
distinguirlas sin la imagen. Dejalas fuera.

## 17-ago (noche) — el mismo verso, glosas distintas en cada sitio

**El fallo mas grave del dia.** `yat te sujāta-caraṇāmburuham` (SB 10.31.19) se
cita TRES veces en el Caitanya-caritamrta: adi 4.40, adi 4.173 y madhya 8.219. Y
el impreso le pone glosas DISTINTAS en cada pasaje:

    adi 4.40 / 4.173      madhya 8.219
    sujata—very fine      sujata—delicate
    sanaih—gently         sanaih—very carefully
    karkasesu—rough       karkasesu—very rough and hard
    tena—with them        tena—by such lotus feet
    atavim—the path       atavim—the forest
    dhih—the mind         dhih—intelligence

Se cambiaron nueve glosas de madhya 8.219 poniendole las del adi-lila, porque el
ancla habia caido en la otra cita. **No des por hecho que un verso repetido
tiene las mismas glosas: cotejalo contra SU pasaje.**

**Cuatro cambios mas salieron invertidos por anclas malas** —el impreso decia lo
que el repo ya tenia— y hubo que revertirlos: `sb/5/16/3 api` (although),
`sb/6/9/32 te` (of You), `sb/3/9/10 dhiyā` (by intelligence) y el orden de las
tres `na` de `sb/7/13/7` (not, nor, not).

**Como se cazaron, y como cazarlos tu.** Despues de aplicar, saca del `git diff`
cada pareja clave—glosa que cambiaste y vuelve a contrastarla, con el ancla ya
arreglada. Es barato y es lo unico que encuentra este tipo de error: 82 cambios,
50 confirmados a la primera, y los que no cuadraban eran justo los malos.

**Dos anclas, no una.** Si la transliteracion no localiza el verso —el OCR la
estropea a menudo— sirve la PRIMERA pareja completa, «clave —glosa» junta, que
es muy distintiva. Con las dos, de 138 versos sin cotejar quedan unos pocos.

## 18-ago — los seis dudosos, resueltos con la pagina delante

Se sacaron las paginas de los PDF originales (`scan_vedabase/originals/
sb_original_prabhupada/`) con `pdftoppm -r 200 -png` y se miraron. La numeracion
de los `.surya.txt` es 1:1 con la del PDF, asi que localizar la pagina es
inmediato: `grep -rl` en el escaneo del volumen.

**Cinco de seis: el OCR era fiel y el repo estaba mal.**

    sb/1/13/42  protāḥ—women                     (el repo decia «strung»)
    sb/1/14/19  aśru-mukhāḥ—with a fearful face  (aunque aśru es lagrima)
    sb/1/16/19  anāmayam—quite hail and hearty   (y la traduccion tambien)
    sb/1/19/32  atithi-rūpeṇa—in the manner of the great
    sb/3/12/45  triṣṭubh / anuṣṭabh en las glosas

**Uno de seis: el OCR fallaba.** `sb/2/4/22 sarasvatī—the goddess of learning`;
«godless» era la dd leida dl. El repo ya estaba bien.

**La leccion, que corrige lo que decia esta misma nota.** La regla que veniamos
usando —«si la lectura del escaneo es absurda, sospecha del OCR»— acierta una de
cada seis veces. El impreso de 1972-75 dice cosas que no cuadran con el
significado: glosa `aśru` como «fearful», `atithi` como «the great», y escribe
«hail and hearty». Son erratas del libro, y el libro es la norma. Sospechar del
OCR sirve para NO aplicar a ciegas, no para decidir: lo que decide es la pagina.

**Y un detalle que solo se ve en el papel:** sb/3/12/45 usa dos grafias en la
misma pagina, «triṣṭubh/anuṣṭabh» en las glosas y «triṣṭup/anuṣṭup» en la
traduccion. No es incoherencia que haya que arreglar: es lo que esta impreso.
