Incident: CHECK constraint fallida en bib_wiki_log — operación 'delete' no permitida (sesión 21)
Resumen
Durante la sesión 21 (2026-04-24), el primer hard-delete real de la wiki ejecutado con wiki_delete_page (sobre la página feature--supercontexto--bibliotecario-lint-fase5) falló con el error:
CHECK constraint failed: operation IN ('ingest','query','lint','curate','create','update','archive')
El borrado del fichero .md vía GitHub API y el borrado del row en D1 sí se completaron antes del error. Lo que falló fue la inserción del log de auditoría en bib_wiki_log. El sistema quedó en estado inconsistente (archivo y fila borrados, sin registro de auditoría) hasta su resolución manual.
Cronología
| Hora (UTC) | Evento |
|---|---|
| ~08:00 | Sesión 21 inicia. Se detecta duplicado feature--supercontexto--bibliotecario-lint-fase5 (marcada superseded_by). |
| ~08:20 | Se ejecuta wiki_delete_page por primera vez en producción. |
| ~08:21 | GH API borra el .md (404 confirmado). D1 row eliminado. |
| ~08:21 | INSERT INTO bib_wiki_log ... VALUES ('delete', ...) → CHECK constraint failed. |
| ~08:30 | Estado inconsistente resuelto manualmente. Orphans: 2 → 1. |
| 08:37 | Commit eb4d951 pusheado a main con workaround + migration 0015. |
Causa raíz
La migration 0014 creó la tabla bib_wiki_log con una CHECK constraint que enumera los valores válidos de operation:
CHECK (operation IN ('ingest','query','lint','curate','create','update','archive'))
La sesión 17 añadió el handler wiki_delete_page (hard-delete real de páginas draft). El validator TypeScript de wiki_log_event se actualizó para aceptar 'delete' como valor del enum operation. Sin embargo, la constraint SQL de D1 no se actualizó en ese momento.
Gap: desalineación entre el tipo TypeScript y la constraint SQL durante ~N sesiones hasta el primer uso real.
Impacto
- Datos: ninguna pérdida funcional. El
.mdy el row D1 se borraron correctamente. - Auditoría: el log del delete no se escribió. El registro del hard-delete quedó sin traza en
bib_wiki_loghasta la resolución. - Operacional: 1 orphan residual (de 2 → 1). Requirió intervención manual.
- Severidad: baja-media (estado inconsistente puntual, sin pérdida de datos de usuario).
Fixes aplicados
Fix 1 — Workaround en wiki.ts (desplegado automáticamente via CF Pages)
wikiDeletePage ahora inserta operation='archive' con summary prefijado "Hard-deleted draft: ..." y el artefacto hard_delete: true en el JSON. Esto permite distinguir hard-deletes en auditoría sin romper la constraint actual.
// functions/api/mcp/handlers/wiki.ts
await db
.prepare(
`INSERT INTO bib_wiki_log (operation, actor, page_slug, summary, artifacts)
VALUES ('archive', ?, ?, ?, ?)`,
)
.bind(
actor,
slug,
`Hard-deleted draft: ${reason}`.slice(0, 500),
JSON.stringify({ slug, file_path: page.file_path, file_deleted: fileDeleted, hard_delete: true }),
)
.run();
Estado: activo tras el próximo deploy de CF Pages.
Fix 2 — Migration 0015 (ejecución manual pendiente)
migrations/0015_bib_wiki_log_allow_delete.sql recrea la tabla bib_wiki_log (SQLite/D1 no soporta ALTER TABLE ... DROP/ADD CHECK) con la constraint ampliada:
CHECK (operation IN (
'ingest', 'query', 'lint', 'curate',
'create', 'update', 'archive', 'delete'
))
La migration copia todos los datos existentes, hace swap de tablas y recrea los índices.
Comando de ejecución:
wrangler d1 execute crearacksl-workspace-db --remote \
--file=./migrations/0015_bib_wiki_log_allow_delete.sql
Estado: ⚠️ PENDIENTE — debe ejecutarse manualmente por Edu o Dani.
Post-migration (opcional)
Una vez ejecutada la migration 0015, se puede revertir el workaround de wiki.ts para usar operation='delete' de verdad, eliminando la ambigüedad con 'archive'.
Pasos de verificación post-migration
- Ejecutar la migration con
wrangler d1 execute --remote. - Verificar que la tabla tiene los índices correctos:
SELECT name FROM sqlite_master WHERE type='index' AND tbl_name='bib_wiki_log'; - Test: ejecutar
wiki_delete_pagesobre una página draft de prueba y confirmar que el log se escribe conoperation='delete'. - Revertir workaround en
wiki.ts(cambiar'archive'→'delete'y"Hard-deleted draft"→"Deleted draft"). - Hacer commit + deploy.
Lecciones aprendidas
- SQL constraints y TypeScript enums deben actualizarse al mismo tiempo. Cuando se añade un valor a
wiki_log_event(enum TS), la migration SQL correspondiente debe ir en el mismo PR. - Primer uso en producción de features críticas revela gaps que tests unitarios pueden no cubrir si no hay tests de integración contra D1.
- Auditar el workaround: mientras
operation='archive'sea el proxy de hard-delete, las queries de auditoría deben filtrarartifacts LIKE '%hard_delete%'para identificar borrados reales.
Page aislada: no existen aún páginas wiki indexadas para las entidades relacionadas (
bib_wiki_log,wikiDeletePage, migration schema D1). Cuando se creen, enlazar desde aquí.
Véase también
- [[entity—d1—table—bib-wiki-pending-commits]]