Files
fn_registry/dev/issues/0050-jupyter-exec-collab-client-failure.md
T
egutierrez faac610745 feat: extraccion masiva footprint_aurgi (41 funcs + 4 types + stack Docker geo)
Extrae al registry funciones del proyecto interno footprint_aurgi:
- core (6): slugify_ascii, normalize_for_join, cp_provincia_es, infer_provincia_from_cp, safe_read_csv_fallback, csv_to_parquet_duckdb
- geo puras (7): haversine_km, point_in_ring, point_in_polygon, point_in_polygons_bbox, polygon_bbox, extent_with_padding, distance_bucket
- geo I/O (4): load_geojson_polygons, load_boundary_gdf, add_basemap_osm, add_basemap_with_timeout
- valhalla client (4): valhalla_route, valhalla_isochrone, valhalla_isochrones_async, valhalla_matrix_1_to_n
- datascience stats (7): trimmed_mean, geometric_mean, detect_distribution_type, best_central_tendency, summary_stats, kde_density_levels, alpha_shape_concave_hull
- datascience fuzzy (3): fuzzy_merge_adaptive (rapidfuzz), words_to_dataset, remove_words_from_column
- datascience viz (2): plot_kde_2d, plot_heatmap_log
- infra (4): compress_pdf_ghostscript, render_table_page_pdfpages, add_header_logo, osm2pgsql_ingest
- pipelines (4): setup_geo_stack_docker, compute_centers_reachability, generate_isochrones_by_zone, count_points_per_zone
- types geo (4): LonLat, BBox, IsochroneRequest, Centro

Incluye:
- apps/footprint_geo_stack/ (PostGIS + Martin + Valhalla via docker-compose)
- 131/132 tests pasan (1 skip esperado: osm2pgsql en PATH)
- Issue tracker dev/issues/0052-footprint-aurgi-extraction.md
- Atribucion uniforme: source_repo internal:footprint_aurgi, source_license internal-aurgi
- Build con 9 agentes en paralelo (8 wave 1 + 1 wave 2 pipelines)

Tambien commitea trabajo previo no commiteado: aggregate_extraction_results, chunk_with_overlap, clean_pdf_text, merge_entity_aliases, extract_graph_gliner2, extract_relations_mrebel, extract_triples_spacy_es, gliner2/mrebel/marianmt/rebel/spacy_es load_model, parse_rebel_output, translate_es_to_en, issue 0050/0051.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 23:35:22 +02:00

5.8 KiB

0050 — jupyter_exec falla por cliente colaborativo (workaround documentado)

APP Metadata

Campo Valor
ID 0050
Estado pendiente
Prioridad media
Tipo bug — python/functions/notebook/jupyter_exec.py

Dependencias

Ninguna. Independiente del resto.


Sintoma

Al ejecutar jupyter_exec.py append <notebook> <code> contra un Jupyter Lab arrancado con el launcher estandar de los analyses (run-jupyter-lab.sh, flag --collaborative), la operacion falla con:

{"error": "HTTP Error 405: Method Not Allowed"}

jupyter_write.py append-code y append-markdown SI funcionan (no usan el canal colaborativo). El bug solo afecta a jupyter_exec, que necesita ejecutar la celda en el kernel y para eso usa jupyter_nbmodel_client con websocket Y.js.

Reproducido en 2026-05-04 durante la construccion del analysis projects/osint_graph/analysis/gliner_glirel_tuning/. El resto de funciones del modulo notebook/ quedan intactas:

$JX append <nb> <code>            # ❌ HTTP 405
$JW append-code <nb> <code>       # ✅ OK (sin ejecucion)
$JW append-markdown <nb> <md>     # ✅ OK
$JX cell <nb> <idx>               # 🔁 No probado, pero usa el mismo cliente
$JX kernel <code>                 # 🔁 No probado

Diagnostico (parcial)

jupyter_nbmodel_client espera que el server tenga la extension jupyter_collaboration activa y montada en /api/collaboration/.... El launcher arranca jupyter con el flag CLI --collaborative, que en versiones recientes (jupyter_server >= 2.x, jupyter-collaboration >= 4.x) ya no es suficiente — la extension se carga via entry-point y se controla con flags distintos (--YDocExtension.disable_rtc o equivalente), o requiere un fichero de config explicito.

