CreaRack-SL

Drift Check Semántico · MCP handlers + cron diario (ADR KB vs Graph Fase 2-3)

Drift Check Semántico — MCP handlers + cron diario

Estado: implementado en s61 (14-05-2026). Fases 2 + 3 del ADR [[decision—20260514—knowledge-base-vs-graph]] desplegadas. Cron en modo dry_run=true las primeras 2 semanas para calibrar prompt y threshold.

Qué es

Sistema que detecta drift semántico en la wiki Supercontexto: cuando un commit modifica código declarado como sources de una page wiki, el sistema marca esa page como pendiente de verificación. Un cron diario invoca a Claude Haiku 4.5 para decidir si los cambios hacen que la documentación esté obsoleta. Si lo está, crea automáticamente un draft de fix que el Curator existente triará.

Resuelve el problema raíz identificado en el ADR: el corpus tenía 84 pages active con last_verified > 30 días (21% del corpus) porque ningún proceso miraba “esta page describe código que cambió, ¿sigue siendo correcta?”.

Componentes

3 handlers MCP en functions/api/mcp/handlers/wiki.ts

HandlerInputOutput
bib_mark_verification_pending{file_paths: string[], actor?: string}{ok, marked, page_slugs, paths_processed, candidates_checked}
bib_check_drift_for_doc{slug: string, dry_run?: boolean}{slug, drift, confidence, summary, suggested_changes_excerpt, draft_slug_created, commits_total, commits_analyzed, haiku_input_tokens, haiku_output_tokens, haiku_cost_usd, dry_run}
bib_run_drift_check_batch{max_pages?: number, dry_run?: boolean}{ok, processed, drift_detected, drafts_created, total_input_tokens, total_output_tokens, total_cost_usd, dry_run, results[]}

bib_mark_verification_pending — tripwire trigger

Tras cada commit mergeado, el Bibliotecario-Ingest llama este handler con la lista de paths tocados. El handler:

  1. Carga bib_wiki_pages con status='active' AND verification_pending=0 AND sources != '[]'.
  2. Para cada page, parsea sources, filtra type='code', y compara con cada file_path recibido (match exacto o prefijo de directorio).
  3. UPDATE batched a 90 slugs por chunk (D1 bind limit · [[footguns_d1_bind_limit]]).
  4. Idempotente: pages ya pendientes se omiten.
  5. INSERT en bib_wiki_log con resumen.

bib_check_drift_for_doc — verificación individual con Haiku

Para un slug concreto:

  1. SELECT page → parsea sources tipo code.
  2. Si no hay code sources: {skipped: 'no_code_sources'}.
  3. Para cada source, fetch commits de GitHub API (GET /repos/{repo}/commits?path=...&since=last_verified&per_page=5) en el repo correcto (heurística por prefijo: workspace para functions/ src/ migrations/ scripts/ .github/scripts/bib_ingest, CreaRack-Pro para el resto).
  4. Cap 10 commits totales, fetch diff de los top-5 (patches truncados a 900 chars cada uno).
  5. Si 0 commits: UPDATE last_verified=NOW(), verification_pending=0 + INSERT bib_drift_checks con cost=0. Devuelve {drift: false, reason: 'no_commits_since_last_verified'}.
  6. Si hay commits: lee body del .md (sin frontmatter, max 6KB), construye prompt sistema con reglas estrictas (JSON-only output, sin chain-of-thought), llama Haiku 4.5 con max_tokens=600.
  7. Si drift=true && confidence>0.7 && !dry_run: crea draft <slug>--drift-fix-YYYYMMDD via wikiCreatePage interno con status=draft, kind=knowledge_base, lifecycle=refresh-90d, owner=agent-drift-check, tags ['drift-check', 'auto-generated', 'pending-review']. El Curator existente lo triará en su próximo run.
  8. Si drift=false || confidence<0.3 && !dry_run: UPDATE last_verified=NOW(), verification_pending=0.
  9. Si 0.3 ≤ confidence ≤ 0.7: solo registra audit en bib_drift_checks (sin draft, sin update).
  10. INSERT siempre en bib_drift_checks con (slug, drift_detected, confidence, summary, draft_slug_created, haiku_input_tokens, haiku_output_tokens, haiku_cost_usd).

bib_run_drift_check_batch — entrypoint del cron

Encapsula el bucle del workflow:

  1. SELECT top-N pages con verification_pending=1, ordenadas por utility_score DESC, COALESCE(last_verified, '1970-01-01') ASC.
  2. Para cada slug, invoca bibCheckDriftForDoc internamente.
  3. Agrega: processed, drift_detected, drafts_created, total_input_tokens, total_output_tokens, total_cost_usd, results[].
  4. INSERT en bib_wiki_log con el resumen del batch.

