0 Fundaciones ¿Hay dónde construir y cómo mirarlo? ✓
cerrada · v0.0.2
Qué queda construido
- Worker desplegado en una URL viva con health público
- D1 pulso-db / pulso-obra, KV pulso-cache, R2 pulso-media (uat y producción separados)
- Este panel de obra, con los veredictos persistidos en D1 pulso-obra
- Dependencias fijadas exactas, con un test que falla si alguien las desfija
- Entrada por magic link: sin contraseña, sesión firmada con HMAC. Se adelantó aquí porque la auth era el bloqueo del proyecto y había que probarla el día 1
- Esquema completo de D1 aplicado (la fase 1 solo tendrá que sembrar y consultar)
Guión de pruebas
- Abre https://uat-api.pulso.travel/entrar en el móvil, con datos, no en wifi. → Sale un campo de correo. El teclado del móvil aparece con la arroba a mano.
- Escribe lc@cooweb.co y toca «Enviarme el enlace». → Sale un mensaje verde diciendo que si ese correo tiene acceso, le llega un enlace.
- Abre el correo. Mira también en spam si no lo ves en un minuto. → Ha llegado un correo de Pulso con un botón «Entrar».
- Toca «Entrar» en el correo. → Vas directo al panel de obra, ya dentro, y arriba aparece tu correo.
- Sin girar el móvil, desliza de arriba abajo toda la página del panel. → Nada se sale por el lado. No hay barra de scroll horizontal ni hace falta zoom.
- Despliega la Fase 0 y lee los criterios del gate. → Entiendes cada criterio sin preguntarme qué significa.
- Marca ✓ o ✗ en cada criterio humano de la Fase 0. En al menos uno, escribe un comentario. → El botón se queda marcado. Aparece «guardado» con la hora.
- Vuelve a tocar el enlace del correo, el mismo de antes. → Dice que ese enlace ya no vale. Un magic link se usa una vez y solo una.
- Cierra el navegador del todo y vuelve a abrir https://uat-api.pulso.travel/obra → Sigues dentro y tus ✓/✗ y tu comentario siguen ahí. Nada se ha perdido.
- Lee la sección «Pendiente de atender» arriba del panel. → Tu comentario y cualquier ✗ aparecen ahí, esperando respuesta.
Gate
-
autoGET /v1/public/health responde 200 con status ok, versión y entorno
Falla si: No responde 200, o el JSON no trae version y environment
-
autoNinguna dependencia usa rango (^, ~, *, x): todas fijadas exactas
Falla si: Cualquier versión en package.json no es exacta
-
autoUn veredicto enviado al panel se guarda en D1 y reaparece al recargar
Falla si: El veredicto no vuelve en GET /obra/api/estado
-
autoToda fase tiene pregunta, al menos un criterio auto y al menos uno humano
Falla si: Una fase sin pregunta o sin gate humano
-
autoUna cookie de sesión manipulada, caducada o mal formada se rechaza
Falla si: Cualquiera de los tres casos entra
-
autoUn magic link usado dos veces no entra la segunda, y caduca a los 15 minutos
Falla si: El mismo enlace sirve dos veces
-
autoA un correo que no está en la lista no se le envía nada, y la respuesta es idéntica: no se filtra quién tiene acceso
Falla si: La respuesta permite distinguir un correo con acceso de uno sin acceso
-
túAbro la URL desde el móvil y el panel se lee sin hacer zoom ni scroll lateral
Falla si: Tengo que hacer zoom, o algo se sale de la pantalla
-
túPido el enlace en /entrar, me llega al correo, lo toco y entro. Ya puedo marcar veredictos
Falla si: No llega, llega a spam, o al tocarlo no entro
-
túEl plan de 7 fases que veo es el que quiero para Pulso, en ese orden
Falla si: Falta algo importante, o el orden no tiene sentido para mí
-
túPuedo marcar ✓/✗ y dejar un comentario en tres toques, sin teclear nada raro
Falla si: Me cuesta encontrar dónde opinar, o se pierde lo que escribo
1 El feed, con datos sembrados ¿Esto se entiende y apetece? ✓
cerrada · v0.1.0
Qué queda construido
- 18 eventos reales de Castellón y provincia, extraídos de vivecastellon.com, cada uno con su URL de origen para poder comprobarlo
- 11 sitios con coordenadas reales geocodificadas con Nominatim (OpenStreetMap)
- GET /v1/events, /events/cities, /events/:id, /events/nearby con bounding box + Haversine
- Feed en /feed a 360 px, con filtros por ciudad y categoría, y ficha de detalle
Guión de pruebas
- Abre https://uat-api.pulso.travel/feed en el móvil. → Sale una lista de planes. Nada se sale por el lado de la pantalla.
- Sin abrir ninguno, lee las tres primeras tarjetas. → De cada una sabes qué es, cuándo y dónde. Si tienes que abrirla para saberlo, es un ✗.
- Toca los filtros de arriba: prueba «Onda» y luego «Música». → La lista cambia. Los filtros se deslizan a lo ancho sin mover la página entera.
- Quita los filtros y toca «Ver por cercanía al centro», al final de la página. → Los planes salen ordenados por distancia, y cada uno dice a cuántos km está.
- Abre un evento cualquiera. → Ves cuándo, dónde, la distancia, la descripción y un botón a la fuente.
- En la ficha, toca «Ver en la fuente» y compara: título, fechas y sitio. → El evento existe de verdad en vivecastellon.com y los datos coinciden.
- Repite el paso 6 con otros dos eventos distintos, elegidos al azar. → Los tres existen. Si alguno es inventado o no cuadra, es un ✗.
- Toca «Ver en el mapa» en una ficha que tenga sitio concreto. → El mapa cae en el sitio correcto de Castellón, no en medio del campo ni en el mar.
- Vuelve al feed y prueba a combinar «Onda» con «Familia». → Dice que no hay nada con esos filtros, en vez de quedarse en blanco.
- Ahora la pregunta de verdad: ¿te apetece tocar algo de lo que ves? → Si el feed te parece una tabla de base de datos y no te dice nada, marca ✗ y dime por qué.
Gate
-
autoGET /v1/events?city=Castellón devuelve los eventos sembrados paginados
-
autoGET /v1/events/nearby filtra por radio real (Haversine), verificado con distancias conocidas
-
autoHaversine y bounding box tienen test con coordenadas de Castellón y distancias conocidas
-
túMiro el feed y me apetece tocar algo. No parece una tabla de base de datos
Falla si: Lo veo y no me dice nada, o no sé qué hacer con él
-
túDe un evento entiendo qué es, cuándo y dónde sin abrirlo
Falla si: Tengo que abrir el detalle para saber si me interesa
-
túCojo tres eventos al azar, abro su enlace a la fuente y compruebo que existen de verdad
Falla si: Alguno no existe, o su fecha o su sitio no coinciden con la fuente
2 MCP y scraping real ¿La pieza cara funciona y trae datos de verdad? ✓
cerrada · v0.2.0
Qué queda construido
- Servidor MCP en uat-mcp.pulso.travel con 11 tools y 4 resources, transporte Streamable HTTP sin sesión (no necesita Durable Objects)
- add_event: Luis encuentra algo que falta y el agente lo mete, con geocodificación
- research_event: el agente va a la web oficial y trae descripción e imagen reales
- Scraper de vivecastellon.com con HTMLRewriter y dedup por source_hash
- Las tools que aún no funcionan se niegan diciéndolo, para que el agente no invente
Guión de pruebas
- Añade el MCP a Claude Desktop o Codex con la URL y el token que te doy aparte. → Aparece «pulso» conectado, con 11 herramientas.
- Pregúntale: «¿qué hay este finde en Castellón?» → Contesta con eventos reales, con hora y sitio. Cada uno con su enlace de origen.
- Elige uno y pídele: «cuéntame más de ese». → Usa research_event y te resume lo que encontró, distinguiendo lo que NO encontró.
- Dile: «falta un evento, el [algo que tú sepas], es el [fecha] en [sitio]». → Lo añade con add_event y te da el enlace del feed para verlo.
- Abre ese enlace en el móvil. → El evento está ahí, con la fecha y el sitio que le dijiste.
- Pídele un evento inventado: «busca el Festival de Jazz de Villarreal de 2026». → Dice que no lo encuentra. Si se lo inventa, es un ✗ y el más grave de todos.
- Pídele: «avísame de ese evento». → Registra la suscripción Y te advierte de que el aviso todavía no llega (fase 5).
- Pídele: «hazme una ruta con tres de estos eventos». → Los ordena por cercanía y te avisa de que son distancias en línea recta.
Gate
-
autoUn cliente MCP se conecta y lista las 11 tools y los 4 resources
-
autoLas tools sin construir devuelven error diciendo en qué fase se hacen, y las que no encuentran nada dicen explícitamente que no se invente el resultado
Falla si: Alguna devuelve datos vacíos o falsos como si fueran válidos
-
autoadd_event da de alta un evento con fechas en prosa, no duplica al repetirlo, y se niega si no entiende la fecha en lugar de inventarse una
-
autoSi el municipio geocodificado no es el pedido, se avisa en la respuesta al agente
Falla si: Un evento se coloca en otro pueblo sin decir nada
-
autoEl scraper extrae ≥10 eventos reales de vivecastellon.com con título y fecha
Falla si: Extrae menos de 10, o alguno sin fecha parseable
-
autoScrapear dos veces la misma fuente no duplica eventos (source_hash)
-
túConecto el MCP en Claude o Codex y le pregunto «¿qué hay este finde en Castellón?»
Falla si: No conecta, o me contesta con eventos que no existen
-
túLe digo a Claude que falta un evento que yo conozco y lo añade. Luego lo veo en el feed
Falla si: No lo añade, o lo añade con la fecha o el sitio mal
-
túLe pido que investigue más sobre un evento y me trae información de la web oficial, no inventada
Falla si: Se inventa datos, o no distingue lo que encontró de lo que no
3 Con memoria: quién eres y qué te gusta ¿Recuerda lo que debe? 0/2
esperando tu veredicto · v0.3.0
Qué queda construido
- Preferencias, ubicación y modo acompañante persistidos
- GET /v1/events/for-you cruzando preferencias × ubicación × compañía
- Zero Trust conectado de verdad: Access Application sobre pulso-travel, IdP y service token. Solo falta el API token con Access:Edit
Gate
-
autoCon AUTH_MODE=access-jwt, un JWT sin firmar, caducado o con audience ajeno recibe 401, validado contra el JWKS real de pulso-travel
Falla si: Alguno de los tres casos entra
-
autoEl mismo usuario entrando dos veces no crea dos filas
-
autofor-you ordena por relevance × peso de preferencia, verificado con pesos fijados
-
túEntro con mi Google por Zero Trust y la app sabe quién soy sin que le diga nada
Falla si: Me pide algo más, o no me reconoce al volver
-
túMarco mis gustos, vuelvo mañana y el feed sigue ajustado a ellos
Falla si: Se olvidó de lo que le dije
4 Con tiempo: crons y digest ¿Aguanta el paso de los días? 0/2
sin empezar
Qué queda construido
- Cron de scraping diario 03:00 UTC vía Queue
- Digest matutino pre-computado en KV a las 06:00
- Cron de recordatorios cada 5 min y limpieza semanal
- Días simulados: 7 ejecuciones seguidas sin duplicar ni romper
Gate
-
autoSimular 7 días de crons no duplica eventos ni deja tareas colgadas
Falla si: Crecen los duplicados, o alguna tarea queda en running para siempre
-
autoGET /v1/users/me/digest se sirve de KV, no recalcula
-
autoLa limpieza archiva eventos de hace más de 7 días y no toca los vivos
-
túLeo el digest de la mañana y me sirve. No es un listado, es un plan
Falla si: Es un volcado de eventos sin criterio
-
túVuelvo tres días después sin tocar nada y hay eventos nuevos
Falla si: La base está igual que la dejé
5 El circuito entero: tiempo real y avisos ¿Funciona de punta a punta? 0/2
sin empezar
Qué queda construido
- Durable Object EventChannel con WebSocket y ring buffer de 50
- Web Push real con VAPID (esto sí es gratis, va de verdad)
- Durable Object SocialListener contra stub determinista (no hay claves de X aún)
- Media a R2, servida por media.pulso.travel
Gate
-
autoDos clientes WS conectados al mismo evento reciben el mismo broadcast
-
autoAl reconectar, el cliente recibe los mensajes que se perdió (hasta 50)
-
autoEl payload de Web Push se cifra correctamente (ECDH + VAPID) y el push service lo acepta
-
autoEl social listening en modo stub lo dice en su respuesta: nunca finge ser real
Falla si: Devuelve datos inventados sin marcarlos como stub
-
túMe suscribo a un evento desde el móvil y me llega la notificación push de verdad
Falla si: No llega, llega tarde, o llega sin decir de qué evento es
-
túCon la app abierta pasa algo en un evento y lo veo aparecer sin recargar
Falla si: Tengo que recargar para verlo
6 El canal real ¿Alguien lo quiere de verdad? 0/2
sin empezar
Qué queda construido
- Dominios finales api / mcp / media .pulso.travel en producción
- Docs con Scalar en /docs, público
- Rutas entre eventos (nearest neighbour + Nominatim, sin Google)
- Hot scoring y rate limiting
Gate
-
autoapi., mcp. y media.pulso.travel responden en producción con TLS válido
-
auto/docs y /v1/openapi.json responden sin auth y el spec valida
-
autoLa ruta entre 3 eventos no cruza la ciudad dos veces (orden mejor que el de entrada)
-
túUn fin de semana lo uso yo de verdad para decidir qué hacer, sin forzarme
Falla si: Abro otra cosa para decidir
-
túLe paso la URL a alguien de Castellón sin avisar de que es un PoC
Falla si: Me da vergüenza enseñarlo