DocTracker
← volver al dashboard

Cómo funciona DocTracker

Updated 2026-05-21 divulgativo para entender el proyecto GitHub ↗

DocTracker es un radar que vigila la documentación de los servicios cloud que tu equipo ha homologado, y avisa cuando algo cambia. Esta página explica el proyecto desde cero — por qué existe, qué hace cada día, y cómo está construido.

El problema que resuelve

Tu equipo de plataforma homologa servicios cloud — Azure Foundry, Bedrock, AgentCore — produciendo dos cosas: una guía de servicio que explica cómo usarlo, y un módulo IaC (Terraform/Bicep) que lo despliega de forma aprobada. Eso queda congelado en una versión.

Mientras tanto, el proveedor cloud no para de cambiar la documentación: añade features, deprecia endpoints, modifica límites, introduce breaking changes silenciosos. Tu módulo homologado se desincroniza. Nadie se entera hasta que algo se rompe en producción.

Tu Módulo Homologado terraform/bicep · v1.2.0 api_version = "2024-08" sku = "Standard" network = "private" ⏸ congelado hace 4 meses ⏸ revisado por el equipo ¿cómo te enteras? drift silencioso Docs del proveedor learn.microsoft.com/... + api_version "2025-04" ~ sku "Standard" → renamed − `keys` field deprecated ⚠ BREAKING — ayer cambian cada semana

Fig. 1 — el gap entre lo que tu equipo homologó y lo que el proveedor publica hoy

DocTracker cierra ese hueco. Cada día descarga las páginas relevantes del proveedor, las compara con la última versión vista, y si algo cambió, un LLM clasifica si es un breaking change, una nueva feature, o una corrección cosmética. Recibes un email con lo importante y un dashboard navegable con todo el historial.

Un día en la vida de DocTracker

Concretamente: esto es lo que pasa cada mañana sin que nadie tenga que hacer nada.

09:00 GitHub Actions cron despierta crawl.yml 09:01 Crawler descarga 312 páginas Azure 09:03 Differ 3 páginas cambiaron 09:04 Analyzer (LLM) 1 high · 2 med + resumen 09:05 Notifier email al equipo + dashboard ✓

Fig. 2 — 5 minutos cada mañana, sin intervención humana

Ejemplo real: el 19 de mayo, Azure Foundry añadió GPT-Realtime-Translate y GPT-Realtime-Whisper. El crawl de las 09:00 detectó la nueva página, Claude la clasificó como <new-feature> con relevancia high, y el equipo lo supo antes de las 09:10 — con un link directo al diff de GitHub.

El diagrama grande

Si solo te quedas con un diagrama, que sea este. Muestra los actores principales, qué dato cada uno produce, y dónde acaba almacenado.

FUENTES EXTERNAS Azure Foundry learn.microsoft.com Stripe API stripe.com/docs GCP Docs cloud.google.com Orchestrator src/docstracker/orchestrator.py · disparado por GitHub Actions cron Crawler BFS desde la raíz · extrae markdown por sección snapshots/ git files Differ compara snapshot actual vs anterior lee histórico Changes (New / Modified Page) Analyzer · LLM relevance + category + summary · post-crawl analyses/ YYYY-MM-DD.json Site Generator site/index.html → GitHub Pages Notifier Change Report email → equipo

Fig. 3 — el pipeline completo · azul = procesa · amarillo = coordina · verde = produce salida visible

Conceptos clave

Antes de entrar en el detalle del pipeline, estos son los términos que vas a ver en todas partes. Los he agrupado por familia.

Lo que se vigila

Watch Target
Una fuente de documentación a vigilar — definida por una URL raíz y un límite opcional de páginas.
Ej: "Azure Foundry" → learn.microsoft.com/azure/foundry/
Page
Una URL concreta descubierta durante el crawl, dentro del prefijo del Watch Target.
Ej: /azure/foundry/whats-new-foundry
Section
Una subdivisión lógica de una Page, delimitada por una cabecera HTML (h1–h3). Es la unidad de diff.
Ej: "## V3 Migration Guide" + todo su contenido

Lo que se persiste

Snapshot
El contenido markdown de una Page tras un crawl, guardado como fichero en git. La historia de git es la historia de todos los snapshots.
Ej: snapshots/azure-foundry/<hash>.txt
Change
Diferencia entre el crawl actual y el snapshot anterior. Dos tipos: New Page o Modified Page. Las páginas borradas no se trackean (ruido).
Ej: Modified · azure/foundry/agents/overview
PageAnalysis
Valoración del LLM sobre un Change: relevance, category y un summary de 1-2 frases.
Ej: high · <breaking-change> · "Se elimina el param X"

