Volver a la wiki

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:00Sesión 21 inicia. Se detecta duplicado feature--supercontexto--bibliotecario-lint-fase5 (marcada superseded_by).
~08:20Se ejecuta wiki_delete_page por primera vez en producción.
~08:21GH API borra el .md (404 confirmado). D1 row eliminado.
~08:21INSERT INTO bib_wiki_log ... VALUES ('delete', ...) → CHECK constraint failed.
~08:30Estado inconsistente resuelto manualmente. Orphans: 2 → 1.
08:37Commit 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


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

  1. Ejecutar la migration con wrangler d1 execute --remote.
  2. Verificar que la tabla tiene los índices correctos:
    SELECT name FROM sqlite_master WHERE type='index' AND tbl_name='bib_wiki_log';
  3. Test: ejecutar wiki_delete_page sobre una página draft de prueba y confirmar que el log se escribe con operation='delete'.
  4. Revertir workaround en wiki.ts (cambiar 'archive' → 'delete' y "Hard-deleted draft" → "Deleted draft").
  5. Hacer commit + deploy.

Lecciones aprendidas


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

Subir