Salida de jupyter_discover.py confirma el sintoma indirectamente:

{ "url": "http://localhost:8888", "collaborative": false, ... }

aunque --collaborative esta en el launch command. Es decir: el server arranca, expone la API REST, pero la capa colaborativa NO esta activa.


Workaround usado en gliner_glirel_tuning

Cambio de tactica: en lugar de construir el notebook con jupyter_exec append celda a celda, se ejecutan los experimentos en un script externo y se empotran las celdas (codigo + outputs ya generados) con nbformat directo a fichero. El notebook resultante es persistente y no necesita el canal colaborativo.

# build_notebook.py
import nbformat as nbf
nb = nbf.v4.new_notebook()
for src, stdout in cells:
    cell = nbf.v4.new_code_cell(src)
    cell.outputs = [nbf.v4.new_output("stream", name="stdout", text=stdout)]
    nb.cells.append(cell)
nbf.write(nb, "notebooks/01_foo.ipynb")

Si se quieren outputs reales (DataFrames como HTML, figuras matplotlib), ejecutar despues con nbconvert:

IPYTHONDIR=$(pwd)/.ipython ./.venv/bin/jupyter nbconvert \
  --to notebook --execute notebooks/01_foo.ipynb \
  --output 01_foo.ipynb --ExecutePreprocessor.timeout=300

Esto bypassa completamente el canal colaborativo y produce un .ipynb funcional, abrible en Jupyter Lab para ver / iterar / re-ejecutar.

Ver projects/osint_graph/analysis/gliner_glirel_tuning/build_notebook.py y build_notebook_e2e.py para ejemplos vivos.


Causas raiz a investigar

  1. Verificar la version de jupyter-collaboration en el venv del analysis. Si es >=4.x, el flag --collaborative ya no aplica y el launcher (write_jupyter_launcher_bash_io) tiene que actualizarse.
  2. El cliente jupyter_nbmodel_client puede tener su propia ventana de versiones soportadas — comprobar pinning en python/.venv y en los venvs de analyses.
  3. El endpoint /api/collaboration/document debe responder a un GET con HTTP 200 cuando la extension esta activa. Si responde 405, el cliente intenta una operacion (POST/PUT) sobre un endpoint que solo acepta GET, sintoma de mismatch.

Tareas

  1. Reproducir el HTTP 405 con un notebook nuevo y un kernel nuevo en un analysis recien creado.
  2. Capturar la URL exacta y el metodo HTTP que dispara el 405 (anadir logging a jupyter_exec.py linea ~192/229 donde llama a get_jupyter_notebook_websocket_url).
  3. Verificar version de jupyter-collaboration en el venv y comparar con la matriz de compatibilidad de jupyter_nbmodel_client.
  4. Una de dos:
    • (a) Corregir el flag/config en write_jupyter_launcher_bash_io para activar correctamente la colaboracion en versiones nuevas.
    • (b) Si la API colaborativa cambio mucho, migrar jupyter_exec.py a usar el JupyterClient clasico (REST + WebSocket directo al kernel sin Y.js) que es estable a traves de versiones. jupyter_kernel.py ya hace algo asi y funciona.
  5. Anadir un test e2e basico en tests/ que arranca jupyter, lanza jupyter_exec append, verifica que la celda se ejecuto y captura stdout. Sin esto el bug puede regresar.

Out of scope

  • Reescribir el sistema completo de notebook collaboration.
  • Migrar a un MCP. La regla notebook_collaboration.md es explicita: estas funciones reemplazan al MCP jupyter.

Riesgos

  • Si la causa es la matriz de versiones, la opcion (a) puede generar fricion futura cada vez que jupyter-collaboration haga un breaking change. La opcion (b) es mas robusta a largo plazo aunque pierde la capacidad de ver cambios en tiempo real desde el navegador.

Notas operativas

Mientras este bug exista, el patron recomendado para construir notebooks desde un agente Claude en un analysis es:

  1. build_notebook.py con nbformat para estructura + outputs estaticos.
  2. nbconvert --execute para outputs reales (HTML, plots).
  3. Si necesitas tiempo real con el browser, abre el notebook ya generado en Jupyter Lab y reejecuta a mano.

El propio analysis gliner_glirel_tuning es referencia.