Lo que se entrega

Change Report
Email enviado cuando hay al menos un Change. Agrupa los cambios por Watch Target. Si no hay nada, no se envía email.
Inbox: "DocTracker · 3 changes · 1 HIGH"
Site (dashboard)
Página estática regenerada en cada crawl, publicada vía GitHub Pages. Timeline de cambios filtrable.
URL: inimeve.github.io/docstracker/

Lo que pasa después (homologación)

Service Repo
Repositorio dedicado a un servicio (ej. foundry-agents, bedrock). Es el "consumer" de DocTracker.
Contiene: config, módulo IaC, snapshots, tests
Homologated Module
Módulo IaC (Terraform/Bicep) que despliega el servicio con la configuración aprobada por el equipo de plataforma.
Codifica naming, secrets, network, seguridad
Verification Suite
Tests automáticos contra el módulo. Layer A: despliega bien. Layer B: se comporta como dicen los docs.
Corre en un Ephemeral Environment efímero

El pipeline paso a paso

Mismo flujo que la Fig. 3, pero contado desde el dato. Sigue la pista a un solo cambio desde el momento en que el proveedor edita su web hasta que tu equipo lo lee.

HTML <html> <p>...</p> </html> FUENTE crawl Markdown ## Section 1 ## Section 2 ## Section 3 SNAPSHOT diff Change + added - removed ~ changed DIFF LLM PageAnalysis high <breaking-change> "resumen…" CLASIFICADO Dashboard (site/index.html) 19 May · [HIGH] <breaking-change> azure/.../v3-migration → link al diff de GitHub Email (Change Report) Subject: 3 changes · 1 HIGH ─ Azure Foundry (1) ─ Stripe API (2) → se envía solo si hay cambios

Fig. 4 — el dato se transforma en 4 etapas: HTML → Markdown → Diff → PageAnalysis · y se entrega por 2 canales

Etapa 1 · Crawl (HTML → Markdown)

El Crawler arranca en la URL raíz del Watch Target y descubre páginas con BFS, siguiendo enlaces que comparten el mismo prefijo. Cada página descargada se convierte a markdown fiel — preserva código, tablas, listas. No se le pide al LLM que reorganice nada: la fidelidad es la garantía de que el diff de mañana sea reproducible (ver ADR-0004).

Etapa 2 · Snapshot (markdown → git)

El markdown se guarda como un fichero en snapshots/<target>/<hash>.txt y se commitea. Git es la base de datos — no hay otra. Esto da auditoría gratis: cada cambio tiene un commit, cada commit tiene un diff visible en GitHub, y los links del dashboard apuntan ahí directamente (ver ADR-0002).

Etapa 3 · Diff (snapshot N vs N-1)

El Differ compara la versión recién escrita contra la anterior en git. Produce un objeto Change por página afectada — New Page si no existía antes, Modified Page si su contenido difiere. Las páginas que desaparecen del crawl no se reportan como borradas: es ruido (un timeout temporal del proveedor no debe disparar un email).

Etapa 4 · Análisis (diff → PageAnalysis)

Por cada Change, una llamada al LLM con todos los SectionDiffs de esa página en un solo prompt. El modelo devuelve tres campos cerrados: relevance, category, summary. El resultado se persiste en analyses/YYYY-MM-DD.json.

Si el LLM falla, el pipeline continúa sin análisis y el email sale igual (con los cambios pero sin clasificar). Esto se llama "silent degradation" y es intencional — la detección de cambios nunca debe depender de un servicio externo de IA.

Etapa 5 · Salida (sitio + email)

El Site Generator regenera site/index.html y lo commitea — GitHub Pages lo publica automáticamente. El Notifier envía el Change Report por email solo si hay cambios. Cero spam los días tranquilos.

Cómo se clasifica un cambio

El Analyzer asigna dos ejes a cada Change: severidad (qué tan urgente es) y categoría (qué tipo de cambio es). Los enums son cerrados — el LLM no puede inventarse categorías nuevas.

SEVERIDAD → CATEGORÍA ↓ HIGH acción urgente MEDIUM revisar pronto LOW informativo <breaking-change> <deprecation> <behavior-change> <new-feature> <limit-or-quota> <clarification> <new-example> <cosmetic> ● = típico · = a veces Solo HIGH y MED de breaking/deprecation entran en alertas urgentes

