Skip to content

TP · Cierre del Entregable 3: visor rediseñado, capturas regenerables y PRs del grupo en el informe - #50

Merged
R0SEWT merged 7 commits into
developfrom
feature/tp-cierre
Oct 4, 2026
Merged

R0SEWT merged 7 commits into
developfrom
feature/tp-cierre

Conversation

@R0SEWT

@R0SEWT R0SEWT commented Oct 2, 2026 •

Copy link
Copy Markdown
Owner

Qué trae

Verificación

  • go test -race ./... en tp/kmeans: pasa.
  • ruff check / ruff format --check sobre el script nuevo: limpio.
  • tp/informe/tp/compilar.sh: compila, 79 páginas.

Pendiente fuera de esta PR (bloquea empaquetar-tp.sh)

  • Video: URL, duración y partes en el Anexo A.
  • \verificar de Rody en conclusiones/rody.tex y en el Anexo C.
  • Comentario del team leader y nivel de cumplimiento en participacion-tp/main.tex.
  • Release release/tp → main y tag tp antes del 2026-10-05 09:00.

R0SEWT added 3 commits October 1, 2026 19:25
…ables

- Colores de los 8 arquetipos con la paleta de Bang Wong (segura para
  daltonismo) en el agregador de Go y en los JSON del visor; fuera los emojis,
  cada arquetipo se identifica por su punto de color.
- Paneles colapsables, modo mapa limpio y deep links (?hour, ?day, ?zone,
  ?filter, ?min) en tp/app.
- En pantallas angostas, con un filtro activo, los chips de la barra superior
  quedan solo con su ícono: a 412 px «Arquetipos» se salía de la pantalla.
Las dos figuras de fig:app-movil eran del diseño anterior. tp/scripts/
capturas_app.py las rehace desde los deep links del visor (Midtown a las 12:00
con el detalle expandido; Cluster 5 aislado a las 15:00), así que el pie de la
figura describe exactamente el estado capturado y se pueden volver a generar.
…nforme del TP

Cierra los \pendiente de la tabla de pull requests y de la participación del
Entregable 3 con lo que trae cada PR, y regenera el historial de commits.
@sourcery-ai

sourcery-ai Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Reviewer's Guide

El PR cierra el Entregable 3 rediseñando el visor para accesibilidad y móviles, incorporando estados reproducibles mediante deep links y un generador Playwright de capturas, y sincronizando el informe con las PRs, participaciones e historial actualizados.

Sequence diagram for deep-link mobile screenshot generation

sequenceDiagram
    participant Script as capturas_app.py
    participant Server as HTTP server
    participant Browser as Playwright browser
    participant App as NYC Taxi Pulse app
    participant Map as Leaflet map

    Script->>Server: serve_forever()
    Script->>Browser: launch()
    Script->>Browser: new_context()
    Browser->>App: goto(index.html?hour&day&zone&filter&min)
    App->>Map: initMap()
    App->>App: toggleCleanMapMode()
    Browser->>App: click(sheetHandle)
    Browser->>Browser: screenshot()
    Browser-->>Script: screenshot file
Loading

Flow diagram for responsive map and panel controls

flowchart TD
    Start[User opens visor] --> Query{Deep link contains min?}
    Query -->|Yes| Minimized[Add minimized to temporalControls]
    Query -->|No| Expanded[Show temporal controls]
    Minimized --> Panels{User toggles panels}
    Expanded --> Panels
    Panels -->|Hide| Clean[Add clean-map-mode]
    Clean --> Restore[Show restore control]
    Panels -->|Restore| Visible[Show HUD and action deck]
    Restore --> Visible
Loading

File-Level Changes

Change Details Files
Rediseño del visor interactivo para accesibilidad, legibilidad y uso móvil.
  • Sustituye emojis por iconos SVG, etiquetas temporales y colores Bang Wong en los ocho arquetipos.
  • Añade paneles colapsables, modo de mapa limpio, controles flotantes y ajustes responsive para 412 px.
  • Configura deep links para hora, día, zona, filtro, minimización y modo limpio.
  • Ajusta el mapa Leaflet con límites de NYC, renderizado SVG y opciones de carga durante gestos móviles.
