Saltar al contenido
Development

La tarjeta de revisión del vault que nunca rotaba

Por Victor Da Luz
sveltesqlitetauridev-loggreenhouse

Greenhouse tiene una tarjeta diaria “Rescatar o Guardar” del vault para lo más antiguo que hay en el vault. Rescatar tiene sentido, saca el elemento de ahí. Guardar se supone que es la otra respuesta válida: dejarlo en paz, ya lo revisé, pregúntame de nuevo más tarde. Excepto que ese “más tarde” nunca llegó. Encontré el bug mientras trabajaba en un issue adyacente, y es un buen ejemplo de un comentario que me mintió durante semanas antes de que alguien lo detectara.

La lógica de selección es determinista a propósito: ordena todos los elementos guardados en el vault por cuánto tiempo llevan inactivos, y la revisión diaria muestra el que lleva más tiempo inactivo. Ese es un diseño razonable. El problema era qué hacía “Guardar” con esa selección. Había un comentario justo al lado explicando que hacer clic en Guardar descarta la tarjeta y la selección “cambia naturalmente (mañana).” Leí ese comentario, le creí, y pasé al siguiente issue. Estaba mal. Guardar no escribía nada en la base de datos. Fijaba un dato de estado en el componente de Svelte y lo daba por hecho. La tarjeta desaparecía por el resto de esa sesión porque un id del lado del cliente quedaba marcado como descartado, pero la consulta subyacente nunca cambiaba. Recargar la app, o volver al día siguiente, y el mismo elemento exacto volvía a ganar el concurso de “más inactivo.” Para siempre. Cada otro elemento del vault simplemente… nunca se revisaba.

La solución terminó siendo una sola columna nula. Agregué last_reviewed_at a la tabla de elementos, separada de vaulted_at. Esa separación importó más de lo esperado al escribirla: vaulted_at es sobre lo que se construye el orden de inactividad, así que si Guardar hubiera tocado esa columna en cambio, habría reiniciado el reloj de inactividad del elemento y empezado a corromper el orden exacto del que depende la revisión, la misma trampa que el diseño original de Guardar esquivó al no volver a llamar al comando de vault. Dos preguntas distintas, dos columnas distintas: “cuánto tiempo lleva esto en el vault” y “cuándo fue la última vez que lo revisé y decidí dejarlo.”

Con la nueva columna en su lugar, la selección diaria obtuvo un filtro más: saltar cualquier cosa revisada dentro de la cadencia configurada, y luego tomar la más antigua de lo que queda. Guardar ahora hace una llamada real al backend, y la bandera de descarte del lado del cliente en la que había estado confiando simplemente desaparece por completo, comentario incluido.

La parte que sigo pensando es que este bug era invisible en todo sentido obvio. Sin crash, sin error, sin prueba fallida. La tarjeta se comportaba exactamente como decía el comentario, dentro de una sola sesión. Solo se notaría algo raro usando la app a lo largo de varios días y preguntándose por qué la revisión del vault seguía mostrando la misma idea de canción inactiva de hace tres semanas. Que es justo cómo se reportó en primer lugar.

Lección que me llevo de esto: un comentario que explica por qué el comportamiento actual está bien es una afirmación, no un hecho, y necesita el mismo escepticismo que el código mismo. “Cambia naturalmente mañana” suena como una declaración sobre el sistema. En realidad era una declaración sobre la intención de alguien para el sistema que nunca se construyó.

Lecturas relacionadas

Development

Seis correcciones pequeñas de UX en una sola sesión

Límites de layout para pantallas ultra anchas, timestamps que respetan el idioma, emojis convertidos a SVG, errores descartables, un hero de primer uso, y la palabra que aparecía tres veces en una sola tarjeta.

Leer
Development

Toast y deshacer para la acción de vault de Greenhouse

La primera superficie de feedback transitorio de la app, la regla de aria-live que hace que un toast renderizado condicionalmente quede sin anunciar en silencio, y un prop que queda desactualizado apenas se renombra algo.

Leer