Descripción
core/api_help.py es el módulo Django que implementa el proxy HTTP del Help Widget de CreaRack Pro. Actúa como intermediario entre el frontend (panel de ayuda IA) y los servicios externos alojados en workspace.crearack.com:
/api/mcp— proxy parabib_ask: el usuario hace una pregunta y la respuesta viene de la Biblioteca via MCP./api/biblioteca/wiki-titles— obtiene títulos EN para traducciones del panel./api/biblioteca/wiki— obtiene la lista de artículos wiki para mostrar en el panel.
Funciones clave
_workspace_headers() (helper privado)
Construye los headers HTTP necesarios para llamar a workspace.crearack.com. Desde s58 (commit 881f96f) inyecta también los headers CF Access Service Token cuando están configurados:
def _workspace_headers():
token = getattr(settings, "WORKSPACE_MCP_TOKEN", "")
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
}
cf_id = getattr(settings, "CF_ACCESS_CLIENT_ID", "")
cf_secret = getattr(settings, "CF_ACCESS_CLIENT_SECRET", "")
if cf_id and cf_secret:
headers["CF-Access-Client-Id"] = cf_id
headers["CF-Access-Client-Secret"] = cf_secret
return headers
Comportamiento:
- Si
CF_ACCESS_CLIENT_IDyCF_ACCESS_CLIENT_SECRETestán vacíos (dev local) → no envía headers CF Access (compatible con entornos sin CF Access). - Si están configurados (PROD) → los inyecta automáticamente en las 3 llamadas del Help Widget, ya que todas pasan por este helper.
_mcp_call(tool_name, arguments)
Ejecuta una llamada MCP a workspace.crearack.com/api/mcp usando _workspace_headers().
Desde v1.82.1 (#254): el workspace MCP puede responder con HTTP 200 y cuerpo {"error": "..."} cuando la tool falla (p.ej. artículo no encontrado) — resp.raise_for_status() no detecta eso porque el status code es 200. _mcp_call ahora desenvuelve el body, y si es un JSON con clave "error", lanza RuntimeError(f"workspace MCP error: {...}") en vez de devolver el texto tal cual. Cada caller del Help Widget ya sabía convertir esa excepción en un 502 honesto; antes de este fix, el JSON de error viajaba íntegro y se pintaba como si fuera contenido legítimo (ver [[incident—20260823—help-es-json-error-como-articulo]]). Aplica a las 3 llamadas del módulo por igual — blinda el puente MCP entero, no solo el camino de artículos.
_apply_language(data, lang)
Introducida en sesión 137 (2026-06-14). Para lang=es, traduce los títulos de la lista de artículos vía el mapa EN→ES (wiki-es/titles.json) y reescribe los paths wiki/ → wiki-es/ para servir el corpus español; para el resto de idiomas (EN canónico) solo normaliza los category_label legacy que quedan en español.
Desde v1.82.1 (#254): la reescritura de ruta wiki/ → wiki-es/ solo ocurre para un artículo cuyo título está en el mapa de traducción (es decir, que tiene gemelo español confirmado). Antes reescribía la ruta de TODO artículo incondicionalmente, asumiendo una “simetría total” entre corpus EN y ES que dejó de ser cierta en cuanto nacieron artículos EN nuevos sin traducir — el rewrite ciego producía una ruta wiki-es/ inexistente, que el workspace respondía con el payload de error de arriba. Un artículo sin gemelo español ahora se sirve en inglés (degradación elegante) en vez de una ruta rota. Detalle completo del incidente: [[incident—20260823—help-es-json-error-como-articulo]].
help_article(request, path) — endpoint GET /api/help/article
Desde v1.100.0 (T9): solo sirve rutas que casan _HELP_ARTICLE_RE (prefijo wiki/ o, desde v1.132.3, también wiki-es/, seguido de crearack--*.md) — antes de ese filtro, un usuario autenticado podía leer cualquier doc interna del workspace (ADRs, concept--/decision--/incident--, claude-method) pasando su ruta directamente. El filtro original solo contemplaba wiki/ y dejó sin abrir los 69 artículos de la Ayuda en español durante 13 días, porque _apply_language entrega rutas wiki-es/ — ver [[incident—20260914—help-es-whitelist-rechaza-articulos]].
Settings requeridas
| Setting | Env var | Descripción | Default |
|---|---|---|---|
WORKSPACE_MCP_TOKEN | WORKSPACE_MCP_TOKEN | Bearer token para autenticación MCP | "" |
CF_ACCESS_CLIENT_ID | CF_ACCESS_CLIENT_ID | CF Access Service Token ID | "" |
CF_ACCESS_CLIENT_SECRET | CF_ACCESS_CLIENT_SECRET | CF Access Service Token Secret | "" |
Definidas en config/settings/base.py. Propagadas al contenedor web via compose.yml y compose.prod.yml.
Callers del Help Widget (inventario completo)
| Endpoint destino | Método | Propósito | Headers requeridos |
|---|---|---|---|
workspace.crearack.com/api/mcp | POST | Proxy bib_ask (IA) | Bearer + CF Access |
workspace.crearack.com/api/biblioteca/wiki-titles | GET | Traducciones EN | Bearer + CF Access |
workspace.crearack.com/api/biblioteca/wiki | GET | Lista artículos | Bearer + CF Access |
⚠️ Importante: Todos los callers pasan por
_workspace_headers()y, desde v1.82.1, por el guard de payload de error de_mcp_call(). Cualquier cambio de autenticación o de formato de error enworkspace.crearack.comdebe actualizarse en esos dos puntos únicos.
Historial relevante
| Versión | Sesión | Cambio |
|---|---|---|
| v1.132.3 | ronda 13-09 (task #308, #533) | _HELP_ARTICLE_RE acepta también wiki-es/: el filtro T9 solo aceptaba wiki/ y dejaba sin abrir los 69 artículos de la Ayuda en español (13 días). Test de contrato “lo que listo, lo puedo abrir” en EN+ES — ver [[incident—20260914—help-es-whitelist-rechaza-articulos]]. |
| v1.82.1 | ronda 23-08 (#254) | _mcp_call detecta payload {"error": ...} con HTTP 200 y lo convierte en excepción; _apply_language solo reescribe rutas wiki-es/ con gemelo confirmado. Fix de incidente de 9 semanas — ver [[incident—20260823—help-es-json-error-como-articulo]]. |
| Sesión 137 (2026-06-14) | — | _apply_english → _apply_language(data, lang): nace el soporte de corpus en español (wiki-es/). |
| v1.0.73 (hotfix) | s58 | _workspace_headers() inyecta CF Access headers. Fix incidente 403 post-s57. |
| v1.0.73 | s56 | Implementación del Informante del Help Widget (+806 LOC) |
Relación con CF Access
Desde s57, los endpoints de workspace.crearack.com están protegidos por Cloudflare Access (sin bypass-everyone). Todos los callers — incluidos los Django runtime como este módulo — deben presentar un CF Access Service Token válido (CF-Access-Client-Id + CF-Access-Client-Secret).
Ver el incidente de referencia: [[incident—20260512—cf-access-help-widget-403]].
Véase también
- [[incident—20260512—cf-access-help-widget-403]]
- [[incident—20260823—help-es-json-error-como-articulo]]
- [[incident—20260914—help-es-whitelist-rechaza-articulos]]
- [[entity—harness—script—bib-report-check]]
- [[feature—core—help-widget]]
- [[runbook—infra—cf-access-service-token]]
Referenciado desde
- El Help Widget sirvió el JSON de error como artículo — paridad EN/ES del corpus de Ayuda rota ~9 semanas (#254)
- Incidente #254 · La Ayuda en español mostraba el JSON de error como si fuera el artículo
- Incidente s58: CF Access 403 — Help Widget bloqueado tras endurecer bypass-everyone (s57)
- La Ayuda en español no abría ningún artículo: el filtro de seguridad T9 solo aceptaba wiki/, no wiki-es/