tp/app/app.js
tp/app/index.html
tp/app/style.css
tp/app/data/nyc_clusters_resumen.json
tp/reports/nyc_clusters_resumen.json
Hace reproducibles las capturas móviles incluidas en el informe.
  • Añade un script Playwright que sirve la aplicación localmente, abre estados definidos mediante deep links y genera las capturas a 412×915.
  • Valida errores JavaScript durante la captura y permite seleccionar un ejecutable de Chrome alternativo.
  • Regenera las imágenes del informe con estados de Midtown y aeropuertos.
tp/scripts/capturas_app.py
tp/informe/tp/img/app-movil-midtown.png
tp/informe/tp/img/app-movil-aeropuertos.png
Actualiza el informe para reflejar la actividad y participación del Entregable 3. tp/informe/tp/secciones/14-github.tex
tp/informe/tp/generado/historial.tex
tp/informe/tp/compilado.pdf
Regenera la salida de agrupamiento con la nueva paleta visual.
  • Cambia los ocho colores generados por el comando de resumen de zonas a una paleta basada en Bang Wong.
  • Actualiza el reporte JSON consumido por el visor.
tp/kmeans/cmd/resumen_zonas/main.go
tp/reports/nyc_clusters_resumen.json

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

R0SEWT added a commit that referenced this pull request Oct 2, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 6 security issues, and 2 other issues

Security issues:

  • User controlled data in methods like innerHTML, outerHTML or document.write is an anti-pattern that can lead to XSS vulnerabilities (link)
  • User controlled data in a archetypeDesc.innerHTML is an anti-pattern that can lead to XSS vulnerabilities (link)
  • User controlled data in methods like innerHTML, outerHTML or document.write is an anti-pattern that can lead to XSS vulnerabilities (link)
  • User controlled data in a legItem.innerHTML is an anti-pattern that can lead to XSS vulnerabilities (link)
  • User controlled data in methods like innerHTML, outerHTML or document.write is an anti-pattern that can lead to XSS vulnerabilities (link)
  • User controlled data in a card.innerHTML is an anti-pattern that can lead to XSS vulnerabilities (link)
Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="tp/scripts/capturas_app.py" line_range="63" />
<code_context>
+                pag.wait_for_timeout(900)
+            if errores:
+                raise SystemExit(f"{nombre}: errores de JavaScript: {errores}")
+            pag.screenshot(path=args.salida / nombre)
+            print(f"→ {args.salida / nombre}")
+        nav.close()
</code_context>
<issue_to_address>
**nitpick (bug_risk):** `pag.screenshot(path=args.salida / nombre)` raises an error when the output directory does not already exist, so the documented `--salida` option cannot write captures to a new directory.

**Triggers:** When the caller passes a new or otherwise nonexistent directory via `--salida`.

**Suggested fix:** Create the destination before the capture loop with `args.salida.mkdir(parents=True, exist_ok=True)`.

```suggestion
    args.salida.mkdir(parents=True, exist_ok=True)
        for nombre, (query, expandir) in VISTAS.items():
```
</issue_to_address>

### Comment 2
<location path="tp/scripts/capturas_app.py" line_range="47-49" />
<code_context>
+            pass
+
+    manejador = functools.partial(Silencioso, directory=TP / "app")
+    servidor = http.server.ThreadingHTTPServer(("127.0.0.1", 0), manejador)
+    threading.Thread(target=servidor.serve_forever, daemon=True).start()
+    base = f"http://127.0.0.1:{servidor.server_port}/index.html"
+
+    with sync_playwright() as pw:
</code_context>
<issue_to_address>
**nitpick (bug_risk):** The HTTP server is never shut down when browser launch, navigation, screenshot, or JavaScript-error handling raises; the cleanup call is reached only on the successful path, leaving the server thread and listening socket alive until interpreter termination.

**Triggers:** When Playwright startup or any capture operation fails before the final `servidor.shutdown()` call.

**Suggested fix:** Wrap the server and Playwright work in `try/finally` and call `servidor.shutdown()` (and close the browser/context) from the `finally` block.
</issue_to_address>

### Comment 3
<location path="tp/app/app.js" line_range="581-584" />
<code_context>
    archetypeDesc.innerHTML = `
      <strong>${cluster.nombre}:</strong> ${cluster.subtitulo}.${notaMuestra}<br>
      ${cluster.desc}
    `;
</code_context>
<issue_to_address>
**security (javascript.browser.security.insecure-document-method):** User controlled data in methods like `innerHTML`, `outerHTML` or `document.write` is an anti-pattern that can lead to XSS vulnerabilities