Workflow .github/workflows/wiki-drift-check.yml

Cron diario 0 6 * * * (06:00 UTC = 08:00 Madrid CEST · 07:00 Madrid CET). Espaciado intencionalmente del Curator (05:00 UTC L+J) y del Lint bulk (04:30 UTC).

Inputs workflow_dispatch:

  • dry_run (default true durante las 2 primeras semanas).
  • max_pages (default 5).

Patrón: curl POST https://workspace.crearack.com/api/mcp con Bearer + headers CF Access, payload JSON-RPC con tool bib_run_drift_check_batch. Job summary humano-legible ($GITHUB_STEP_SUMMARY) + artifact JSON con el reporte completo (30 días retention).

Pausa global via vars.BIBLIOTECARIO_PAUSADO (compartido con Curator/Lint/Utility).

Extensión del Ingest

.github/scripts/bib_ingest.py (en AMBOS repos: workspace + CreaRack-Pro) tiene nueva función trigger_tripwires(changed_files, mcp_token) llamada desde main() antes del flow Tier 1/2/3. Filtra paths internos (.github/scripts/bib_*, scripts/harness/, src/content/wiki/, context/) y llama el MCP. Non-blocking: errores se loguean pero no rompen el Ingest.

Coste estimado

Pricing Haiku 4.5 (mid-2026): $0.0008 / 1K input tokens + $0.004 / 1K output tokens.

VolumenPor pagePor día (cap 20)Por mes
Input típico~3500 tokens (doc body 1.5KB + 3 diffs)70K tokens~$1.68
Output típico~250 tokens (JSON)5K tokens~$0.6
Total~$0.004~$0.08~$2.4

Backfill inicial (84 stale actuales · cap 20/día → 4-5 días): **$0.34** una sola vez.

Salvaguardas

  • Threshold confidence > 0.7 para draft: falsos positivos LLM cuestan ~$0.004 + el draft pasa por revisión humana del Curator. Confidence en (0.3, 0.7) NO crea draft, solo audit.
  • Cap diario max_pages: limita coste y subrequests CF Workers. Inicio en 5/día durante calibración, después 20/día.
  • dry_run de partida: 2 primeras semanas el cron NO crea drafts ni actualiza last_verified. Solo registra en bib_drift_checks para que Edu/Dani revisen veredictos y calibren el prompt.
  • NO auto-merge: ningún fix de drift llega a status=active automáticamente. Todo pasa por Curator → revisión humana.
  • kind: knowledge_graph no aplica: las pages auto-archivadas del Help Widget siguen su lifecycle ephemeral-Nd (caducan solas), no se les ejecuta drift check.
  • Toggle pausa: BIBLIOTECARIO_PAUSADO=true en repo vars detiene el cron junto con el resto del Bibliotecario.

Métricas

Pulse del workspace · sección Bibliotecario · Drift checks 7d (Fase 5 del ADR, implementación pendiente):

  • Pages procesadas (drift_detected vs no_drift).
  • Drafts creados, drafts promovidos por Curator (señal de detección útil).
  • Coste API 7d.
  • Top-10 pages que han generado drafts (detecta áreas calientes del proyecto).

Criterio de éxito (3 meses): >40% de drafts del cron promovidos por Curator. Si <20%: prompt necesita iteración o threshold confidence demasiado bajo.

Estado de despliegue

FaseEstado
Fase 1 · schema Astro + D1 migration 0024 + backfill 449 pages✅ 14-05-2026 (PR workspace #36)
Fase 2 · handlers MCP + tripwire trigger✅ 14-05-2026 (PR workspace #37 + PR CreaRack-Pro #34)
Fase 3 · cron wiki-drift-check.yml dry_run✅ 14-05-2026 (este PR · primera ejecución 15-05-2026 06:00 UTC)
Fase 3 · activación final (dry_run=false, cap 20)⏳ 28-05-2026 estimado (tras 2 semanas calibración)
Fase 4 · Lint bulk evolucionado (respeta lifecycle)✅ 14-05-2026 (este PR)
Fase 4 · backfill 84 stale⏳ se ejecutará automáticamente cuando Fase 3 esté en apply=true
Fase 5 · métricas Pulse · widget Drift checks 7d⏳ implementación independiente

Véase también

  • [[decision—20260514—knowledge-base-vs-graph]]
  • [[ia-tech—automatismos—metodo—bibliotecario-procesos]]
  • [[entity—biblioteca—table—bib-drift-checks]]
  • [[feature—biblioteca—kb-vs-graph-fase1]]
  • [[feature—biblioteca—kb-vs-graph-fase2]]
  • [[footguns_d1_bind_limit]]
  • [[footguns_gemma4_chain_of_thought_leak]] — patrón similar de JSON-only output aplicado al prompt