Fig. 5 — matriz de clasificación · severidad × categoría (8 categorías cerradas)

Esta matriz no se hardcodea — es el LLM el que decide. Lo que está fijado es el conjunto de valores posibles. Esto permite que el Analyzer "razone" sobre cada cambio sin que se invente etiquetas, y que el dashboard pueda agrupar/filtrar de forma estable.

Framework + consumer repos

DocTracker no vive en el mismo repo que tus servicios homologados. Es un framework: el motor (crawler, differ, analyzer, generador de sitio) vive en este repositorio, y se inicializa en un consumer repo dedicado por cada servicio.

DocTracker framework / engine crawler · differ · analyzer generator · notifier foundry-agents consumer repo config.yaml · módulo IaC snapshots/ · tests/ bedrock consumer repo config.yaml · módulo IaC snapshots/ · tests/ agentcore consumer repo config.yaml · módulo IaC snapshots/ · tests/ docstracker run docstracker run docstracker run FRAMEWORK • motor estable y versionado • se actualiza vía pin de versión CONSUMER REPO • dueño de la config • dueño de los artefactos

Fig. 6 — un motor · N consumer repos, cada uno con su servicio y sus artefactos

¿Por qué esta separación? Porque cada servicio homologado tiene su propio ciclo de vida, su propio equipo dueño, y su propio módulo IaC versionado. Mezclarlos en un monorepo acopla cosas que no deberían estar acopladas (ver ADR-0005).

Dónde corre todo esto

Cero infra propia. Todo en GitHub.

El coste de operar DocTracker es esencialmente la factura del LLM, y solo de las páginas que cambiaron — no de todas las que se descargaron.

Tres decisiones clave

Si quieres entender el "por qué" detrás del diseño, lee estas tres. Las demás están en el apéndice.

ADR-0004 El LLM nunca toca el snapshot Accepted

Snapshots se guardan como markdown fiel al HTML original. El LLM corre después — analiza los diffs, no los produce. Si dejáramos que el LLM "limpiara" o "reorganizara" el snapshot, mañana el mismo HTML produciría un snapshot distinto (no-determinismo), y el diff sería falso.

Esta separación es la garantía de que un Change en el report = un cambio real en el origen.

ADR-0002 Git es la base de datos · el sitio es estático Accepted

Cero servidor, cero base de datos, cero infra. Cada snapshot es un commit; cada diff es una URL permanente de GitHub; el dashboard es HTML estático regenerado en cada run. Coste de hosting: 0€.

El precio es que no hay búsqueda full-text ni alertas en tiempo real — pero el caso de uso primario es "qué cambió", no "qué dice el doc", así que está bien.

ADR-0005 Framework + consumer (no monorepo) Accepted

El motor vive aquí; los servicios homologados viven en repos separados que se inicializan con docstracker init. Cada equipo es dueño de su consumer repo y pinea la versión del framework que quiere usar.

La alternativa (todo en un monorepo) acoplaría ciclos de vida que en realidad son independientes.

Preguntas que te estarás haciendo

¿Por qué no usar webhooks del proveedor?

Porque los proveedores cloud no los ofrecen para cambios en documentación. Sus docs son un sitio web; no hay API para subscribirse a cambios. Crawl diario es lo que hay.

¿Por qué un LLM y no regex / heurísticas?

Porque clasificar "este cambio es un breaking change" requiere entender semántica. Una regex puede detectar que cambió la palabra "deprecated", pero no puede distinguir entre una deprecación seria y una nota informativa sobre algo deprecado hace años. El LLM razona; la regex no.

Eso sí: la detección del cambio (el diff) es determinista. El LLM solo entra a etiquetarlo.

¿Por qué cron diario y no en tiempo real?

Porque (a) los cambios en docs no son urgentes en escala de minutos — un breaking change en docs hoy se traduce en código mañana en el mejor caso, y (b) crawlear continuamente sería tirarse piedras al tejado del proveedor y a la factura del LLM. Una vez al día es el sweet spot.

¿Por qué snapshots en git y no en una BD?

Tres razones: (1) git ya hace diff e historial gratis, (2) cada cambio es auditable con un commit y un autor, (3) cero infra — sin BD que mantener, escalar o backupear. La pega es que git no escala a millones de snapshots, pero para el orden de magnitud de DocTracker (cientos de páginas por target, decenas de targets) sobra.