*Source: opengrep*
</issue_to_address>

### Comment 4
<location path="tp/app/app.js" line_range="581-584" />
<code_context>
    archetypeDesc.innerHTML = `
      <strong>${cluster.nombre}:</strong> ${cluster.subtitulo}.${notaMuestra}<br>
      ${cluster.desc}
    `;
</code_context>
<issue_to_address>
**security (javascript.browser.security.insecure-innerhtml):** User controlled data in a `archetypeDesc.innerHTML` is an anti-pattern that can lead to XSS vulnerabilities

*Source: opengrep*
</issue_to_address>

### Comment 5
<location path="tp/app/app.js" line_range="633-636" />
<code_context>
        legItem.innerHTML = `
          <span class="dist-color-box" style="background: ${cMeta.color};"></span>
          <span>${cMeta.nombre} (${Math.round(pct)}%)</span>
        `;
</code_context>
<issue_to_address>
**security (javascript.browser.security.insecure-document-method):** User controlled data in methods like `innerHTML`, `outerHTML` or `document.write` is an anti-pattern that can lead to XSS vulnerabilities

*Source: opengrep*
</issue_to_address>

### Comment 6
<location path="tp/app/app.js" line_range="633-636" />
<code_context>
        legItem.innerHTML = `
          <span class="dist-color-box" style="background: ${cMeta.color};"></span>
          <span>${cMeta.nombre} (${Math.round(pct)}%)</span>
        `;
</code_context>
<issue_to_address>
**security (javascript.browser.security.insecure-innerhtml):** User controlled data in a `legItem.innerHTML` is an anti-pattern that can lead to XSS vulnerabilities

*Source: opengrep*
</issue_to_address>

### Comment 7
<location path="tp/app/app.js" line_range="926-942" />
<code_context>
      card.innerHTML = `
        <div class="arch-header">
          <div class="arch-title-group">
            <span class="arch-color-badge" style="background: ${c.color};"></span>
            <span class="arch-name">${c.nombre}</span>
          </div>
          <span class="arch-pct">${c.porcentaje}% (${c.viajes_total.toLocaleString()})</span>
        </div>
        <p class="arch-desc">${c.desc}</p>
        <div class="arch-metrics">
          <span>Duración: ~${c.duracion_min} min</span>
          <span>Distancia: ~${c.distancia_mi} mi</span>
          <span>Pico: ~${Math.round(c.hora_pico)}:00 (${c.dia_nombre})</span>
        </div>
        <div style="font-size: 10.5px; color: ${isSelected ? '#38BDF8' : '#6B7280'}; margin-top: 4px; font-weight: 600;">
          ${isSelected ? 'Activo en el mapa (toca para quitar)' : 'Toca para aislar en el mapa'}
        </div>
      `;
</code_context>
<issue_to_address>
**security (javascript.browser.security.insecure-document-method):** User controlled data in methods like `innerHTML`, `outerHTML` or `document.write` is an anti-pattern that can lead to XSS vulnerabilities

*Source: opengrep*
</issue_to_address>

### Comment 8
<location path="tp/app/app.js" line_range="926-942" />
<code_context>
      card.innerHTML = `
        <div class="arch-header">
          <div class="arch-title-group">
            <span class="arch-color-badge" style="background: ${c.color};"></span>
            <span class="arch-name">${c.nombre}</span>
          </div>
          <span class="arch-pct">${c.porcentaje}% (${c.viajes_total.toLocaleString()})</span>
        </div>
        <p class="arch-desc">${c.desc}</p>
        <div class="arch-metrics">
          <span>Duración: ~${c.duracion_min} min</span>
          <span>Distancia: ~${c.distancia_mi} mi</span>
          <span>Pico: ~${Math.round(c.hora_pico)}:00 (${c.dia_nombre})</span>
        </div>
        <div style="font-size: 10.5px; color: ${isSelected ? '#38BDF8' : '#6B7280'}; margin-top: 4px; font-weight: 600;">
          ${isSelected ? 'Activo en el mapa (toca para quitar)' : 'Toca para aislar en el mapa'}
        </div>
      `;
</code_context>
<issue_to_address>
**security (javascript.browser.security.insecure-innerhtml):** User controlled data in a `card.innerHTML` is an anti-pattern that can lead to XSS vulnerabilities

*Source: opengrep*
</issue_to_address>

Sourcery assessment

