bib_wiki_pending_commits — Tabla D1 · Parking de commits wiki pendientes
bib_wiki_pending_commits
Tipo: Tabla D1 (Cloudflare)
Migration: migrations/0036_wiki_pending_commits.sql
Introducida en: s80 · 2026-05-22 (commit@bd61e31)
Propósito
Tabla de staging temporal para el sistema Bibliotecario-Ingest Batch. Almacena el contenido .md de las páginas wiki que wiki_create_page y wiki_update_page generan durante el agentic loop de Sonnet, aplazando el commit a GitHub hasta que wiki_flush_pending_commits consolide todo en un único push.
Esquema
CREATE TABLE IF NOT EXISTS bib_wiki_pending_commits (
id INTEGER PRIMARY KEY AUTOINCREMENT,
trigger_ref TEXT NOT NULL, -- "PR#63", "commit@abc1234"
slug TEXT NOT NULL, -- slug kebab-case de la wiki page
file_path TEXT NOT NULL, -- "src/content/wiki/<slug>.md"
body TEXT NOT NULL, -- contenido completo del .md (front-matter + body)
operation TEXT NOT NULL
CHECK (operation IN ('create', 'update')),
commit_message TEXT NOT NULL,
created_at TEXT DEFAULT (datetime('now')),
UNIQUE(trigger_ref, slug)
);
CREATE INDEX IF NOT EXISTS idx_wiki_pending_trigger
ON bib_wiki_pending_commits(trigger_ref);
Constraint UNIQUE(trigger_ref, slug)
Garantiza exactamente una entrada por (trigger, slug). El ON CONFLICT DO UPDATE se comporta diferente en create vs update:
En wikiCreatePage
ON CONFLICT(trigger_ref, slug) DO UPDATE SET
body = excluded.body,
operation = excluded.operation,
commit_message = excluded.commit_message
Gana el último body sin condiciones.
En wikiUpdatePage
ON CONFLICT(trigger_ref, slug) DO UPDATE SET
body = excluded.body,
operation = CASE
WHEN bib_wiki_pending_commits.operation = 'create' THEN 'create'
ELSE excluded.operation
END,
commit_message = excluded.commit_message
Si Sonnet hace create + update sobre el mismo slug en la misma sesión, el campo operation se preserva como 'create' para que ghCommitMultipleFiles sepa que el archivo es nuevo (no requiere SHA previo).
Ciclo de vida de una fila
wiki_create_page(defer_commit=true)
→ INSERT (o ON CONFLICT UPDATE) en bib_wiki_pending_commits
wiki_flush_pending_commits(trigger_ref)
→ SELECT todas las filas con trigger_ref
→ commit a GitHub (ghPutFile o Trees API)
→ DELETE FROM bib_wiki_pending_commits WHERE trigger_ref = ?
(solo si commit OK — idempotente)
Las filas son efímeras: desaparecen en cuanto el flush tiene éxito. Si el flush falla (red, GH_PAT inválido, race 422), las filas permanecen y se puede reintentar manualmente.
Índice
idx_wiki_pending_trigger sobre (trigger_ref): la query principal en el flush es WHERE trigger_ref = ? — el índice la cubre directamente.
Tablas relacionadas
| Tabla | Relación |
|---|---|
bib_wiki_pages | Se escribe simultáneamente con el INSERT pending (metadata D1 inmediata, .md diferido) |
bib_wiki_log | wiki_flush_pending_commits inserta un registro operation='ingest' tras flush OK |
Operaciones de mantenimiento
-- Ver páginas pendientes por trigger
SELECT trigger_ref, slug, operation, created_at
FROM bib_wiki_pending_commits
ORDER BY trigger_ref, id;
-- Limpiar manualmente un trigger atascado (usar con cuidado)
DELETE FROM bib_wiki_pending_commits WHERE trigger_ref = 'PR#XX';
-- Ver páginas envejecidas (>1 hora sin flush — posible flush fallido)
SELECT * FROM bib_wiki_pending_commits
WHERE created_at < datetime('now', '-1 hour');
Véase también
- [[feature—biblioteca—bib-ingest-batch]]
- [[entity—mcp—tool—wiki-flush-pending-commits]]