¿Por qué dos modelos (analyzer + synthesizer)?

Tienen perfiles de coste/calidad opuestos. El analyzer corre cada día, una vez por página cambiada → muchas llamadas pequeñas, sensible a latencia y coste → modelo barato y rápido. El synthesizer corre cada semana, una vez → pocas llamadas con contexto grande, sensible a calidad → modelo top.

Forzar un solo modelo te hace pagar de más a diario o quedarte corto los lunes (ver ADR-0006).

¿Qué pasa si el LLM se cae?

Silent degradation: el pipeline sigue, el email se envía con los cambios pero sin clasificación, el dashboard muestra los cambios sin etiqueta. Detectar cambios es la función crítica; clasificarlos es opcional.

Apéndice A · Módulos en src/docstracker/

MóduloFicheroResponsabilidad
Orchestratororchestrator.pyEntry point — secuencia crawl → diff → analyze → site → notify.
Crawlercrawler.pyBFS desde la raíz del Watch Target; descarga; extrae secciones markdown.
Differdiffer.pyCompara snapshot actual vs anterior; produce objetos Change.
Analyzeranalyzer.pyLlamada al LLM por cada Change; produce PageAnalysis.
Synthesizersynthesizer.pyResumen semanal/on-demand; Target Overviews; Weekly Digests.
Site Generatorsite_generator.pyGenera site/index.html estático.
Notifiernotifier.pyEnvía Change Report email (solo si hay cambios).
Snapshot Storesnapshot_store.pyLectura/escritura de snapshots en git.
Analysis Storeanalysis_store.pyLectura/escritura de analyses/YYYY-MM-DD.json.
Config Loaderconfig_loader.pyParser de config.yaml (Watch Targets + bloques LLM).
Watch Targetswatch_targets.pyLógica de selección y filtrado de Watch Targets activos.
Change Reportchange_report.pyComposición del email a partir de Changes + PageAnalysis.
Modelsmodels.pyTipos de dominio (Page, Snapshot, Change, PageAnalysis…).
Replayreplay.pyRe-ejecuta análisis sobre crawls históricos sin re-crawlear.
CLIcli.pyArgumentos y subcomandos (docstracker init, run, replay…).
MCP Servermcp_server.pyExpone snapshots y analyses vía Model Context Protocol para agentes IA.

Apéndice B · Todos los ADRs

Los 3 más importantes están explicados arriba (decisiones clave). Aquí están los 6 completos para referencia.

ADR-0001 Store page content as Markdown sections Accepted

Contenido extraído como markdown (prose, código, tablas, listas) agrupado por sección. Preserva código y tablas que el extractor anterior (solo <p>) descartaba silenciosamente. La granularidad por sección mantiene el Change Report legible: diffs por heading, no por línea de la página entera.

ADR-0002 Document exposure surface · Static wiki en GitHub Pages Accepted

Sitio estático servido por GitHub Pages desde site/ en master, estilo S3 Terminal Mono (monospace, denso, links directos al diff de GitHub). Decisión guiada por la query primaria: "qué cambió recientemente", no "qué dice el doc sobre X".

ADR-0003 Sources and notifications management Proposed · Deferred

Cómo gestionar Watch Targets y entrega de notificaciones cuando crezca la base de usuarios. Decisión diferida — depende de ADR-0002 y de si la base de lectores supera al usuario configurador único.

ADR-0004 AI-assisted ingestion · Híbrido fiel + capa IA Accepted

Snapshots permanecen deterministas y fieles. La capa IA corre post-crawl, downstream de snapshot writes, y nunca realimenta change detection. Granularidad: por Page. Output: relevance + category (enum cerrado) + summary. Persistido en analyses/YYYY-MM-DD.json. Failure: silent degradation.

ADR-0005 Framework / consumer architecture Accepted

DocTracker como framework, inicializado en consumer repos vía docstracker init. El framework provee el motor; cada consumer es dueño de config, Homologated Module, Service Guide, Verification Suite y Snapshots. Versión pineada en cada consumer.

ADR-0006 Two-model configuration: analyzer + synthesizer Accepted

Dos bloques en config.yamlanalyzer (rápido y barato, corre cada día por Page) y synthesizer (calidad, corre semanalmente para overviews y digests). Forzar un solo modelo encarece el análisis diario o degrada la síntesis semanal.