Approval pending. 6 findings to address first.

Blocking findings: tp/app/app.js:584, tp/app/app.js:584, tp/app/app.js:636, tp/app/app.js:636, tp/app/app.js:942, and 1 more


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment thread tp/scripts/capturas_app.py Outdated
Comment thread tp/scripts/capturas_app.py
Comment thread tp/app/app.js Outdated
Comment thread tp/app/app.js Outdated
Comment thread tp/app/app.js Outdated
Comment thread tp/app/app.js Outdated
Comment thread tp/app/app.js Outdated
Comment thread tp/app/app.js Outdated

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New security issues found

Comment thread tp/app/app.js Outdated
Comment thread tp/app/app.js Outdated
Comment thread tp/app/app.js Outdated
Comment thread tp/app/app.js Outdated
Comment thread tp/app/app.js Outdated
Comment thread tp/app/app.js Outdated
…apturas

Respuesta a la revisión de la PR #50:
- app.js: los textos del JSON que entran por innerHTML pasan por esc() y los
  colores por colorSeguro() (#RRGGBB). No son datos del usuario, pero los
  nombres ya traen '&' y una descripción '<8 mph', que se insertaban como HTML.
- capturas_app.py: crea el directorio de --salida y apaga el servidor en un
  finally aunque falle el navegador o una captura.
R0SEWT added a commit that referenced this pull request Oct 2, 2026
…apturas

Respuesta a la revisión de la PR #50:
- app.js: los textos del JSON que entran por innerHTML pasan por esc() y los
  colores por colorSeguro() (#RRGGBB). No son datos del usuario, pero los
  nombres ya traen '&' y una descripción '<8 mph', que se insertaban como HTML.
- capturas_app.py: crea el directorio de --salida y apaga el servidor en un
  finally aunque falle el navegador o una captura.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@R0SEWT

R0SEWT commented Oct 2, 2026 •

Copy link
Copy Markdown
Owner Author

Respondí los 14 comentarios de la revisión: los 8 hallazgos se resolvieron en 6455e40.

Una corrección a la guía del revisor: la tabla de cambios menciona tp/informe/tp/compilado.pdf, pero ese archivo no forma parte de esta PR. Los 11 archivos que cambia están en la pestaña Files changed, y ninguno es un PDF.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New security issues found

Comment thread tp/app/app.js Outdated
Comment thread tp/app/app.js Outdated
Comment thread tp/app/app.js Outdated
Comment thread tp/app/app.js Outdated
Comment thread tp/app/app.js Outdated
Comment thread tp/app/app.js Outdated
Comment thread tp/app/app.js Outdated
Comment thread tp/app/app.js Outdated
@R0SEWT
R0SEWT force-pushed the feature/tp-cierre branch from d7ca47a to 18bef1b Compare October 2, 2026 03:26
… interpolado

Sourcery (opengrep) seguía marcando los cuatro innerHTML aunque los valores ya
pasaban por esc(): la regla mira el patrón, no el escape. Con el() los textos
del JSON entran como texto y los colores por style.background validado.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sourcery assessment

Approved.

@R0SEWT R0SEWT left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Revisión semanal
Lista para merge

Repasé el diff completo (app.js/index.html/style.css, el script nuevo capturas_app.py, y los cambios en tp/kmeans/cmd/resumen_zonas/main.go). go test -race ./... pasa en tp/kmeans y ruff check no marca nada en capturas_app.py. No encontré bugs ni tests rotos. Un único hallazgo menor, no bloqueante:

  • tp/app/app.js:297,537,585,975 — estas cuatro asignaciones a *.style.backgroundColor usan cluster.color/c.color directo, sin pasar por colorSeguro(), mientras que las de app.js:656 y app.js:948 sí la usan. El comentario en app.js:15 ("Los colores van a style.background: solo se acepta #RRGGBB") sugiere que la regla debería aplicarse en todos los puntos. No es explotable (una asignación a style.backgroundColor no interpreta HTML, el navegador simplemente ignora un valor inválido), pero para ser consistentes con la regla que el propio código declara, conviene envolver esos cuatro casos también en colorSeguro(...).

Generated by Claude Code

@R0SEWT
R0SEWT merged commit 584f6a0 into develop Oct 4, 2026
6 checks passed
@R0SEWT
R0SEWT deleted the feature/tp-cierre branch October 4, 2026 00:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant