TheFittClub — Claude project context bundle

Auto-generado. Fuente: dev repo thefittclub @ a7771a7 · 2026-09-28.

Uso: subir este archivo a tu proyecto TheFittClub en claude.ai → Project Files, reemplazando el anterior. Cadencia recomendada: una vez al mes (o cuando hagas cambios grandes en voice / brand / tickets activos).

No editar manualmente. Cualquier cambio aquí se sobrescribe en la siguiente regeneración. Para editar el contenido: edita el archivo canónico en _docs/01-core/ y vuelve a generar.

Índice

  1. Voice & vocabulario
  2. Brand & posicionamiento (incluye ancla experiencial)
  3. Design system & rúbrica de evaluación
  4. Product law (Rituales / Módulos / Cápsulas)
  5. Strategy
  6. Founder context (privado) — (not bundled — file absent in repo)
  7. Active tickets — full specs
  8. QA tickets — full specs
  9. Pending backlog — summary (top of queue)
  10. Recently shipped — summary
  11. Outreach metrics — current state

§1 — Voice & vocabulario


Sistema de documentos del proyecto:

TheFittClub — Voz y tono de la fundadora

1. Quién habla

La voz de TheFittClub es la voz de Gala Calero. No es un personaje. No es un tono corporativo. Es una mujer real, ingeniera civil, hablando a otra mujer real.

Gala escribe como es: cercana sin ser informal, técnica sin ser clínica, segura sin ser arrogante. Su autoridad no viene de un título médico —viene de haber estudiado el cuerpo como una estructura durante años y de haber vivido en carne propia lo que enseña.

Este documento es la guía práctica para replicar esa voz. Cualquier IA, copywriter o colaborador debe interiorizarlo antes de escribir una sola palabra para TheFittClub.


2. Los 7 rasgos de estilo

Cada texto de Gala respira estos siete rasgos. Si un texto no cumple al menos cinco, no está listo.

2.1 Cercana pero técnica

Explica como alguien que ha estudiado el cuerpo en profundidad y lo ha vivido en primera persona — no desde un título, sino desde el conocimiento y la práctica. Sin sonar clínica ni distante. Usa la primera persona del singular. La usuaria siente que Gala le habla a ella, no a una audiencia.

Ejemplo real (DM):

“Hola! Esto no es raro, la comba es un deporte de alto impacto que se debe retomar cuando realmente estemos preparadas.”

2.2 Validación primero

Arranca normalizando la experiencia de la usuaria antes de corregir o proponer. “Esto no es raro” es su frase de entrada más característica. La usuaria debe sentir que su cuerpo no está roto —está pasando por algo normal y hay camino.

Ejemplo real (DM):

“Muy posiblemente lo que te pasó en la segunda cesárea es que se te quedó adherida la cicatriz a la pared abdominal y por eso estaba hundida en esa zona.”

2.3 Mecanismo + acción

Primero explica el porqué fisiológico (el mecanismo), luego da un siguiente paso concreto (la acción). Nunca suelta información sin anclarla a algo que la usuaria pueda hacer.

Ejemplo real (DM):

“El motivo por el que te ocurre es por debilidad del suelo pélvico. Ir a un fisio que te valore personalmente es muy buena idea.”

2.4 Realismo radical

No promete milagros. Marca límites, plazos y condiciones. La honestidad es su forma de respetar la inteligencia de la usuaria.

Ejemplo real (DM):

“Mejorará seguro, tanto en apariencia como en funcionalidad y sobre todo evitarás que la hernia empeore, pudiendo llegar a convivir con ella sin sus consecuencias. Eso sí, necesitarás tiempo, constancia y tras conseguir el objetivo, mantenerlo.”

2.5 Lenguaje claro y directo

Frases cortas. Sin jerga innecesaria. Si hay que decir “transverso abdominal”, lo dice. Si hay que decir “vagina”, lo dice. Las palabras exactas generan más confianza que los eufemismos.

Ejemplo real (SRT, vídeo):

“El segundo, que es personalmente uno que me gusta mucho más que los kegel, es el movimiento de tratar de elevar nuestra vagina hacia el ombligo.”

2.6 Primera persona, tono humano

Usa “yo”, “nosotras”, expresiones naturales y cierres de acompañamiento. No escribe como una institución: escribe como una mujer que sabe del tema y te acompaña.

Ejemplo real (SRT, vídeo):

“Yo siempre os digo que os hagáis fotos. Es fundamental para poder ir valorando el progreso y poder ir motivándoos.”

2.7 Afirmativa, nunca dubitativa

No usa “quizás”, “tal vez”, “podría ser”. No pide disculpas por no ser médica. Afirma. Propone. Guía. Si algo no lo sabe, lo dice con la misma seguridad: “esto no es mi campo, pero puedo derivarte a quien corresponda.”

2.8 Honesta sobre sus propios límites (con humor)

No oculta cuando algo es largo, complejo o imperfecto. Lo dice directamente y con humor ligero. Esa honestidad es lo que la hace creíble.

Ejemplo real (caption reel):

“Es un vídeo un poco más largo de lo habitual pero no he sido capaz de explicarlo con menos palabras 😅“

2.9 El regreso tras ausencia — su patrón de voz más valioso

Cuando vuelve después de una pausa, no se disculpa en exceso ni dramatiza. Explica la razón con naturalidad, da las gracias sin caer en el sentimentalismo y mira hacia adelante. Este patrón es el modelo para el relanzamiento actual.

Ejemplo real (caption, regreso feb 2023 tras casi un año):

“Tras casi un año sin apenas entrar en Instagram estoy calentando motores.

Llevaba ya un par de meses pensando en retomar este proyecto y creo que el leer algunos de vuestros mensajes me ha dado el empujón.

La vida da muchas vueltas y hace un año me vi metida en un nuevo trabajo bastante exigente al que me tenía que adaptar, a la vez que comencé una reforma en la que tuve que remangarme para conseguir nuestro nuevo hogar.

Imagino que como animal de costumbres, me acostumbré a dejar de subir contenido. Pero vuelvo y traigo interesantes novedades.

Gracias a todas las que os habéis interesado y a las que no me habéis abandonado ❤️”


3. Vocabulario: lo permitido y lo prohibido

Estas reglas no son opcionales. Son una protección legal para Gala y para la marca.

3.1 Permitido (usar siempre)

  • Activa, fortalece, trabaja, entrena
  • Recupera, mejora, restaura
  • Puede ayudar a reducir
  • Resultados visibles en muchas mujeres
  • Usuarias, educación física, evaluación física, entrenamiento adaptativo
  • Bienestar holístico, empoderamiento, recomendación

Nota técnica: el linter content-legal-check.mjs hace match exacto de palabra (word-boundary en ambos extremos). Por eso esta lista enumera inflexiones explícitamente — no asume stems. Si añades un término, añade sus formas comunes.

  • Pacientes, paciente, diagnóstico, diagnósticos, tratamiento, tratamientos, curación, curaciones, terapia psicológica, receta médica
  • Cura, curan, elimina, eliminan, eliminado, eliminada, eliminamos, corrige, corrigen, corregir, corregido, diagnostica, diagnostican, diagnosticar, tratamiento garantizado
  • Rehabilita, rehabilitan, rehabilitar, rehabilitación (si no hay contexto clínico formal)
  • Querida, queridas, guapa, guapas, reina, reinas, campeona, campeonas, cariño, cariños (infantilizantes)
  • Pierde peso, perder peso, quema grasa, quemar grasa, tonifica, tonifican, tonificar, tonificación, ponte en forma (fitness genérico)

3.3 Frases seguras de sustitución

En lugar deUsar
”Reduce la diástasis""Puede ayudar a reducir la diástasis"
"Elimina las pérdidas""Fortalece el suelo pélvico"
"Cura el prolapso""Mejora la función del suelo pélvico"
"Te garantizo resultados""Los resultados dependen de la constancia y el punto de partida”

3.4 Checklist pre-publicación

Antes de publicar cualquier texto, verificar:

  • No hay promesas absolutas
  • No hay lenguaje de diagnóstico
  • El CTA no sugiere sustitución médica
  • Si aplica, incluye derivación a profesional sanitario

3.5 Motivación: refuerzo digno vs gamificación barata

La motivación es vital — una app que no reconoce el esfuerzo no es amigable. Pero el refuerzo de TheFittClub nace de devolverle a la usuaria sus propios datos reales, con calidez y respeto, nunca de mecánicas fabricadas ni de culpa. La dopamina se gana, no se manipula. Esta sección aterriza el principio #3 de marca (“Sin culpa. Sin falsa motivación. Con realismo y calidez”): “sin falsa motivación” prohíbe lo fabricado, no la motivación verdadera.

✅ Permitido / fomentado❌ Prohibido
Reconocer un hito real con sobriedad (“Semana 1 completada”)Culpa / pérdida (“no rompas tu racha”, “vas a perder tu progreso”)
“Días Activos” / constancia como dato del que enorgullecerseUrgencia o escasez fabricada (“¡solo hoy!”, “se te escapa”)
Progreso preciso y honesto (“Día 12 de 30”, anillo de fase)Emoji-spam de hype y celebración que suena falsa
Calidez al celebrar (“bien hecho, esto es constancia de verdad”)Frases motivacionales vacías (“¡tú puedes!”, “¡eres una crack!“)
Una racha contada como ritmo sostenibleInfantilizar o tratar el logro como un juego de puntos

Regla de oro: si el refuerzo sigue siendo verdad cuando la usuaria falla una semana, es digno. Si solo funciona presionando, es gamificación barata.

Superficie abierta (decisión fundadora 2026-06-13): este tipo de señal — constancia, Días Activos, hitos — puede vivir donde aporte (dashboard, perfil, player, email…). No se cierra el diseño a una superficie concreta; no sabemos aún dónde interesará más mostrarla.

3.6 Longevidad: vocabulario seguro / prohibido (T49 D8)

La oferta incluye objetivos longevity-adjacent (fuerza sostenida, postura duradera, recomposición corporal en el tiempo). El límite sigue siendo wellness/fitness — los reguladores (AEMPS, AESAN, AEPD) leen “longevidad” con más severidad que sus equivalentes fitness; cruza el Real Decreto 1907/1996 si el vocabulario se vuelve claim de propósito sanitario. SSOT operativo y razonamiento completo: _docs/01-core/compliance/longevity-terminology.md.

✅ Seguro (descriptivo / mecanismo)❌ Prohibido (perímetro regulado)
“salud a largo plazo”, “rendimiento físico duradero”, “fuerza sostenida en el tiempo""antienvejecimiento”, “rejuvenecimiento”, “anti-aging"
"vitalidad”, “energía cotidiana”, “hábitos que se mantienen""programa de longevidad”, “tratamiento de longevidad”, “programa antiage”, “fórmula de longevidad”, “longevidad celular"
"cintura fina con transverso fuerte”, “buena postura corporal”, “ganancia muscular en glúteos""prevención de enfermedad”, “previene [condición]”, “reduce el riesgo de [patología]"
"hipertrofia muscular optimizada a tu complexión”, “reclutamiento de fibras”, “reeducación neuronal""resultados clínicos”, “evidencia clínica” (la palabra clínica arrastra a perímetro médico)
“constancia que sostiene resultados en el tiempo”cualquier claim cuantitativo de extensión de vida (“añade X años”, “vive más”)

Regla: describe la actividad y su mecanismo; nunca un resultado clínico ni un producto de longevidad. Esta tabla extiende §3.2 (no la sustituye) y la consume tfc-brand-vocab-lint + T53 (blog).


4. Fragmentos reales de referencia

Estos fragmentos son ejemplos auténticos de la voz de Gala. Úsalos como referencia de tono, ritmo y estructura al generar nuevo contenido.

4.1 DM: Comba + suelo pélvico

Hola!

Esto no es raro, la comba es un deporte de alto impacto que se debe retomar cuando realmente estemos preparadas.

El motivo por el que te ocurre es por debilidad del suelo pélvico. Ir a un fisio que te valore personalmente es muy buena idea, aunque también es cierto que es fácil que te digan que estás bien y teniendo pérdidas con la comba porque como te comento es de alto impacto y muchas veces nos dan el visto bueno cuando no estamos tan tan bien.

En cuanto a mi programa online, tiene una duración mínima de cuatro meses y al menos nos vamos asegurando de que vamos subiendo correctamente de nivel. Porque cada mujer requiere un tiempo diferente y cada mujer tiene un punto de partida diferente.

4.2 DM: Cesárea + fibrosis

Hola!

Muy posiblemente lo que te pasó en la segunda cesárea es que se te quedó adherida la cicatriz a la pared abdominal y por eso estaba hundida en esa zona. Y en la tercera cesárea debes de tener fibrosis sobre la cicatriz. Si ya han pasado dos años, que se elimine la fibrosis no va a ser posible.

Masajeando la cicatriz sí que vas a conseguir que esté mejor, pero no vas a poder eliminar ese bulto si es una fibrosis.

Con el programa lo que sí que puedes conseguir es volver a tener un core fuerte y un abdomen plano, pero la cicatriz posiblemente siga teniendo ese bulto que comentas.

4.3 DM: Hernia + horizonte real

Mejorará seguro, tanto en apariencia como en funcionalidad y sobre todo evitarás que la hernia empeore, pudiendo llegar a convivir con ella sin sus consecuencias. Eso sí, necesitarás tiempo, constancia y tras conseguir el objetivo, mantenerlo.

4.4 SRT: Activación suelo pélvico (vídeo)

Tres tipos de activación de suelo pélvico.

El segundo, que es personalmente uno que me gusta mucho más que los kegel, es el movimiento de tratar de elevar nuestra vagina hacia el ombligo.

¿Por qué te recomiendo practicar los tres? Porque es importante saber mandar con nuestra mente a nuestros músculos diferentes tipos de señales.

4.5 SRT: Progreso postparto real (vídeo)

Dejar constancia gráfica de ahora, que casi hace cuatro semanas que di a luz, cómo va mi abdomen para luego poder ir viendo la evolución.

Yo siempre os digo que os hagáis fotos. Es fundamental para poder ir valorando el progreso y poder ir motivándoos.


4b. Fragmentos reales de IG — captions publicados

Los DMs de §4 muestran cómo Gala responde. Los siguientes muestran cómo escribe para publicar. Son registros distintos: el caption es más estructurado y pedagógico; el DM es más conversacional. Ambos son la misma voz.

4b.1 Caption post educativo (17.417 guardados — el más guardado del historial)

⚠️ Nota: el reel de 2023-06-18 (13.912 guardados, flexores cadera + suelo pélvico) tiene caption escrito por IA — no usar como referencia de voz. El vídeo es de Gala, el texto no.

❤️ Hoy os traigo 5 ejercicios para aplanar el abdomen bajo y fortalecer los músculos profundos del abdomen y del suelo pélvico.

Como persona estudiosa y practicante de la recuperación postparto, creo que la clave para un core fuerte y saludable es re-conectar y fortalecer estos músculos importantes.

A menudo, cuando pensamos en tener un abdomen plano, nos centramos en hacer abdominales tradicionales, pero esto sólo trabaja los músculos superficiales del abdomen. Para tener un abdomen realmente plano y fuerte, necesitamos trabajar en la activación profunda de los músculos del core y el suelo pélvico.

Trabajarlos es especialmente importante después de haber sido madre (tanto si pasaron semanas o años desde el último parto), ya que los músculos del núcleo y del suelo pélvico se debilitan durante el embarazo y el parto.

Qué hace aquí: abre con emoji + promesa concreta → se posiciona como estudiosa y practicante (no médica) → explica el mecanismo (por qué los abdominales normales no bastan) → amplía el contexto (no solo postparto reciente, también años después).

4b.2 Caption reel explicativo (mecanismo + debunking)

Todavía crees que lo importante es el tener o no diástasis. Yo no tengo diástasis ya. Pero observa qué ocurre si no activo correctamente el core bajo presión. Aquí podéis ver la protusión en la zona del ombligo.

Ahora voy a repetir el mismo ejercicio activando correctamente el core. Veamos qué ocurre bajo la presión. Nada. Abdomen plano y funcional.

No solo cuenta la diástasis. Si quieres que te ayude, visita mi programa.

Qué hace aquí: desafía una creencia extendida → demuestra en su propio cuerpo → CTA directo al final sin rodeos.

4b.3 Caption instructivo con sistema de progresión (816 guardados)

🤍 Rutina transición Nivel Básico → Nivel Intermedio 🤍

Debemos de tratar qué la exhalación y activación del transverso dure todo el recorrido del movimiento e inhalar y relajar, cuando estamos en la posición de descanso.

Si tenéis duda sobre cómo hacer la activación del transverso correctamente usando la respiración abdominal, en las historias destacadas, tenéis una qué se llama técnicas y en un par de ellas lo explico 😘

Esta rutina, está pensada para ser repetida de 2 a 3 veces, respetando nuestro cuerpo, si se nos cansa el abdomen y no somos capaces de activar, lo dejamos. Ya iremos poco a poco ganando fuerza y concentración.

Qué hace aquí: instrucción técnica precisa → deriva al archivo de stories para más contexto → da permiso para parar (“si se nos cansa el abdomen”). La frase “ya iremos poco a poco” es una de sus marcas de paciencia radical.

4b.4 Caption de regreso tras pausa larga (plantilla para el relanzamiento)

Tras casi un año sin apenas entrar en Instagram estoy calentando motores.

Llevaba ya un par de meses pensando en retomar este proyecto y creo que el leer algunos de vuestros mensajes me ha dado el empujón.

La vida da muchas vueltas y hace un año me vi metida en un nuevo trabajo bastante exigente al que me tenía que adaptar, a la vez que comencé una reforma en la que tuve que remangarme para conseguir nuestro nuevo hogar.

Imagino que como animal de costumbres, me acostumbré a dejar de subir contenido. Pero vuelvo y traigo interesantes novedades.

Gracias a todas las que os habéis interesado y a las que no me habéis abandonado ❤️

Qué hace aquí: anuncia el regreso sin disculparse → explica con naturalidad (no drama) → usa humor suave (“animal de costumbres”) → cierra con gratitud genuina. Cero auto-flagelación.


7. Quirks de escritura — observados en posts reales

Estos patrones aparecen de forma consistente en el historial de 664 posts. No son errores: son la voz.

7.1 “qué” en lugar de “que” en instrucciones

En captions instructivos Gala usa “qué” donde gramaticalmente iría “que”. Es un ritmo visual, no un error de tildes.

“Recordad qué la calidad es más importante qué la cantidad.” “Está pensada para ser repetida de 2 a 3 veces, respetando nuestro cuerpo, si se nos cansa el abdomen y no somos capaces de activar, lo dejamos.”

Cuándo reproducirlo: en captions instructivos tipo rutina. No en emails, artículos de blog ni DMs.

7.2 Emojis como arquitectura visual

Los emojis no son decoración: marcan secciones y ritmo.

  • Al inicio del título del post: 💜 🤍 ❤️ ☀️ ⚡️ 🤩
  • Al final de frases de aliento o cierre: ❤️ 💪🏼 😉 😘 🙌🏼
  • Para marcar bullet points de logros: ✅ 🔝

No van en medio de frases explicativas. No más de 3-4 por caption.

7.3 Dirección siempre en femenino

“Compañeras”, “vosotras”, “nosotras”. Nunca género neutro ni masculino genérico. La audiencia es 100% femenina y el texto lo refleja.

7.4 La frase de paciencia radical

Aparece en casi todas las rutinas: una variación de “cada cuerpo necesita un tiempo diferente” o “ya iremos poco a poco”. Es su forma de desactivar la ansiedad de resultado.

7.5 Estructura del caption de rutina

[emoji] Título del nivel / tipo de rutina [emoji]

Qué consigue esta rutina (1-2 frases).

Instrucción técnica principal (cómo activar, qué sentir).

Número de repeticiones y modificaciones.

Permiso para parar / frase de paciencia.

[CTA suave o link a bio si aplica]

#hashtags

7.6 Top pain_flags por guardados (qué duele más a la audiencia)

Basado en el análisis de los 664 posts:

  1. diastasis — el dolor más buscado
  2. suelo_pelvico — el más guardado en formato educativo
  3. recuperacion_postparto — el más amplio
  4. barriga_postparto — el más emocional
  5. cesarea — audiencia muy fiel y agradecida
  6. hipopresivos — diferenciador técnico de la marca

4c. Voz docente — transcripciones reales de vídeos del curso

Este es el tercer registro de Gala: ni DM ni caption. Es la voz de cuando enseña en vídeo. Más lenta, más rítmica, más corporal. Es la fuente más auténtica porque no hay edición — es ella pensando y enseñando al mismo tiempo.

Características exclusivas de este registro:

  • Ritmo respiratorio como estructura: “cogemos aire… soltamos…” funciona como metrónomo para la alumna
  • Se incluye a sí misma en el ejercicio: “aquí yo lo tengo más tenso por ejemplo”, “yo tengo una cesárea, así que por eso me quedo más”
  • Normaliza la imperfección mientras enseña: “esto yo no es una cosa que haga muy a menudo, debería hacerlo más a menudo porque es súper bueno y por eso no tengo tanta habilidad”
  • Conecta la mecánica con el cuerpo real: “estos que tenemos aquí”, “este espacio que hay entre la columna en los lumbares y el suelo”
  • Usa metáforas físicas propias: el ascensor (suelo pélvico), la sonrisa (contracción abdominal), borrar la curvatura

4c.1 Explicación técnica con anatomía precisa y metáfora (Fase 1, circuito tonificación)

“Vamos a necesitar un bloque de yoga y una esterilla. Comenzaremos con un ejercicio de relajación de suelo pélvico. Para ello vamos a colocar el bloque bastante cerca. Nos vamos a sentar en él, dejando nuestros huesos isquiones —estos que tenemos aquí, sobre los que nos apoyamos— colgando fuera del bloque.

Cuando cojamos aire, vamos a sentir como se nos relaja toda la zona abdominal, del suelo pélvico, y en general nos abrimos. Y cuando soltemos el aire, vamos a activar todo nuestro núcleo, nuestro suelo pélvico, y a sentir cómo se le va hacia el ombligo.

Aunque ahora mismo suene extraño, no os preocupéis porque con la práctica todo esto se os va a ir reconectando.”

4c.2 La metáfora del ascensor — su imagen más usada para el suelo pélvico

“Queremos sentir como si tuviéramos un ascensor. En la parte de la relajación lo dejamos abajo, sin llegar a hacer fuerza para afuera, simplemente en la planta baja. Y cuando comenzamos la activación, comenzamos a subir.

Quiero que visualicéis esto del ascensor y de una cremallera que conforme va pasando, va cerrando. Hacia arriba conforme nos vamos estirando y soltando el aire.”

4c.3 Permiso explícito para no hacerlo perfecto (Bonus kinesiotape)

“No hace falta que sea una precisión quirúrgica. Es más importante hacerlo que por miedo a no hacerlo perfecto, no hacerlo. Y si tenéis cualquier duda, por favor, escribid.”

4c.4 Se incluye a sí misma, en tiempo real (Fase 2, funcional)

“Yo tengo una cesárea, así que por eso me quedo más. Si habéis tenido un parto por cesárea, os recomiendo mucho el enfocaros bastante en la zona de la cicatriz con la pelota, porque también ayuda a movilizar dentro los tejidos de la cicatriz y viene fenomenal.”

4c.5 Por qué antes de cómo — siempre explica el mecanismo (Fase 2, funcional)

“Es muy importante jugar con la respiración para que el masaje realmente sea profundo. Si no, nuestro cuerpo tiende a cerrarse, a contraerse, y no conseguimos nada.”

“Es muy importante saber diferenciar las respiraciones porque, por ejemplo, en el caso de hacer ejercicios isométricos, en la postura de relax podemos hacer respiraciones 360 grados llevando el aire también a la tripa. Pero una vez que estamos en posición isométrica, como una plancha, nos interesa llevar el aire hacia arriba, hacia las costillas y hacia el pecho, y menos hacia la tripa, para poder mantener la tensión en el abdomen.”

4c.6 Honesta sobre sus propias limitaciones, en tiempo real (Respiración del fuego)

“A ver, hemos llegado al final de la semana. Hoy es un día tranquilo, solamente quiero que hagáis un ejercicio de respiración, que es la respiración del fuego.

Ok, ya estoy perdiendo el ritmo. Puede que hayáis aguantado mucho más. Esto es posible. De hecho, esto yo no es una cosa que haga muy a menudo. Debería hacerlo más a menudo porque es súper bueno y por eso no tengo tanta habilidad.”

4c.7 Cuidado genuino — conecta el ejercicio con la vida larga (Fase 2, funcional)

“Vuestros músculos, vuestra abdomen, vuestro cuerpo os va a acompañar toda la vida. Queremos que dé lo mejor de sí. Queremos evitar pérdidas, no queremos prolapsos, no queremos corrimientos. Queremos un abdomen plano, queremos estar bien, pero siempre desde la salud.”


Lo que distingue la voz docente de la voz de caption

Caption IGDMVídeo curso
LongitudMedia, estructuradaCorta, directaLarga, rítmica
PersonaGala → vosotrasGala → túGala + nosotras juntas
TonoPedagógica + CTAClínica + empáticaCorporal + íntima
MecánicaExplica el por quéResuelve el problemaGuía el cuerpo en tiempo real
ImperfecciónOcultaHonestaVisible y usada como recurso
MetáforasPocasNingunaCentrales (ascensor, cremallera, sonrisa)

Este prompt puede usarse con cualquier IA para convertir transcripciones de vídeo, notas de voz o ideas sueltas en contenido listo para publicar con la voz de Gala.

Actúa como editora de contenido de Gala Calero, fundadora de TheFittClub.

Tu tarea: convertir la transcripción que te pego en un artículo de blog escrito con la voz de Gala, siguiendo el documento thefittclub-voice.md.

Usa este estilo:

Cercano pero con autoridad propia: alguien que ha estudiado el cuerpo a fondo, lo ha vivido en primera persona y enseña desde esa combinación — no desde un título sanitario.

Primera persona singular.

Frases cortas y claras.

Estructura: respuesta directa al inicio, explicación fisiológica, pasos prácticos, cierre accionable.

No prometer resultados absolutos.

Honestidad intelectual: explicar límites cuando corresponda y derivar a profesional sanitario si el tema lo requiere.

Reglas de vocabulario:

Usa: activa, fortalece, trabaja, entrena, recupera, mejora, puede ayudar.

Evita: cura, elimina, corrige, tratamiento garantizado.

Formato de salida:

Título SEO (claro y específico).

Respuesta corta en 2-4 líneas al inicio (pirámide invertida).

Desarrollo en secciones H2/H3.

Bloque “Qué hacer desde hoy” en viñetas.

Cierre con CTA suave (guardar, compartir o visitar programa).

Meta description (140-155 caracteres).

Ahora convierte esta transcripción: [PEGAR TRANSCRIPCIÓN]

text


6. Diferencias con otros documentos

Este documento no compite con los demás. Cada uno cubre un dominio distinto:

  • thefittclub-brand.md define qué transmite la marca y cómo debe sentirse la usuaria. Este documento define cómo se escribe para lograr esa transmisión.
  • thefittclub-product.md define las reglas de negocio y arquitectura. Este documento define cómo se comunican esas reglas a la usuaria.
  • thefittclub-strategy.md define los canales y el roadmap. Este documento define el tono con el que se ejecuta esa estrategia.

Este documento es la guía práctica de la voz de TheFittClub. Cualquier texto que salga de la marca —un email, un post, un guión, un DM— debe pasar por estos siete rasgos y este filtro de vocabulario.

Última actualización: Mayo 2026 (T145 — tono SaaS-genérico).


8. SaaS-generic tone gate

Implementado por T145 (2026-05-27). Esta sección documenta la taxonomía de frases cliché SaaS que se detectan automáticamente por el segundo pass del linter tfc-brand-vocab-lint/scripts/lint.sh. Las reglas derivan del contrato de voz de las §§ anteriores; este apartado las hace explícitas para el registro de IA generativa.

Por qué existe este gate

tfc-brand-vocab-lint ya bloquea palabras individuales prohibidas (§3.2). Pero hay un segundo vector de deriva: frases compuestas por palabras individualmente legales que, juntas, forman el registro SaaS-genérico que la marca rechaza. La IA generativa produce estas frases por defecto. Sin un gate determinista, se filtran a producción silenciosamente.

Tres categorías de deriva identificadas:

  1. Compuestos cliché. Cada palabra es inofensiva; el compuesto es el cliché: “unlock your potential”, “your best self”, “transform your life”, “join thousands”, “level up your routine”. En español: “tu mejor yo”, “transforma tu vida”, “desbloquea tu potencial”.

  2. Verbos imperativos de poder. La voz de la marca es invitación, no comando. “Conquer your…”, “Crush your…”, “Master your body/life” colocan el cuerpo de la usuaria como obstáculo a vencer — incompatible con el ancla ‘santuario’. En español: “conquista tu…”, “aplasta tus…“.

  3. Adjetivos hiperbólicos. Drenan la especificidad de la marca: “revolutionary”, “game-changing”, “transformative”, “breakthrough”, “science-backed” (sin cita), “mindset shift”. La voz de Gala nombra el mecanismo; no necesita superlatives.

Taxonomía de severidad

SeveridadComportamientoCategorías
ERRORBloquea siempre (pre-commit + CI)Compuestos cliché + verbos imperativos de poder (ES + EN)
CAUTIONBloquea solo bajo TFC_VOCAB_STRICT=1Adjetivos hiperbólicos

Patrones de sustitución recomendados

Frase prohibidaAlternativa anclada en mecanismo
”unlock your potential”Nombrar qué cambia en el cuerpo: “reactivar el core profundo"
"transform your life""Entrenar el suelo pélvico que tu cuerpo ya tiene"
"your best self”La versión específica del objetivo: “core funcional y sin pérdidas"
"join thousands”Omitir o citar número real con fuente
”level up your routine”Describir el progreso de fase: “avanzar al siguiente bloque de carga"
"revolutionary”Describir el mecanismo diferenciador en concreto
”science-backed”Citar fuente: “basado en [estudio/protocolo específico]"
"mindset shift”Nombrar el cambio motor: “reconectar señal nerviosa → músculo”

Bypass procedure

Ver CLAUDE_GUARDRAILS.md §Tone gate. El bypass determinista es via .lint-saas-cliches.allowlist.json (legacy debt con expires o excepción permanente con cita). Nunca git commit --no-verify sin registrar la justificación en el allowlist.


§2 — Brand & posicionamiento (incluye ancla experiencial)


description: Identidad de marca de TheFittClub — quiénes somos, a quién hablamos, metodología, estética y principios. Fuente de verdad para cualquier material de la marca.

Sistema de documentos del proyecto:

TheFittClub — Identidad de marca

1. Qué es TheFittClub

TheFittClub es una casa de bienestar para mujeres que exigen lo mejor para sí mismas. No es una app de fitness. No es un spa. No es una clínica. Es el lugar donde una mujer culta, exigente y vanidosa encuentra a una autoridad silenciosa que la guía de vuelta a su cuerpo.

TheFittClub nace de la ingeniería, no del marketing. Su fundadora es ingeniera civil —una mujer que entiende el cuerpo como una estructura y que ha vivido en carne propia lo que significa perder el control de esa estructura. Esa combinación de precisión técnica y experiencia visceral es el ADN de la marca.

TheFittClub comparte con el biohacking más puntero la convicción de que el cuerpo humano puede alcanzar niveles extraordinarios con la tecnología adecuada. Pero donde otros ofrecen datos fríos y optimización agresiva, TheFittClub ofrece una experiencia que envuelve la ciencia más avanzada en un ritual de autocuidado profundamente femenino.


2. La mujer a la que hablamos

Mujer, 35–52 años. Audiencia mayoritariamente LATAM: Argentina (25.1%), Espana (19.1%), Mexico (15.9%), Colombia (11.3%), Chile (6.5%) (snapshot: 2026-09-20). Las ventas, en cambio, se concentran casi por completo en España: la audiencia LATAM da alcance y autoridad; la clienta que paga es sobre todo española. El crecimiento se busca en el mercado angloparlante — la marca es bilingüe ES/EN desde el relanzamiento (ver Estrategia §5.1). Profesional en activo, empresaria o autónoma. Ha invertido en su cuerpo antes. No es impresionable. Busca resultados reales. Ver Audiencia_IG_Real para demografía completa.

El hilo conductor no es el postparto. El hilo conductor es querer su mejor cuerpo posible para su complexión. El postparto es una entrada, no la identidad.

VarianteQuién esLo que busca
Sin maternidadNunca ha sido madre. Quiere cambiar su composición corporal.Método con progresión real, no rutinas genéricas.
Postparto reciente0–2 años desde el parto. Cuerpo en proceso de recuperación.Recuperar función + estética sin riesgo. Que alguien la entienda.
Madre de hace años3+ años desde el parto. Nunca recuperó el cuerpo preparto.Saber que aún es posible. Método, no resignación.
Pre-embarazoPlanea quedarse embarazada o no puede/quiere.Preparación estructural del cuerpo, no solo estética.

Regla de copy y diseño: cualquier pantalla o texto debe funcionar para las 4 variantes. Si solo funciona para la de postparto reciente, está mal calibrado.

Necesidad real: su mejor cuerpo dado su complexión y su historia — cintura fina mediante transverso fuerte, postura, hipertrofia glútea, ganancia muscular optimizada a su complexión. No el cuerpo de otra mujer.

Lo que ha probado y ha fallado: gimnasio genérico, pilates/yoga sin progresión, personal trainer que no entendía su cuerpo, apps genéricas, programas de postparto centrados en recuperación básica. Ha abandonado no por pereza, sino porque los métodos no entendían su cuerpo.

Lo que teme: ser juzgada, ser tratada como paciente clínica, recibir el plan genérico de siempre, pagar premium por algo básico, sentirse culpable cuando no puede seguir el ritmo.

Lenguaje que resuena: precisión técnica sin condescendencia, “yo te veo”, calidez sin paternalismo, resultados medibles con plazos honestos.

Lenguaje que repele: vocabulario médico/clínico, urgencia manipuladora, streak guilt, “transformation challenge”, comparativas antes/después, “guapa/reina/campeona”.


3. Lo que ella desea sentir

Al descubrir la marca

Que ha encontrado algo que no sabía que existía pero que siempre había deseado. Algo hecho para ella. Para su cuerpo. Para su momento vital. Algo que no es para todas las mujeres, solo para las que entienden lo que vale cuidarse de verdad.

Curiosidad intelectual: “Esto es diferente. Esto tiene sentido. Esto está pensado por alguien que sabe de lo que habla.”

Al comprar

Un acto de autocuidado elevado. No una transacción: una declaración de intenciones. Está entrando a un espacio al que no cualquiera accede, pero para el que ella está cualificada.

El precio debe parecer justo —no barato, justo— porque lo que recibe no es un programa de ejercicios: es una guía personal, una metodología propietaria, acceso a una fundadora que entiende su cuerpo mejor que nadie.

Al usar la marca

“Estoy en las mejores manos.” Todo está cuidado. Todo tiene sentido. Una mente ingenieril ha pensado en cada detalle.

“Me cuidan, no me juzgan.” No hay presión. No hay culpa. Si un día no puede, la marca la acoge con la misma elegancia con la que la celebra cuando completa.

Al proyectarse a través de la marca

Usar TheFittClub es un marcador de estatus silencioso. Cuando saca el teléfono, quien esté al lado debe intuir: esto no es una app genérica. Cuando dice “estoy haciendo Ritual Core”, está diciendo sin decirlo: yo invierto en mí. Yo tengo estándares.


4. Por qué desea comprar

Quiere recuperar el control de su cuerpo. Alguien le ofrece un camino estructurado, con fases, con evaluaciones, con criterio técnico. No promesas vagas. Ingeniería aplicada a su cuerpo.

Quiere sentirse deseada de nuevo. Por ella misma. Quiere mirarse al espejo y reconocerse. Quiere recuperar su cintura, su abdomen, su seguridad.

Quiere pertenecer. Un espacio selecto donde las mujeres se reconocen entre sí por sus estándares. No hay que dar explicaciones. Todas han llegado allí porque se lo merecen.

Quiere confiar. Está harta de probar cosas que no funcionan. Quiere alguien con autoridad real. Alguien que haya estudiado el cuerpo como una estructura. Alguien que haya pasado por lo mismo.


5. La metodología

El problema que nadie está resolviendo

La mayoría de los programas de entrenamiento para mujeres hacen lo mismo: cogen una plantilla de hipertrofia masculina, le bajan el peso y le ponen un filtro rosa. No entienden el cuerpo que tienen delante.

El cuerpo de una mujer que ha sido madre —o que simplemente ha pasado años sin entrenar su core de forma específica— no es el mismo que el de una mujer que nunca ha interrumpido su actividad. Su transverso abdominal ha estado sometido a una presión sostenida durante meses. Sus patrones de movimiento se han reorganizado alrededor de una estructura que ya no existe.

Llegar a esa mujer y decirle que haga sentadillas, planchas y abdominales no es entrenar. Es ponerle una trampa a su cuerpo.

Lo que el mercado ha decidido ignorar, yo lo convertí en la columna vertebral de mi método.

El diferenciador central

Cualquier programa serio de entrenamiento respeta una progresión. Pero casi todos empiezan en el escalón tres.

Ritual Core insiste en cuatro fases, en orden, sin atajos. No puedes construir músculo que no sabes reclutar. No puedes reclutar fibras que tu cerebro ha desconectado. Y no puedes reconectar lo que no has reaprendido a sentir.

El orden no es opcional. Es el método.

Esto no lo aprendí en un manual de entrenamiento. Lo aprendí estudiando el cuerpo como una estructura —soy ingeniera civil, no entrenadora de gimnasio— y viviendo en carne propia lo que significa intentar recuperar un abdomen funcional después de dos cesáreas.

Las cuatro fases

Fase 1 — Conectando Cuerpo y Mente. Antes de que exista fuerza tiene que existir conexión. Tu cerebro necesita volver a hablar con los músculos que llevan meses o años en silencio. Esta fase es pura reeducación del movimiento: respiración diafragmática, activación del transverso en estático, control postural. Parece poco. Es la base sin la cual todo lo demás se construye sobre arena.

Fase 2 — Llamando a Más Fibras Musculares. Una vez que el patrón básico está activo, el trabajo cambia: ahora se trata de que respondan más fibras, de forma más consistente y en la secuencia correcta. Se introduce intensidad controlada. Movimientos funcionales que exigen al core mantener la estabilidad mientras el resto del cuerpo se mueve.

Fase 3 — Tejiendo Mi Faja Abdominal. El transverso ya responde. El suelo pélvico ya acompaña. Ahora toca tejerlos en una sola unidad funcional. Las evaluaciones de readiness no son un examen: son una protección. Entrar a esta fase sin los cimientos puestos es la razón por la que tantas mujeres terminan con dolores de espalda y diástasis que no cierran.

Fase 4 — Feminidad y Fuerza. La fase final no es un destino. Es una celebración. Llegar aquí significa que tu core funciona. Ahora sí, el trabajo de glúteos, la movilidad, el Barre Fitness —todo lo que embellece y esculpe— tiene sentido porque se construye sobre una estructura que no va a fallar. No el cuerpo genérico de una modelo fitness. El mejor cuerpo posible dado el cuerpo que tú tienes.

Por qué funciona mejor

No funciona mejor porque yo sea más lista. Funciona mejor porque el método respeta una verdad que el fitness convencional ignora: el cuerpo femenino no es un cuerpo masculino con menos testosterona.

El 95% de los programas femeninos están diseñados al revés: empiezan por el final (la hipertrofia, la estética) y asumen que el camino se hará solo. Ritual Core empieza por el principio: la conexión neuronal, la respiración, la activación profunda. La estética es el resultado de la función. No al revés.

Cualquier mujer que no haya trabajado su transverso de forma específica —haya sido madre o no— se beneficia de este método. Porque el transverso es el músculo más infrautilizado del cuerpo femenino, punto.

Perimeter de compliance (no negociable): el vocabulario permitido y prohibido tiene UNA sola fuente de verdad: Estilo_Escritura §3.1 (permitido), §3.2 (prohibido) y §3.6 (longevidad). Esta sección mantenía una lista propia divergente (p. ej. permitía “forma física” mientras §3.2 prohíbe “ponte en forma”) — colapsada a este puntero en la auditoría legal 2026-07-25. Si un texto de marca necesita un término nuevo, se añade en el SSOT (repo dev, _docs/01-core/thefittclub-voice.md), nunca aquí.


6. El ecosistema: más allá de la recuperación

TheFittClub no termina cuando la mujer recupera su cuerpo. Ahí empieza la segunda capa.

Una vez que ha reconstruido su suelo pélvico, ha cerrado su diástasis, ha recuperado el control de su core, despierta en ella una pregunta nueva: “¿y ahora qué más puedo hacer?” No es conformismo. Es ambición.

TheFittClub le responde con un ecosistema de Módulos y Cápsulas que exploran territorios donde el fitness tradicional ni siquiera entra. Cada mujer construye su propio camino. No es un programa único para todas. Es “tu cuerpo, tu ritmo, tu combinación”. La personalización como lujo definitivo.

Feminidad y energía sexual. Por fin alguien habla de esto. De la libido, del deseo, de la seguridad en el propio cuerpo. No desde el esoterismo: desde la biología, la neurociencia y la práctica guiada.

Visualización y mentalidad. Herramientas de alto rendimiento traídas al universo del bienestar femenino con el mismo rigor que un programa de entrenamiento.

Destrezas físicas como hitos de poder. Hacer una dominada estricta por primera vez. Aprender un nauli. No son ejercicios: son conquistas personales.

Tech Beauty. La tecnología más avanzada del mundo funcionando a su favor, pero tan perfectamente integrada que ni siquiera tenga que pensar en ella. La tecnología no se ve. Se siente.


7. Personalidad de la marca

TheFittClub tiene la personalidad de su fundadora. Si la marca fuera una persona, sería:

Culta. Habla con precisión. Usa las palabras exactas. Su conocimiento es evidente en cada sílaba.

Tranquila. No se excita. No grita. Su autoridad es tan sólida que no necesita imponerse. No hay urgencia en su tono. Hay certeza.

Exigente. No se conforma con menos que la excelencia. Cada material, cada texto, cada imagen ha pasado por un filtro de calidad. No es perfeccionismo neurótico: es estándar de ingeniería.

Sensual. Emana un erotismo sutil, adulto, sofisticado. La seguridad de una mujer que conoce su cuerpo, que sabe lo que vale, que no tiene miedo de habitar su feminidad con poder.

Cercana pero no informal. Te habla de tú. Te entiende. Pero no te llama “guapa” ni “reina”. No es tu amiga. Es tu guía.

Nunca dubitativa. No usa “quizás”, “tal vez”. Afirma. Propone. Guía.

Puntera. Está en la frontera de lo que se sabe sobre el cuerpo, el entrenamiento y la tecnología aplicada al bienestar. No sigue tendencias: las marca.


8. Estética y atmósfera — Santuario + Inteligencia Aterrizada

La estética de TheFittClub se describe con sensaciones, no con reglas de diseño.

Es un santuario. El espacio donde la usuaria trabaja su cuerpo con precisión y sin ruido externo. Cálido, recogido, presente. No contemplativo: activo. El lugar donde ocurre algo real.

Es inteligencia que no se ve. La complejidad técnica está resuelta antes de que llegue. Lo que percibe es que todo encaja. Micro-respuestas que demuestran comprensión sin exhibirla.

Es un editorial de precisión. Serif para los momentos de peso editorial, sans para la UI, mono para lo técnico. Nada es decorativo; todo comunica.

Es silencio después de un portazo. El momento en que cierras la puerta y respiras. Tu cuerpo te espera. Tu guía también.

Canon de referencias (tono — no copiar estética, extraer el principio)

Santuario: Aēsop (minimalismo cálido, la tienda demuestra premium por lo que no hace), Loro Piana (calidad invisible, nada sobra), Ssense editorial (restraint + tensión entre lo comercial y lo editorial). Principio: lo que no está también comunica.

Inteligencia aterrizada: Linear (velocidad y precisión como estética), Arc Browser (la IA trabaja sin que la veas), Granola (invisible hasta que la necesitas), Apple Health (datos complejos → insight simple), Pitch (complejidad resuelta antes de que llegues). Principio: la complejidad está resuelta antes de que llegue la usuaria.

Anti-referencias

Por qué no
Vercel / Notion templatesSaaS genérico frío. Sin calidez, sin personalidad, sin cuerpo.
Apps médicas / clínicasLa estética clínica activa el miedo, no la confianza.
Headspace / CalmDemasiado blando, demasiado new-age. Paleta pastel + mindfulness genérico.
Lululemon / Nike WomenAthleisure comercial masivo. Demasiado “empowerment genérico”.

9. Tono de voz

Ver thefittclub-voice.md para la guía completa de estilo, ejemplos reales y vocabulario prohibido.

En resumen: cercana sin ser informal, técnica sin ser clínica, segura sin ser arrogante, sensual sin ser explícita, validante sin ser complaciente. Siempre en primera persona. Nunca dubitativa.

Copy de tecnología: “tu rutina se adapta a lo que hiciste ayer” — tecnología como servicio silencioso. Nunca “powered by AI”, “nuestro algoritmo”, “inteligencia artificial avanzada”.


10. Principios innegociables

Aplican a cualquier material de la marca: web, emails, redes sociales, producto, packaging, atención al cliente.

  1. Precisión antes que emoción. La emoción es el envoltorio, no el contenido.
  2. La usuaria es inteligente. Nunca se le habla con condescendencia.
  3. La marca no juzga. Sin culpa. Sin falsa motivación. Con realismo y calidez. Nota: «Sin falsa motivación» prohíbe lo fabricado y la culpa, no el refuerzo verdadero: reconocer progreso real, constancia y Días Activos con calidez es parte de la marca.
  4. La belleza es consecuencia de la salud estructural. La cintura, el abdomen, la seguridad — vienen como resultado, no como promesa.
  5. El lujo está en los detalles, no en la decoración. Lo superfluo no es lujo: es ruido.
  6. La fundadora es la ventaja competitiva. Una ingeniera civil que ha aplicado su mente estructural al cuerpo humano y lo ha vivido en carne propia.
  7. TheFittClub no es para todas. Y no intenta serlo.
  8. Siempre en la frontera. No sigue tendencias: las evalúa con criterio de ingeniería y adopta lo que funciona.

11. El camino: de fundadora a institución

En su fase actual, TheFittClub descansa sobre los hombros de Gala Calero. Eso ha sido una ventaja competitiva absoluta. Y también es una fragilidad estructural que hay que construir para superar.

Las marcas más valiosas del mundo empezaron siendo la extensión de una persona. Hoy son instituciones que respiran solas. No porque la fundadora desapareciera, sino porque su visión quedó tan profundamente codificada que otras personas pueden ejecutarla sin desviarla.

Fase actual: Gala es la voz, la metodología, la ingeniera, la cara visible. Todo pasa por ella.

Fase 2: Liberar a la fundadora. Personas asumen la operación diaria; Gala reserva su tiempo para lo que solo ella puede hacer: dirigir el criterio, diseñar la metodología, decidir hacia dónde va la marca.

Fase 3: Formar prescriptoras. Mujeres formadas en el método TheFittClub que puedan ser la voz de la marca sin que sea la historia personal de Gala, pero con el mismo rigor y la misma calidez.

Fase 4: TheFittClub como institución. La marca tendrá peso propio. Gala será la CEO, la visionaria, la guardiana de la esencia. La institución respirará sola.

La mujer que entra en TheFittClub no compra una suscripción: compra acceso a un universo que va a existir dentro de cinco, diez, veinte años. TheFittClub será el lugar al que su hija irá cuando sea madre.


Última actualización: 2026-05-15.


§3 — Design system & rúbrica de evaluación


description: Sistema de diseño visual, rúbrica de evaluación e implementación UI (tokens, tipografía, color) para TheFittClub. Complementa la identidad narrativa en thefittclub-brand.md.

Sistema de documentos del proyecto:

TheFittClub — Sistema de diseño visual (implementación)

Este documento acota cómo se ve la app en código: tokens, tipografía, convenciones de layout y la rúbrica de evaluación de pantallas. La intención emocional (santuario, inteligencia aterrizada) está definida en thefittclub-brand.md §8.

Stack

  • Tailwind CSS v4 — sin tailwind.config.ts; tokens en @theme dentro de la hoja global.
  • Fuente de verdad CSS: app/styles/app.css (@import "tailwindcss" + bloque @theme).

Tokens de color y superficie

Definidos en @theme en app/styles/app.css (nombres usables como utilidades Tailwind, p. ej. bg-primary, text-textBody):

  • Superficies: primary, surfaceMuted, surfaceSoft, surfaceMid, darkBg, darkCard
  • Texto: textMain, textBody, textSecondary, textMuted
  • Acento / marca: signature, signatureDeep, clubGold
  • Utilidad: success, danger, whatsapp, borderLight, borderDashed, banner

Los valores hex concretos viven solo en app/styles/app.css para evitar deriva entre doc y código.

Tipografía

En @theme:

  • Sans: DM Sans (--font-sans)
  • Serif: Cormorant Garamond (--font-serif)

Uso: combinación premium — serif para titulares / momentos editoriales donde encaje la marca; sans para UI y cuerpo.

Layout y producto

  • Variables CSS globales para navegación y dashboard: --app-navbar-height, --dashboard-sticky-stack-height, --dashboard-scroll-margin (ver comentarios en app/styles/app.css).
  • Utilidad .dashboard-section-anchor para scroll con márgenes correctos bajo cabeceras sticky.
  • Contrato de shell de producción (T70, 2026-07-28): una superficie del handoff es el documento entero en el prototipo, pero en producción vive dentro del shell global y puede cambiar de régimen de posicionamiento a mitad de flujo. De ahí que las unidades de viewport (vh) dejen de significar lo que parecen. Reglas + las cinco preguntas que debe contestar todo brief: design-handoff-production-shell.md. Léelo antes de aterrizar cualquier superficie nueva del handoff.
    • --app-navbar-height no mide la cabecera real. Dice 52px/64px; .appbar renderiza ~65px (padding 12px ×2 + control de 40px + hairline). Sirve para scroll-margin, NO para posicionar contra ella — usa flujo y deja que el layout mida.

Reglas para contribuciones UI

  1. No inventar colores fuera del @theme salvo transición documentada en este archivo y reflejada en app/styles/app.css.
  2. Mobile-first; la experiencia debe sentirse “app” coherente con la promesa de marca (ver brand §8).
  3. i18n: no hardcodear copy; criterio en .cursorrules (namespaces por página).

Rúbrica de evaluación de diseño — gate obligatorio

Cómo usar: Aplica los criterios 1–7 en orden. Si una pantalla falla cualquiera de los primeros 4, para ahí — los fallos tempranos no se arreglan con ajustes tardíos. El Criterio 8 se evalúa aparte y leyendo: lo aplica el juez de comprensión (tfc-comprehension-judge) en QA, no el revisor estético. Cuándo aplicar: Cualquier ticket que toque UI (componentes, rutas con vistas, tokens). Gate explícito en el harness de implementación y en QA.

Cada criterio tiene:

  • Pregunta de evaluación — la haces en 3–5 segundos, sin leer el contenido.
  • Pass — qué tiene que ocurrir para aprobarla.
  • Fail — señales de rechazo inmediato.
  • Matiz — si la respuesta es “más o menos”, qué pregunta adicional resuelve la duda.

Regla general: si dudas en cualquier criterio, es fail. La duda es la respuesta.

Criterio 1 — Jerarquía tipográfica en 3 segundos

Pregunta: Al mirar la pantalla 3 segundos sin leer, ¿sé inmediatamente qué es lo más importante?

Pass: Hay un elemento dominante claro. El ojo va ahí primero, siempre. Fail: Compiten dos o más elementos de peso similar. No sé dónde mirar. Matiz: Si el elemento dominante no es el que debería serlo según la función de la pantalla, la jerarquía está invertida — también es fail.

Criterio 2 — Presencia del CTA

Pregunta: ¿El botón principal tiene presencia sin gritar? ¿Compite con algo?

Pass: El CTA se encuentra sin buscarlo. Su peso es el adecuado para la acción que pide. Fail: El CTA desaparece entre el contenido. O bien es tan grande/brillante que aplasta la jerarquía. Matiz: Un CTA secundario visible es aceptable si está claramente subordinado al principal. Si los dos pesan igual, es fail.

Criterio 3 — Temperatura cromática

Pregunta: ¿La paleta coincide con santuario? ¿Hay algún tono frío que se cuele sin justificación?

Pass: La superficie es warm-neutral. Los colores de marca aparecen con propósito, no como relleno. Fail: Azules fríos genéricos, grises neutros sin temperatura, fondos blancos puros #FFFFFF como base de página. Matiz: Un tono frío puede estar justificado si sirve a un propósito funcional (ej: estado de error, información técnica). Si está ahí “porque queda bien”, es fail.

Criterio 4 — Densidad / respiración

Pregunta: ¿La pantalla respira o me ahoga?

Pass: Hay blanco rítmico — el espacio vacío está distribuido intencionalmente, no relleno. Fail: Cada píxel tiene contenido. No hay pausa visual. O el extremo contrario: tanto espacio que la pantalla parece vacía o no terminada. Matiz: Santuario no es minimalismo estéril — es espacio con propósito. Si el vacío se siente incómodo, añadir un elemento pequeño que ancle; si se siente cargado, eliminar algo.

Criterio 5 — Lectura emocional a 3 segundos

Pregunta: ¿Qué siente la usuaria al abrir esta pantalla?

Pass: Una respuesta clara y específica: calma, confianza, claridad, pertenencia. Fail: “No sé” o “parece una app normal”. Si no produce una respuesta emocional, la pantalla es genérica — falla. Matiz: La respuesta no tiene que ser positiva en todas las pantallas (ej: una pantalla de error puede sentirse como “esto está bajo control”). Pero tiene que ser algo.

Criterio 6 — Anti-vocabulario médico

Pregunta: ¿Hay alguna palabra del vocabulario prohibido?

Palabras prohibidas (lista completa): paciente, diagnóstico, tratamiento, terapia, cura, prescripción, protocolo clínico, rehabilitación médica, intervención, patología, síntoma, pronóstico, enfermedad, lesión (en contexto de diagnóstico), médicamente.

Pass: Cero palabras prohibidas. Fail: Una sola ocurrencia. Sin matices — fail directo. Acción: Reescribir con vocabulario wellness: entrenamiento, progresión, método, fase, activación, bienestar, recuperación física.

Criterio 7 — Anti-señales SaaS genéricas

Pregunta: ¿Podría esta pantalla ser de cualquier app de bienestar / fitness / SaaS?

Señales de rechazo automático:

  • Gradientes diagonales violeta-rosa-naranja.
  • Iconos Lucide / Heroicons en el hero o en posición prominente.
  • Cards con esquinas perfectamente redondeadas + sombra drop genérica.
  • Tipografía Inter o similar sin personalidad editorial.
  • Imagen de stock de mujer sonriendo con ropa de deporte.
  • Animaciones de entrada tipo “bounce” o “slide from left”.
  • “Powered by AI” badge, sparkle emoji como indicador de IA.

Pass: Podría ser solo de TheFittClub. Tiene al menos un elemento que solo este producto haría. Fail: Parece una plantilla de Vercel o una demo de Tailwind UI. Matiz: Un elemento genérico en un componente utilitario (ej: un input de formulario) es aceptable. Un elemento genérico en el hero o en el CTA principal es fail.

Criterio 8 — Éxito de tarea (T522)

Pregunta: ¿Puede decir qué tiene que hacer, sin leer nada más y sin calcular?

Pass: una sola respuesta, en sus palabras, sin restar dos números. Fail: la pantalla enseña el modelo (condiciones, vías, suelos) en vez del estado; o le exige aritmética; o la respuesta está a un clic. Matiz: se evalúa leyendo, al contrario que el Criterio 1. Son preguntas distintas y por eso son criterios distintos. Lo aplica tfc-comprehension-judge (cinco socias simuladas que solo ven la pantalla renderizada) en el paso de comprensión de QA; su recibo es la línea COMPREHENSION VERDICT: en el theater. El juez no sustituye investigación con usuarias reales (R-T522-5): mide si la frase se puede parsear y si algo en pantalla responde la pregunta, no lo que ella siente ni si seguiría pagando.

Calibración (ejemplos reales)

Añadir ejemplos de pass/fail a medida que aparecen. Empieza vacío.

  • Ejemplo pass (Criterio 5):
  • Ejemplo fail (Criterio 7):
  • Criterio que más se incumple en la práctica:
  • Criterio que quiero añadir:

Los tokens pueden evolucionar; ante duda, inspeccionar app/styles/app.css como fuente numérica.

Última actualización: 2026-05-15.


§4 — Product law


description: Lógica de negocio, reglas de producto y arquitectura técnica de TheFittClub. Fuente de verdad para cualquier implementación. globs: *

Sistema de documentos del proyecto:

Documentos técnicos complementarios:

🏆 TheFittClub V2: Master Business Logic & Requirements

This document is the Single Source of Truth for all functional requirements. Any technical implementation must satisfy these business tiers while adhering to the Edge-Native (Cloudflare/D1/RRv7) architecture.


🏗️ LAYER 1: PLATFORM GLOBAL RULES (The Ecosystem)

1. Product Matrix & Upselling

  • Free Combination: Users can own and mix Rituals, Modules, and Capsules. All must coexist in a unified Dashboard (“Mi Espacio”).
  • Dynamic Upselling: The Dashboard uses AI-detected tags (e.g., “lumbar pain”) to suggest specific Capsules or Modules (Ticket 5).
  • Access Control (Ticket 3): Access is strictly managed by user_purchases. Free products (Lead Magnets) bypass Stripe but are registered in D1.

2. Billing, Benefits & Guarantees (Ticket 3 & 9)

  • Club Discount: Active subscribers get a permanent 5% discount on one-off purchases (Modules/Capsules).
  • Refund Windows: 14 calendar days, every product, no exceptions. Rituals, Modules, Capsules and unredeemed gift vouchers alike. This is the Spanish statutory withdrawal right (arts. 102 ff. of RDL 1/2007), and it is what the published terms already promise a buyer — public/locales/{es,en}/legal.json § Derecho de desistimiento. Corrected 2026-08-09 (founder: “garantía 14 días, creí que ya estaba corregido”). This line used to read “Rituals (7 days), Modules (3 days), Capsules (0 days — No refunds)”, which was wrong on all three rows and contradicted the live sales page (ritual-core.json → pricing.guarantee, “14 días de desistimiento”). A published promise the internal SSOT disagrees with is the worse of two records, not a second opinion. The art. 103(m) waiver for immediately-accessible digital content is not available: the terms state it is valid only via an explicit checkbox at checkout, and that checkbox does not exist. Until it ships, 14 days applies without exception — do not shorten this line for Modules or Capsules on the theory that digital content is exempt.
  • Gifting (Ticket 9): Users can purchase products as gifts, generating a unique gift_vouchers code for third-party redemption.

3. Gamification & Global Stats (Ticket 8)

  • Global Streak: Any completion across any product adds to the “Días Activos” global counter and total minutes.
  • Isolation: Progress within a Ritual does NOT unlock phases in a Module. Each program track is independent in D1.
  • Async Processing: All gamification logic (streaks, badges) is handled via Cloudflare Queues to ensure <200ms response times.

🧩 LAYER 2: THE UNIVERSAL ADAPTIVE ENGINE (Building Blocks)

Every program is a “Playlist” of these relational blocks:

1. The Session Canvas (Ticket 2)

  • Canvas Order: Administrators define the sequence (e.g., PDF Intro → Audio → Routine → PDF Tips).
  • 3-Series Routine: Routines are split into Warmup, Main, and Cool-down blocks.
  • Playback State: Video/Audio progress is persisted in user_playback_state for cross-device continuity.

2. Progressive Intelligence (Ticket 2 & 7)

  • Effort rating (founder decision 2026-08-30): after each session she rates her effort from 1 to 10 (optional since T568). The rating moves a session’s level inside the progressive modality, and a level governs series and repetitions only — it never touches phase progression, which is the engine’s (domain-rituals.md §5). The level rows are not decided; T565 owns them and the wiring. The version matrix this line used to describe was never called by application code and is not the model.
  • AI Overrides: If an exercise is “Banned” in user_exercise_preferences, the loader automatically injects the alternative_exercise_id.

3. Personal Journal & AI Memory (Ticket 5)

  • Dual Storage: D1 stores the raw text/photo and the NLP-extracted tags (e.g., “high stress”, “diastasis”).
  • Async NLP: Analysis is performed via context.cloudflare.waitUntil to avoid UI latency.

📜 LAYER 3: PRODUCT-SPECIFIC MECHANICS

3.1 RITUALS (Continuous Transformation)

Ej: Ritual Core, Ritual Tao, Ritual Glúteos.

The method in the founder’s voice — what each phase is, how she advances, which words are hers — is _docs/02-content/ritual-core-metodo.md (T567). Read it before writing anything a member reads; this section is the law, that document is the promise.

  • Modalities: where a product offers more than one product_modalities row she chooses daily. Ritual Core’s three (express · base · progresiva) are defined in § 3.1.0 below and are not built; Ritual Core Legacy has one row and asks nothing.
  • Phase ascent (one engine, T429 / T547 / T552): every Ritual advances by banked weeks past both floors, then the level test where the phase has one. A week banks in proportion to her own minimum and her own days floor; the required weeks, the minimum and the floors are derived per woman from her onboarding answers through the product’s engine (products.progression_engine_id → progression_engines, engine_phase_bases, engine_rules, engine_rule_effects) — live, no clamp, tuned in Admin → Motores. This document states the shape, never the values (ADR-0020). The mechanism, statement by statement, is domain-rituals.md §5; read the live configuration with the four statements there. One of them, for the phases:
    SELECT pp.product_id, pp.sort_order, pp.prep_quarantine_days,
           (SELECT COUNT(*) FROM phase_evaluation_steps s WHERE s.phase_id = pp.id) AS evaluation_steps
    FROM product_phases pp ORDER BY pp.product_id, pp.sort_order;
  • Clinical Fail-Fast (Ticket 6): if the phase evaluation fails, the member is placed in «Modo Preparación» with a mandatory compensation exercise for prep_quarantine_days.
  • Loop Logic (Ticket 7): when a phase’s schedule reaches its end, the sequence loops back automatically using modular arithmetic while she banks the weeks the gate asks for.

3.1.0 What Ritual Core is going to be (product law — founder, 2026-08-30 — not built)

The forward product, prod_ritual_core, is the Legacy programme with a choice of three cuts of the same session each day, in her words:

  • ritual Core no es más que ritual Core Legacy, dando la opción de tener tres sesiones diferentes por día a elegir
  • express una versión muy reducida para la que quiera hacer algo ese día y no tiene tiempo
  • progresiva es la versión base que va progresando en intensidad con cada vez que se vuelva a repetir esa misma sesión
  • purpose: dar mi método con más flexibilidad y dependiendo de lo que cada una haga avanzará a un ritmo

Three rules a writer or an implementer could otherwise get wrong, stated as rules (R-T562-4 — they change only when the founder changes them here by name, with a date):

  1. base is the Legacy session unchanged. Ritual Core is not a second catalogue.
  2. express and progresiva are derivations of that session, never separate content. progresiva grows in intensity — series and repetitions — each time the same session is repeated (Layer 2 §2, T565); it does not change which session she does.
  3. Legacy completes first. una vez tengamos por Legacy perfectamente hecho, es cuando empezaré a trabajar las derivaciones para desarrollar ritual Core.

Verified against production (2026-08-30, re-read 2026-09-04): none of this exists yet. prod_ritual_core carries four modality rows (three seeded plus one created from the Back Office, T563), its phase 1 holds sixteen seeded sessions of generic catalogue exercises against Legacy’s real programme, and its three modalities hold different exercises rather than three cuts of one session. Scaffold, and this entry says so, so scaffold is not mistaken for design.

Before prod_ritual_core goes on sale (founder, 2026-08-30: es para el producto que aún no está en venta … esto debe de estar reflejado en algún lugar. Tendremos que implementarlo antes de su venta.):

#Must existTicket
1The progressive modality actually scales series and repetitions from the effort rating — today the player mounts every block at its stored loops and the scaling code has no callerT565
2The progress-photo lock the documentation promises, expressed against the single banked-weeks counter, enforced server-side, first photo never blockedT566

This list lives beside the product, not in a ticket that closes; add a row when a new pre-sale condition is decided, and strike a row when its ticket lands.

3.1.1 Ritual Core Legacy (T204)

A distinct product, not a tier of the new Ritual Core. Canonical id: prod_ritual_core_legacy (T65’s pm_rcl_standard reconciles to this single id).

  • What it is: the Legacy programme granted to the legacy cohort — one modality (pm_prod_ritual_core_legacy_standard), real content, and the same progression engine as Ritual Core (eng_ritual_core, verified in production 2026-08-30 / 09-01 / 09-04). What separates the two products is modalities and content, not progression. The forward prod_ritual_core (§ 3.1.0, not built) is the same programme with three cuts per day; legacy members do not receive it.
  • Who gets it (cohort law): only members who bought a “Core y Suelo Pélvico Poderosos – <edición>” edition and paid it in full (Σ of their transactions for that edition ≥ the edition’s program price). Abandoned-installment / partial payers are excluded. “Ritual Core Inicial” also grants access; the discontinued bare “Ritual Core” grants nothing.

    Corrected 2026-08-09 (founder: “Ritual Core Inicial murió y ya no existe, no se nombra”). The catalogue today holds exactly two: Ritual Core Legacy (sales never reopen) and Ritual Core (waiting list).

    What Ritual Core Inicial actually was, per the vault’s Capa-0 record (CONTEXTO_SESION_2026-05-17.md, slug membresia-ritual-core): the **≈5.0K lifetime revenue (14% of legacy). It is a retired product name: never in member-facing copy, a price table or a menu. The same vault entry records that confusing it with “Core y Suelo Pélvico Poderosos” (the €400-500 one-off, 86% of revenue) was one of the errors already corrected once — they are unrelated products.

    It is NOT deleted from this rule, and must not be. The line reads as naming a product because it is really an entitlement rule over historical Zenler purchase strings, and ritual-core-inicial is a member of ACCESS_GRANTING_MEMBERSHIPS in app/lib/domain/legacy-membership.ts. Retired as a name, load-bearing as a record.

    One stale label in that classifier, and it is cosmetic. The def still carries active: true, false since the 2026-11-20 closure. Its whole reach is presentational: admin.payments.tsx groups the membership filter into active/inactive, and admin.payments.$id.tsx appends a ”· inactive” suffix. It does not decide which rows appear, who is counted, or who gets access.

    What it does NOT do — recorded because an earlier draft of this section got it wrong (2026-08-09). That draft warned that ACCESS_GRANTING_MEMBERSHIPS containing ritual-core-inicial meant an expired ≈$8/month subscription would grant Ritual Core Legacy in the T386 wave. It does not, on two independent counts. isLegacyProduct (the only function that reads that set) has no production caller — the seed’s tests are all that reach it. And the actual Legacy entitlement runs through a different, much narrower predicate: LEGACY_PRODUCT_MEMBERSHIP is "core-suelo-pelvico" and nothing else, so the cheap membership is already excluded by construction. The founder’s correction was the right one: the Back Office holds the correct cohort, extracted by the scripts. Do not re-raise this as a migration risk without first re-reading both predicates.

  • Eligibility SSOT: the cohort classifier + the canonical per-edition price map (PRICE_PER_EDITION) live in app/lib/domain/legacy-membership.ts; the paid-in-full math is summariseFulfilment (payment-fulfilment.ts). The same price map backs the Back-Office paid-in-full badge (T203).

  • Content: real legacy content (clips/sessions) is T65. T204 defines the product shell + entitlement only.

3.2 MODULES (Targeted Recovery)

Ej: Cesárea (MVP), Diástasis, Postura, Caderas Libres.

  • Duration: 4-8 weeks (20-40 effective days).
  • Flow: On-demand progress. No blocking evaluations.
  • Active Components: Context, Techniques, Bitácora (Metrics), and Journal (AI).

3.3 CAPSULES (Rescue Pills)

Ej: SOS Lumbar, Despertar Pélvico (Free), Reto Hipopresivos 30D.

  • Duration: 1-21 days.
  • Flow: Direct consumption. Clinical metrics (Bitácora) and Journal are DISABLED to reduce friction.
  • Rewards: Contribute to Global Streak and grant a completion Badge.

🛠️ ARCHITECTURAL GUARDRAILS (The Architect’s Code)

  1. Loader-First: Data fetching belongs in RRv7 loaders. No client-side useEffect for initial data.
  2. D1 Relational Purity: No JSON arrays for core relations. Use junction tables and normalized rows (e.g. member_conditions keyed off physical_profiles, exercise_materials, phase schedule links).
  3. Compound Keys: Use composite primary keys where appropriate for idempotency (e.g. product_user_progress: user_id + product_id; onboarding: product_id + question_id).
  4. Edge runtime in Workers: Request handlers and loaders must stay Edge-safe: no Node-only fs / path / Node crypto in app code bound to Workers. Tooling (catalog sync, seeds, Drizzle kit) may use Node locally; keep those scripts out of Worker bundles (see drizzle/seeds/*).
  5. Spec-driven development: No implementation without an approved spec under _docs/03-tickets/02-active/ (then _docs/03-tickets/04-done/ when locked). _docs/03-tickets/03-qa/ is reserved for strict QA contracts when a spec explicitly requires them—not a prerequisite for every feature.

Catalog note (implementation detail)

Editorial content is relational in D1 (training_sessions and related tables). The legacy routines table for Ritual Core Phase 1 is still populated from TypeScript (app/lib/catalog/data/ritual-core/phase-1) until TD-007 is retired — this is handled automatically by npm run db:seed (Phase 2 of drizzle/seeds/run.ts). See thefittclub-private-catalog-data.md.


Architectural Decision Log:

  • [2026-04-04] V2 Pivot: Catalog moved from TS files to D1 Relational Schema.
  • [2026-04-04] Async Logic: Gamification moved to Cloudflare Queues; AI NLP moved to waitUntil.
  • [2026-04-24] Schema split: Drizzle definitions live under app/db/schema/ (domain modules + barrel index.ts).
  • [2026-04-26] Docs: Dual catalog pipeline documented — relational canvas + legacy routines TS sync (thefittclub-private-catalog-data.md).
  • [2026-04-26] Docs: Brand identity documentation system established — see thefittclub-brand.md and related files.

§5 — Strategy


description: Estrategia de lanzamiento, crecimiento y operaciones de TheFittClub. Define el roadmap, pricing, canales de adquisición, métricas y proyecciones financieras.

Sistema de documentos del proyecto:

THEFITTCLUB — PLAN ESTRATÉGICO v5.2

Lanzamiento: apertura única en diciembre 2026 o 2ª semana de enero 2027, después evergreen (Checkpoint 3 de 15_War_Games/Plan_Escenarios.md; corregido 2026-09-03 — la fecha de septiembre pasó a ser la oleada de migración de las legacy, no la apertura de ventas)

Versión con bilingüismo fundacional, YouTube como canal de siembra, Club de Embajadoras como motor de adquisición orgánica, timeline flexible, y cálculos de producción ajustados a 60 sesiones. v5.2 (Ago 2026): el plan se organiza como ecosistema circular de 4 arcos (mapa y orden de arranque en 15_War_Games/Ecosistema_Circular.md), con el auto-test como mecanismo central de captación y el email reclasificado como infraestructura permanente. Proyección base: escenario Moderado (8.200–30.800€ en 12 meses). Estrategias documentadas para alcanzar el rango alto. Última actualización: Septiembre 2026 (2026-09-03: trimestral 197€ · urgencia 147€ · anual 497€; análisis en 15_War_Games/Analisis_Precios.md §0).


0. POR QUÉ EXISTE ESTE PLAN

Este plan no es solo una hoja de ruta operativa. Es la traducción estratégica de una convicción: existe una mujer que el fitness tradicional ha abandonado. Es madre, tiene alrededor de 40 años, es culta, exigente, invierte en sentirse deseada. Ha probado de todo y nada le ha funcionado porque nada entendía su cuerpo postparto. No importa si habla español o inglés: su frustración es la misma.

TheFittClub existe para ser la autoridad silenciosa que la guía de vuelta a su cuerpo. Con precisión de ingeniería. Con la calidez de quien ha pasado por lo mismo. Con una experiencia de lujo que justifica cada euro que invierte. En dos idiomas. Desde el primer día.

Cada decisión de este plan —cada precio, cada email, cada funcionalidad que priorizamos o posponemos— debe responder a una sola pregunta: ¿esto hace que Laura —o Lauren— sienta que está en las mejores manos?


1. SITUACIÓN ACTUAL

Gala Calero. Ingeniera civil, programadora frontend, creadora de contenido. Actualmente cobra el paro tras ser despedida como frontend (la IA se llevó su puesto). Esto no es un obstáculo: es el runway que financia TheFittClub.

Runway: 1.057€/mes de paro hasta noviembre 2027. Intención: solicitar el pago único (capitalización) del paro restante — la solicitud debe hacerse antes del alta de autónoma; el orden solicitud → alta → lanzamiento es innegociable para no perder la capitalización. Esto da margen para hacer las cosas bien, sin prisas.

Clientas actuales: Solo hispanohablantes. Pero el relanzamiento será bilingüe (ES/EN) desde el día 1. App, web, redes sociales, emails, contenido — todo en dos idiomas. Esto no es una traducción: es una experiencia nativa para ambos mercados.

Contenido (estado real, corregido 2026-09-03): el contenido de Ritual Core Legacy se extrae de Zenler fase a fase con el pipeline de corte del repo (scripts/zenler/, ffmpeg + transcripciones Whisper; ticket T65). Fases 1, 2 y 3 están en producción desde agosto de 2026; queda la Fase 4 con sus transiciones y evaluaciones. El nuevo Ritual Core (Express / Base / Progressive) se deriva de ese material después. La estimación anterior de «60 sesiones × 1,75 h en DaVinci» queda superada: el dato medido es ~4 días de trabajo por fase extraída.

Voces autorizadas: Al menos 3 profesionales respetadas (matronas, fisioterapeutas, doulas) pueden amplificar el lanzamiento. Su impacto no es un multiplicador mágico de ventas, pero sí un refuerzo de credibilidad que mejora las tasas de apertura y conversión en la parte alta del funnel.

Principio rector: La calidad del contenido manda sobre el calendario. Las fechas (oleada de septiembre, apertura de diciembre-enero) son objetivos, no cárceles. Si una fase no está al estándar que la marca exige, se retrasa esa fase, no se rebaja.


2. RESUMEN EJECUTIVO

Modelo: Bootstrap 100% equity. Sin capital externo. Mercados: Hispanohablante + angloparlante desde el día 1. Objetivo año 1: 13.500€/mes en mes 6 (moderado) → 17.300€/mes en escenario alto. Objetivo año 3: 200.000€/mes. Revisable con datos reales en mes 12. Carga de trabajo: 20h/semana post-lanzamiento, compatible con maternidad.

Ventajas estructurales reales

  • Fases 1-3 de Ritual Core Legacy ya en producción; solo queda extraer la Fase 4 → el producto de la oleada existe hoy.
  • Pipeline de extracción medido (~4 días por fase) en vez de una estimación de edición.
  • Fundadora = desarrolladora = creadora de contenido = ingeniera civil → 0 dependencias externas.
  • 9.900 emails entregables (Zenler) + 202.397 seguidores Instagram.
  • Runway garantizado: paro 1.057€/mes.
  • Stack Cloudflare edge-native → costes de infraestructura < 20€/mes hasta miles de usuarias.
  • Bilingüismo nativo desde el día 1: duplica el mercado potencial sin duplicar el coste de producción.
  • 3 voces autorizadas para amplificar el lanzamiento.

3. PROYECCIONES FINANCIERAS

Los tres escenarios (sin ajustar por voces autorizadas)

HitoConservadorModerado (base)Plan original
Mes 15 clientas / 700€10 clientas / 1.400€20 clientas / 2.360€
Mes 324 clientas / 3.000€40 clientas / 5.100€48 clientas / 7.615€
Mes 663 clientas / 8.200€104 clientas / 13.500€109 clientas / 17.300€
Mes 9107 clientas / 13.800€176 clientas / 22.800€180 clientas / 28.500€
Mes 12142 clientas / 18.400€237 clientas / 30.800€265 clientas / 42.000€

Nota 2026-09-03: las filas de facturación de la tabla anterior se calcularon con el trimestral a 147€. Con el trimestral a 197€ (§7), la facturación por clienta trimestral sube un 34% para el mismo número de clientas. No se reescriben aquí: se recalculan con tasas reales en cada checkpoint (regla 4 de 15_War_Games/Plan_Escenarios.md).

Impacto estimado de las voces autorizadas (primera semana)

EtapaSin vocesCon 1-2 voces (impacto esperado)
Apertura email blast18 %20-22 %
Signup a Cápsula (sobre aperturas)8 %10-12 %
Completado Cápsula55 %55-65 %
Conversión a Ritual (sobre completado)5 %6-7 %
  • Moderado (sin voces): 10 ventas / ~1.470€ en semana 1 (10 × 147€ de urgencia; ~2.170€ si el 20% elige la anual).
  • Moderado (con 2 voces): 12-14 ventas / ~1.750-2.050€ en semana 1.

Nota: Las voces autorizadas mejoran la credibilidad del funnel, pero la conversión final depende de la calidad del producto. No son un multiplicador mágico, pero inclinan las probabilidades a tu favor.

Neto para Gala (moderado) con paro:

  • Mes 1-9: ingresos moderado + 1.057€ paro − 80€ autónoma − IVA (21%)
  • Mes 1 real neto: ~2.100€ | Mes 6 real neto: ~11.800€ | Mes 12 real neto: ~24.100€

4. STACK DE HERRAMIENTAS REAL

4.1 Desarrollo

HerramientaRolDetalle
Claude Code (remoto en claude.ai/code y local)Único entorno de desarrolloTrabaja los tickets con los harness de _docs/06-prompts/, las skills y los tres subagentes del repo; la fundadora revisa y fusiona cada PR (INV-1).
Gates deterministas (pre-commit, pre-push, CI)Calidad sin depender del modeloi18n, vocabulario de marca, idioma de registro, diseño, duplicación, seguridad; test-first obligatorio en cada fix:.
Claude (modelos según tarea)Implementación, copy, estrategiaopus por defecto; fable solo cuando el juicio es el entregable (copy, ley de producto, auditorías). Decisión 2026-09-03.
Claude (Anthropic)Diseño, copy, estrategiaTareas de alto nivel: revisar arquitectura, generar copy, diseñar componentes.

Contexto compartido: CLAUDE.md + AI_PROTOCOL.md en la raíz del repo, con las reglas modulares de _docs/00-rules/. Cada sesión los carga al iniciar. (Corregido 2026-09-03: CLINE.md, Cursor, Cline y DeepSeek ya no existen en el flujo.)

Flujo de trabajo por ticket:

  1. Idea → spec en 01-pending/ (harness 00-new-ticket.md).
  2. Activación → 02-active/ con contrato cerrado.
  3. Implementación: en un fix: el test de regresión lo escribe un subagente y se confirma en rojo antes del arreglo.
  4. Verificación en navegador con la app local sembrada antes de abrir el PR.
  5. QA: contrato de regresión + teatro ejecutado; rúbrica de diseño y juez de comprensión en superficies de socia.
  6. PR con CI y revisión de IA en verde; la fundadora fusiona (o el agente, si el diff es solo prosa).
  7. Cierre: spec bloqueado en 04-done/.

text

4.2 Producción de contenido

HerramientaRol
Pipeline de corte del repo (scripts/zenler/: Whisper + ffmpeg)Extrae los ejercicios de los vídeos de Zenler por marcas de tiempo, genera miniaturas y sube a R2. DaVinci Resolve queda solo para grabaciones nuevas (formación, YouTube).
Cámara Sony ZV-E10Grabaciones nuevas (guía en 40_Contenido_Redes/Guia_Grabacion_ZV-E10.md).
ObsidianCentro de operaciones: guiones, copy, plan de redes, fichas de ejercicios, métricas, brand book, documentación técnica.

Coste medido de extracción:

  • ~4 días de trabajo por fase extraída de Zenler (Fase 1, jul 2026); Fases 2 y 3 en producción en agosto.
  • A 15-20h/semana = 5-7 semanas de trabajo.

4.3 Email marketing

HerramientaRol
Resend + Back Office (broadcasts)Email transaccional y newsletters desde la propia app (decisión: sin Loops.so, ver _docs/01-core/resend-consolidation-analysis.md en el repo dev). Los envíos a socias y leads salen del panel de administración, con ledger de destinatarias y bajas.
Better Auth + ResendEmail transaccional (alta, verificación, recuperación) desde el día 1; el mismo Resend sirve los broadcasts del BO.

4.4 Soporte

HerramientaRol
Sistema de tickets simpleFormulario en la web con acuse de recibo automático: “Te responderemos en menos de 24 horas.”
FAQs anticipadas5-10 preguntas frecuentes publicadas en una página de ayuda.

5. ESTRATEGIA DE CONTENIDOS Y CANALES DE ADQUISICIÓN

5.0 El ecosistema circular (marco de todos los canales — Ago 2026)

Los canales de este capítulo no son piezas sueltas: forman un círculo de 4 arcos donde la salida alimenta la entrada. Mapa completo, KPIs por arco y orden de arranque en 15_War_Games/Ecosistema_Circular.md.

  1. Atracción (formato corto): Instagram (§5.2). Objetivo: viralidad y alcance amplio — impacto, imagen y más españolas en absoluto; una cuenta grande es en sí misma prueba social. El filtro de calificación no vive aquí.
  2. Educación (formato largo): YouTube (§5.3), SEO (§5.4) y el email como infraestructura (§5.6).
  3. Invitación — la cadena central de captación (ya en producción): auto-test → resultado personalizado por email → guía-bonus descargable → Cápsula Cero → ventana personal de urgencia 72h. El auto-test es el mecanismo de “levantar la mano”: la prospecta se autodiagnostica, recibe su resultado, y entra al funnel ya calificada y segmentada por mercado. Toda pieza de contenido de los arcos 1-2 apunta aquí (CTA permanente), no directamente a la página de venta.
  4. Retroalimentación: testimonios con permiso + Club de Embajadoras (§5.5). Los resultados reales se reintroducen como contenido de los arcos 1-2 — el efecto compuesto que un embudo no tiene.

Regla de arranque: el arco 4 se activa primero (la prueba social de la cohorte legacy ya existe: reviews de Facebook, grupo de WhatsApp). Publicar atracción sin retroalimentación capturada es gastar el mejor tráfico en la peor página de venta que vamos a tener.

5.1 Bilingüismo fundacional

Todo el contenido se publica en español e inglés desde el día 1. No es una capa de traducción añadida después: es una experiencia nativa para ambos mercados.

  • App: i18n completa (namespaces es y en). La usuaria elige idioma al registrarse.
  • Web: Todas las páginas estáticas (landing, blog, FAQs, términos) en ES y EN.
  • Emails: Secuencias desde el Back Office (Resend) en ambos idiomas según el perfil de la usuaria.
  • Redes sociales: Cuentas separadas o contenido bilingüe integrado (a decidir según la plataforma).

5.2 Instagram (reactivación mínimo 3 meses antes del lanzamiento)

Frecuencia progresiva:

PeríodoPosts/semana
Semanas 1-22
Semanas 3-43
Semanas 5-84
Semanas 9-12 (pre-lanzamiento)5

Proporciones de contenido:

Tipo%ObjetivoTono
Gancho estético40%Guardados/viralidadVisual, dewy, piel luminosa, luz lateral
Explicación técnica30%AutoridadPreciso, sin condescendencia, seguridad de ingeniera
Detrás de cámaras20%ConexiónCercano pero no informal, mostrando el estándar de exigencia
Testimonial10%Prueba socialMujeres reales, sin poses forzadas

5.3 YouTube — Canal de siembra a largo plazo

Inicio: Julio 2026 (o antes, si hay tiempo).

Frecuencia: 1 vídeo cada 2 semanas.

Formato: Vídeos de 8-15 minutos con el mismo grado de color y estilo visual que las sesiones del Ritual.

Tipos de contenido:

  • Explicaciones técnicas: “Por qué los crunches empeoran tu diástasis”, “Qué es el transverso abdominal”.
  • Detrás de cámaras: “Cómo se graba un Ritual Core”, “El laboratorio de TheFittClub”.
  • Testimonios y casos reales: Con permiso, mostrando progreso real.
  • Contenido bilingüe: Subtítulos en español e inglés, o vídeos alternos en cada idioma.

5.4 SEO + Blog

Publicación de 5-10 artículos evergreen desde julio 2026. Palabras clave: “recuperar abdomen postparto”, “ejercicios suelo pélvico”, “diástasis ejercicios prohibidos”, “postpartum core recovery”.

5.5 Club de Embajadoras — El motor de boca a boca

El Club de Embajadoras es el sistema de afiliadas automático que convierte a cada clienta en una prescriptora potencial.

AcciónDescuento amigaPuntos para la embajadora
Amiga compra Ritual Semestral10% (-35€)100 pts
Amiga compra Ritual Anual10% (-50€)300 pts
Amiga compra Módulo10% (-10€)50 pts
Amiga compra Cápsula10% (-5€)25 pts

100 puntos = 10€ descuento en renovación. Máximo 50% descuento vía puntos. Expiran a 12 meses.

5.6 Email — infraestructura del círculo (no táctica de lanzamiento)

El email deja de ser “3-4 emails de calentamiento antes del blast” y pasa a ser infraestructura permanente del arco de educación: no depende del algoritmo, cuesta 0€ y la lista ya es nuestra.

  • Cadencia de arranque: newsletter mensual. Sostenible con las horas reales disponibles; sube a quincenal solo tras 3 envíos consecutivos cumplidos sin robar horas a producción.
  • Primer envío: reencuentro honesto (“por qué desaparecí y qué he construido”), sin venta.
  • Prerequisito: importar los contactos de Zenler al Back Office (audiencia leads, con etiqueta de origen y segmento; corregido 2026-09-03: el stack es Resend + broadcasts del BO, no Loops.so) — la palanca de mejor ratio esfuerzo/impacto del plan (15_War_Games/Ruta_Beneficios.md §4).
  • El calentamiento pre-blast (3-4 emails en 3-4 semanas, por tramos crecientes) sigue existiendo como evento aparte, con su protocolo en 15_War_Games/Lanzamiento_Ritual.md Pasos 1-2.

6. ROADMAP FLEXIBLE

Fase 1: Desarrollo y edición (Abril – hasta que esté listo)

Desarrollo (MVP):

  • Auth, player de vídeo, checkout Stripe + página personalizada, oferta urgencia 72h, bitácora básica, dashboard con datos reales, onboarding.
  • App bilingüe completa (ES/EN).
  • Sistema de tickets con auto-respuesta y FAQs.

Contenido (T65):

  • Extraer la Fase 4 de Zenler + transiciones y evaluaciones entre fases (F1-F3 ya en producción).
  • Tiempo estimado: ~4 días por fase (medido), más las transiciones.
  • Herramienta: el pipeline de corte del repo (scripts/zenler/).

Fase 1.5: Cosecha de retroalimentación (Ago 2026 — antes de reactivar canales)

El arco 4 del círculo arranca primero porque su materia prima ya existe y es gratis:

  • Reviews de Facebook → fichas de testimonio en el vault, con nivel de permiso registrado.
  • Formulario de testimonios a la cohorte legacy (permiso en 3 niveles: nombre completo / pila / anónimo).
  • Mensaje al grupo de WhatsApp legacy: pedir en grupo, recoger en privado (datos de salud, art. 9 RGPD). Sin mencionar la migración — testimonio, aviso de migración e invitación a la app son 3 conversaciones separadas en el tiempo.
  • Import Zenler → Back Office (leads) con tags (prerequisito del §5.6) + archivo de datos T300.

Fase 2: Reactivación de audiencia (mínimo 3 meses antes del lanzamiento)

  • Instagram: Reactivación progresiva (2-5 posts/semana), con el pilar testimonial ya alimentado por la Fase 1.5.
  • YouTube: 1 vídeo cada 2 semanas.
  • Email: newsletter mensual desde ya (§5.6); el calentamiento pre-blast (3-4 emails) se ejecuta en las 3-4 semanas previas al lanzamiento.
  • SEO: 5-10 artículos evergreen en el blog.

Fase 3: Beta testing (3-4 semanas antes del lanzamiento)

  • La beta ES es la cohorte legacy migrada usando el producto real (decisión jul 2026, ver 15_War_Games/Migracion_Legacy.md); el lado angloparlante sigue sin fuente (15_War_Games/Ledger.md).
  • Métricas: > 75% completan Cápsula Cero, > 60% llegan a Fase 1, NPS > 8.5.
  • IMPORTANTE: Sin estar de alta como autónoma.

Fase 4: Lanzamiento

  • Solicitud del pago único del paro (antes del alta — orden innegociable) y alta autónoma (epígrafe 631.2).
  • Email blast + post Instagram simultáneo (ES y EN).
  • Activar las secuencias del Back Office (Resend) en ambos idiomas.

Fase 5: Primera contratación (2027, condicionada)

Decisión de Gala, 2026-09-03: cogería una desarrolladora que me ayude cuando comience a facturar algo, para tratar de crecer. Se activa solo con tres meses seguidos de facturación real por encima del umbral del Checkpoint 4 de 15_War_Games/Plan_Escenarios.md, que también fija el perfil (quien revisa y fusiona lo que producen los harness, despliegues y soporte técnico) y la alternativa que hay que contestar antes: si el dinero da para una persona, ¿la hora de Gala vale más revisando código o grabando y contestando? Hasta entonces, la ventaja estructural de «0 dependencias externas» (§2) sigue vigente.


7. PRICING Y OFERTA URGENCIA

Estructura de precios

ProductoPrecioModeloDisponibilidad
Cápsula Cero0€Lead magnetDía 1
Ritual Semestral347€Suscripción recurrente (6 meses)Día 1
Ritual Semestral urgencia≈260€ (-25%)Una vez por usuaria, 72h, nunca como precio de lista; redondeo final al fijar el checkoutDías 4-7
Ritual Anual «Fundadora»497€Suscripción anual, precio congelado mientras renueveDía 1
Cápsula corta47€Pago únicoMes 3
Cápsula extendida67€Pago únicoMes 6
Módulo focalizado97€Pago únicoMes 9

Decisión 2026-09-04 (Gala): estructura semestral 347€ + anual «Fundadora» 497€; el trimestral 197€ del 03-09 queda sustituido. El precio sube por cohortes con resultado medido, no por funcionalidades. Detalle en Analisis_Precios §0 bis.

Principio de pricing

Los precios actuales están calibrados para maximizar la entrada de clientas en el primer año sin devaluar la marca.

Trimestral a 197€ (decisión 2026-09-03): el programa dura 15-28 semanas según el motor del auto-test, así que la clienta típica de la trimestral paga dos trimestres y sale. A 147€ eso eran 294€ por mujer, por debajo de los $318-520 que la mejor cohorte legacy pagó por el mismo contenido: el modelo recurrente cobraba menos por mujer que el histórico. A 197€, dos trimestres son 394€ (en línea con el ticket histórico), tres trimestres son 591€ y la anual de 497€ pasa a ser la elección obvia (con 147€ equivalía a 3,4 trimestres y no anclaba nada). El antiguo precio de lista (147€) se convierte en la oferta de 72h: misma psicología de cierre, 29€ más por venta. Matemática completa en 15_War_Games/Analisis_Precios.md §0.

Precio único global (decisión Ago 2026): el mismo precio en EUR para todos los mercados. Sin PPP ni tier LATAM — el pricing regional invita al arbitraje vía VPN y el producto vale su precio. LATAM aporta alcance y prueba social al arco de atracción; el mercado comprador objetivo es España + anglo, y toda tasa de conversión se mide segmentada por mercado para no contaminar las decisiones. Sin suscripción mensual: 197€/trimestre ≈ 66€/mes efectivos — una mensual más barata y sin compromiso canibalizaría la trimestral y el mix anual Fundadora, y repetiría la forma del experimento fallido de la membresía (análisis en 15_War_Games/Analisis_Precios.md y decisión 3 de 15_War_Games/Ecosistema_Circular.md). El fraccionado 3×69€ existe solo como contramedida oculta, nunca en el menú.

Anual «Fundadora» desde el día 1 (decisión Jul 2026): adelanta caja, elimina 12 meses de riesgo de churn en ese segmento y replica la psicología de pago único de la cohorte legacy (que a ticket ~500€ completaba el programa y refería) — sin reintroducir el acceso vitalicio, que queda prohibido en todo producto futuro (ingreso único + coste de infraestructura perpetuo es deficitario por diseño). Análisis completo en war_games/analisis_precios.md. Para alcanzar los 200.000€/mes en año 3, la clave no está en subir el precio del Ritual, sino en construir las otras patas del negocio: Módulos/Cápsulas (aumentan el LTV) y Tech Beauty + Prescriptoras (nuevas líneas de ingresos de alto margen).

Matemática neta por venta

ConceptoTrimestral 197€Urgencia 147€Anual 497€
Precio197€147€497€
Stripe comisión (3%)-5,91€-4,41€-14,91€
Neto por venta191,09€142,59€482,09€
IVA a declarar (21% incluido)~34€~26€~86€
Neto real post-IVA~157€~117€~396€

8. ESTRATEGIAS PARA ALCANZAR EL RANGO ALTO

  1. Calentar la lista antes del blast.
  2. Urgencia real, no artificial.
  3. Completado de Cápsula como métrica crítica.
  4. Retención trimestral: email de renovación en día 85-87, con datos reales de progreso.
  5. Upsell Cápsula Corta (mes 3).
  6. Sembrar el ecosistema futuro desde la comunicación.
  7. Doble mercado desde el día 1: El bilingüismo duplica el mercado potencial sin duplicar el coste de producción.
  8. Voces autorizadas como amplificadores de credibilidad: 3 profesionales respetadas pueden mejorar las tasas de apertura y conversión en la parte alta del funnel.

9. MÉTRICAS Y SISTEMA DE CONTROL

Dashboard semanal (en Obsidian)

Semana [N] Producción Sesiones editadas: [X] / 60

Tests técnicos superados: [X]

Canales Instagram: engagement rate [X]%

YouTube: suscriptores [X], views/mes [X]

Email: open rate [X]%

¿En qué escenario estoy? Completado Cápsula beta: [X]%

text

KPIs post-lanzamiento

MétricaConservadorModeradoAlto
Signup Cápsula / semana< 2040-60> 80
Completado Cápsula< 40%55-65%> 70%
Conversión Cápsula → Ritual< 3%5-6%> 7%
Retención primer trimestre< 60%68-72%> 75%

10. VISIÓN AÑO 2-3

Tres vectores de crecimiento hacia los 200.000€/mes:

  1. Tech Beauty: Primer dispositivo físico con parámetros preconfigurados por Gala.
  2. Expansión angloparlante: El mercado US/UK ya está sembrado desde el día 1 con YouTube y contenido bilingüe.
  3. Prescriptoras formadas: Mujeres certificadas en el método que ofrezcan sesiones bajo la marca TheFittClub.

Formación Pro (añadido 2026-09-03, decisión de Gala): el vector 3 deja de ser una visión de año 3 y se convierte en una línea de negocio con fecha, formatos y precios de hipótesis — cohorte en vivo online (~990€), presencial intensivo con kit impreso (~1.490-1.690€), grabado (~390-590€) y supervisión mensual (~79€/mes) — que escala por peldaños hasta formadoras licenciadas y el flujo B2B2C hacia la app. Lista de espera «Nivel Pro» en el lanzamiento; primera cohorte en 2027 tras el alta de autónoma. Wargame completo: 15_War_Games/Formacion_Pro.md.


11. CHECKLIST PRE-LANZAMIENTO

Técnico

  • Checkout Stripe + página personalizada.
  • App bilingüe completa (ES/EN).
  • Player de vídeo con firma R2.
  • Dashboard reflecte la atmósfera de marca.
  • Secuencias de email del Back Office (Resend) en ambos idiomas.
  • FAQs y sistema de tickets.
  • CLAUDE.md y AI_PROTOCOL.md en la raíz del repo (hecho).

Contenido

  • Fase 4 + transiciones y evaluaciones extraídas y sembradas en producción (T65).
  • Testimonials beta (mínimo 5) con permiso firmado, en ambos idiomas.

Canales

  • Instagram reactivado con ≥ 3 meses de contenido.
  • YouTube con ≥ 3 vídeos publicados.
  • Blog con ≥ 5 artículos evergreen en ES y EN.
  • Lista de email calentada con ≥ 3 emails de valor.

Legal/Fiscal

  • Pago único del paro solicitado (antes del alta).
  • Alta autónoma, epígrafe 631.2.
  • Términos y condiciones + política de privacidad + disclaimer médico (ES y EN) — vivos en el repo dev (legal.json, ruta /legal/*): aviso legal v2.0, privacidad v2.1, términos v2.0, cookies v2.0, aviso de salud v1.0. No redactar de cero: se versionan allí.
  • RGPD — aplica y está trabajado: DPIA firmada, RAT (art. 30), retención, cascada de borrado, respuesta a brechas y checklist AEPD de lanzamiento en _docs/01-core/compliance/ (repo dev). Pendientes vivos: los del checklist AEPD (auditoría 2026-07-25).

12. REGLAS DE DECISIÓN (NO NEGOCIABLES)

  1. Calidad sobre calendario. Si el contenido no está listo, se retrasa el lanzamiento.
  2. Bilingüismo fundacional. Todo se publica en ES y EN desde el día 1.
  3. Stripe antes que cualquier feature premium.
  4. Calentar la lista antes del blast.
  5. Completado de Cápsula es la métrica más importante.
  6. El Club de Embajadoras es el motor de adquisición orgánica.
  7. No añadir herramientas que no reduzcan tiempo de producción de Gala.
  8. El churn se gestiona en el email de la semana 8-10.
  9. Cada punto de contacto debe reflejar la identidad de marca.
  10. La marca no juzga ni presiona.
  11. TheFittClub no es para todas.
  12. Un entorno, harness y gates como estándar de calidad. Claude Code trabaja los tickets con el pipeline del repo; los tests y los gates deciden, y la fundadora revisa y fusiona cada PR.

Versión 5.2 — Agosto 2026. El plan se organiza como ecosistema circular de 4 arcos (§5.0, mapa en 15_War_Games/Ecosistema_Circular.md): auto-test como cadena central de captación, email como infraestructura permanente (newsletter mensual, §5.6), Fase 1.5 de cosecha de retroalimentación antes de reactivar canales, y precio único global sin tier LATAM ni mensual. Base v5.1 — Abril 2026: cálculos de edición ajustados a 60 sesiones (105h, 5-7 semanas), voces autorizadas recalibradas, bilingüismo fundacional, YouTube como siembra, Club de Embajadoras como motor orgánico, timeline flexible.


§7 — Active tickets (full specs)

565-fix-progressive-modality-never-scales-series-or-reps.md

565 — fix: the progressive modality never adds — or holds back — series and repetitions

Status: Active Stage folder: 02-active Mode: MODE 2 (activated 2026-09-12 — implemented on the F1 integration branch) Branch: codex/f1-legacy-integration PR: https://github.com/gala1234/thefittclub/pull/1702 Domain: player Track: mvp Effort: M Hito: Beta Launch Model: opus Blocking: no

Brief

La fundadora, 2026-08-30: si la sesión la evalúa como exigente … no se le añaden series ni repeticiones. Esa lógica está escrita y correcta en progressive-overload.ts, y no la llama nadie. La pantalla se lo promete igualmente. Solo afecta a prod_ritual_core.

Goal

Decide the six-level progression table with the founder, then make the progressive modality actually serve it — so the level the player already shows her, and the sentence it already prints, become true.

Problem

Ritual Core is not on sale yet, and this must be fixed before it is — but after Legacy is finished, not before (see ## Blockers). Its progressive modality is the product’s core promise and it currently does nothing.

What progresiva is meant to be (founder, 2026-08-30): la versión base que va progresando en intensidad con cada vez que se vuelva a repetir esa misma sesión — the Legacy session itself, weighing more on each repeat. express is una versión muy reducida para la que quiera hacer algo ese día y no tiene tiempo. The purpose of the three cuts is dar mi método con más flexibilidad y dependiendo de lo que cada una haga avanzará a un ritmo. So this ticket scales one session’s own exercises, never a separate catalogue.

The founder’s rule, in her words (2026-08-30):

si la sesión la evalúa como exigente no significa no subirla de fase, significa que si está usando sesión pero agresiva porque está en ritual Core y ha usado la progresiva no se le añaden series ni repeticiones

So the rule is per-session volume inside the progressive modality — series and repetitions — and it does not touch phase progression at all.

Two dead implementations exist, and the six-level one is the design the founder remembers. Neither has a production caller.

app/services/sessionCanvas.server.ts holds PROGRESSION_MATRIX: six levels, each a series multiplier and a repetition multiplier, plus a scaleWarmup flag — and resolveProgressionLevel, which advances a level per completion and holds the level when the last effort rating was ≥ 9. That hold is the founder’s rule (no se le añaden series ni repeticiones) expressed over levels; an earlier draft of this spec wrongly called it a rejected model, from a misreading of her correction, which was about phase vs level and not about the six levels.

app/lib/progressive-overload.ts holds a different, coarser model: four mastery tiers (1 / 2 / 3 / 3 series with ×1.0 / ×1.0 / ×1.2 / ×1.5 repetitions), moved by the effort rating (≥ 8 drops a tier, ≤ 4 raises one). It is not six levels and it cannot express the founder’s worked example.

The data is already configured for the six-level model. Queried read-only against production 2026-08-30: pm_prod_ritual_core_progressive is the only modality in the entire database with scale_on_progression = 1, set on its main blocks (and two warmup rows), with base_loops = 2 and repetitions of 6-10. That matches the founder’s memory of the entry point exactly — la primera … seis repeticiones y dos series.

But the current matrix does not produce her target, and this is the analysis this ticket must do before any code. Her worked example (2026-08-30, offered as illustration, not as a decision — esto todavía hay que analizarlo bien a ver cómo lo vamos a construir):

LevelFounder’s examplePROGRESSION_MATRIX today, on the real config
12 series × 6 reps2 × 6 (loopMult 1, amountMult 1.0) — matches
63-4 series × 15 reps6 series × 10.8 reps (loopMult 3 on base_loops 2, amountMult 1.8)

The gap is semantic, not arithmetic: loopMult multiplies the configured series rather than setting them, so level 6 doubles her intended series and falls short on repetitions. Read as absolute series with a larger repetition multiplier, the same six-row table produces 3 × 15 — her example — from the same configuration. Which reading is right, and what the six rows should hold, is a founder decision this ticket must surface before implementing.

Two further questions the analysis owns: how many completions reach level 6 (today Math.min(6, completions + 1), so six sessions — the founder: no sé cuántas veces tiene que hacer la misma sesión para llegar al sexto nivel), and whether the warm-up scales (scaleWarmup is true from level 3 in the matrix, and two warmup rows carry scale_on_progression = 1 in production).

Blast radius, verified against production D1 2026-08-30:

ProductModalitiesProgressive?Members
prod_ritual_core_legacy1 (standard)No (is_progressive = 0)64
prod_ritual_core4Yes1

So no migrated member is affected today — founder: en ritual Core Legacy … no afecta en nada. Es solo para la categoría progresiva. This is a defect in the product that has not launched, which is why it is a pre-sale requirement rather than an incident.

Premise validation

Validated 2026-08-30 at HEAD d14a80c: read app/lib/progressive-overload.ts, app/services/player.server.ts, app/components/player/PlayerIntroTheory.tsx, public/locales/es/player.json, .knip.allowlist.json; grepped both function names repo-wide (test files only). Modality flags and member counts queried read-only against production D1 (thefittclub-db).

Amendment — 2026-09-12, activated and implemented (what the F1 decisions changed about the plan)

Activated folded into the implementation: the table this ticket was waiting for was decided on 2026-09-11 (F1-DEC-ESCALERA / F1-DEC-CADENCIA) and the sessions it derives from finished with the F1 hand-off, so the two blockers in ## Blockers / dependencies are both cleared. Five things about the plan changed, and none of them is a smaller scope:

  1. The ladder is authored content, not a multiplier. The founder’s table is series counts on three chosen exercises — 1/1/1 → 2/2/1 → 2/2/2 → 3/3/2 → 3/3/3 → 4/3/3 — with the dose per series, the warm-up, the cool-down and the breathing work untouched. There is no factor that produces step N from step 1, so the six steps are six authored block sets tagged with session_blocks.progression_level (migration 0092) and the player serves the step she is on. Both dead implementations stay dead: sessionCanvas.server.ts::PROGRESSION_MATRIX (the ×1.3/×1.5/ ×1.8 repetition multipliers) would contradict la dosis por serie se conserva, and progressive-overload.ts is a different model again. This ticket does not wake either.
  2. The cadence is hers, and it is not one-per-completion. F1-DEC-CADENCIA-2026-09-11 (Sí, valorar tras dos ejecuciones): the next step is offered after TWO executions of the same step with a reported effort below Exigente. A demanding session or an unanswered question holds the dose. app/lib/domain/ritual-core/progression-ladder.ts is the whole rule, and the player, the card and the session-end write all read it.
  3. The hard threshold is 7, not 9. The player’s own scale calls 7-8 Exigente and 9-10 Al límite (player.json), and her rule is about a session that resulta exigente — so the hold starts where the screen says it starts (F1-DOC-RPE-ETIQUETAS-2026-09-11).
  4. Scope covers BOTH products. ## Brief says Solo afecta a prod_ritual_core; the founder asked on 2026-09-12 for the same F1 content in Ritual Core Legacy, so Progresiva now exists on the 61 positioned Legacy members’ product too, on its own rows.
  5. R-565-4’s parenthesis is out of date. Legacy’s full session is no longer standard: its product-modality row moved to the global mod_base (0092), so the modes are Base / Express / Progresiva in both products. What R-565-4 protects still holds — a non-progressive mode serves exactly the rows it was authored with, unscaled — and is pinned by tests/unit/seeds/ritual-core-f1-modes.test.ts.

R-565-3 (scale_on_progression = false is never scaled) is satisfied trivially and for a different reason than the spec expected: nothing is scaled at all any more, so the flag decides nothing. It stays in the schema; a test asserting it would be asserting the absence of a mechanism.

Evidence for each contract line, and the preview receipts, are in the PR body.

Regression contract (pre-drafted — binding once this reaches 03-qa/)

  • R-565-1 In the progressive modality, a session whose last effort rating meets the decided “hard” threshold serves no more series and no more repetitions than the previous run — the founder’s rule, stated as the observable outcome rather than as a level.
  • R-565-2 The level the player displays and the volume it serves come from the same computation; they cannot disagree.
  • R-565-5 Level 1 serves exactly the configured block values, and level 6 serves the table the founder decided — pinned as a fixture so a later edit to the table is a visible test change, never a silent one.
  • R-565-3 A block with scale_on_progression = false is never scaled.
  • R-565-4 Non-progressive modalities (express, base, and Legacy’s standard) serve exactly base_loops and unscaled repetitions — pinned so this fix cannot leak into the migrated cohort.

Executable contract (T813)

Run by run-spec-contract.mjs when this spec moves to 03-qa/. R-565-3 has no line: nothing is scaled any more, so a test for it would assert the absence of a mechanism (see the amendment).

# R-565-1, R-565-2, R-565-5: the ladder rule (two runs below Exigente, threshold 7) and its six authored steps
npx vitest run tests/unit/domain/ritual-core/progression-ladder.test.ts
npx vitest run tests/unit/services/dashboard.ladder-trust-boundary.regression.test.ts
# R-565-4: a non-progressive mode serves the rows it was authored with, unscaled
npx vitest run tests/unit/seeds/ritual-core-f1-modes.test.ts
# Amendment 1: the multiplier model stays dead; nothing outside its own file reads PROGRESSION_MATRIX
! git grep -q "PROGRESSION_MATRIX" -- app/ ":(exclude)app/services/sessionCanvas.server.ts"

Progression study (2026-08-30) — the input the analysis needs

The founder’s framing, which separates two progressions this spec had conflated. Her words: ya en cada fase se va progresando dando ejercicios que van poco a poco subiendo de nivel. Pero la idea es que como las sesiones se repiten, que puedan ir aumentando la intensidad en la parte progresiva de la sesión, la que lo elija.

So the phase progresses by changing the exercises, editorially; the progressive modality raises the intensity of the same session as she repeats it. The exercise is fixed within a level ladder. Any proposal that swaps the exercise at the top of the ladder is out — that is the phase’s job and would collide with the calendar.

What the catalogue actually contains (production, read-only): 30 exercise rows across five families and three incompatible units — reps, breaths, and a per_side flag. Hipopresivos (5 posture variants), breathing work (fire breathing at 30 breaths, a Wim Hof wave at 18), motor control (bird dog / dead bug and their easier variants), isometrics (side plank appears twice, once in reps and once in breaths), and hip/global work.

Why a single multiplier cannot serve them, computed by applying PROGRESSION_MATRIX level 6 to the real block configuration:

ExerciseLevel 1Level 6
Fire breathing2 × 30 breaths324 breaths
Dead bug2 × 10108 reps
Side plank isometric2 × 10 breaths108 per side

What the literature supports, by family (summaries and author conclusions; full texts not read — Cochrane and PubMed returned access walls):

  • Motor control — progress by adding repetitions of brief holds, never by lengthening the hold; descending pyramid 6/4/2 up to 12/10/8, then a harder variant. McGill’s core stability work; broad professional consensus rather than meta-analysis.
  • Hipopresivos — the 8-week RCT (Molina-Torres, Neurourology and Urodynamics, 2023) progressed by posture (standing → seated → quadruped → supine), 2×/week × 20 min, and did not add sets or reps. But the 2023-2024 systematic reviews report “insufficient methodological quality”, “high risk of bias” and “no consensus on real effectiveness” — so progress conservatively, and route any outcome claim through the compliance skill before it reaches copy.
  • Pelvic floor — Cochrane 2024 (Hay-Smith) finds “few trials and very low- or low-certainty evidence” for choosing exercise dose, while “training more days per week may be better than fewer days per week”. This supports the existing product law (days floor + weekly minutes) and argues against inventing a precise dose ladder here.
  • Postpartum / diastasis — meta-analyses support structured exercise for reducing inter-recti distance, but the scoping review states there is “no consensus on the most effective exercise routine”.

breaths means two different things, and only one of them should scale (founder, 2026-08-30): la plancha medida en respiraciones es para que ellas logren mantenerse con activación en la inhalación. Para lograr ese control motor. So on the isometric side plank the breath is the load, not a clock — and it targets the harder half of the cycle: on inhalation the diaphragm descends, intra-abdominal pressure rises and the pelvic floor lengthens, which is exactly when activation is lost. Counting breaths counts how many times she holds it against that descent, which a stopwatch cannot distinguish.

Use of breathsExamplesScales?
The breathing is the exerciseFire breathing (30), Wim Hof wave (18)No by volume — 324 breaths is not a progression
The breathing is the loadSide plank isometric (10 per side)Yes — more cycles = more times holding activation

The tension with the motor-control literature is declared rather than smoothed: adding breaths lengthens the hold, and McGill argues against lengthening holds — but his objection is to long holds for endurance, whereas this trains coordination under respiratory load. At 10 breaths (~30-40 s) it is still a brief hold. Progress in cycles with a modest ceiling; do not open the duration. The underlying physiology (diaphragm–pelvic floor cylinder, phase coordination) is well established; the progression built on it is clinical-practice consensus, not a controlled trial.

The levers that remain once the exercise is fixed: repetitions (bounded, the main one), series (capped at the founder’s 3-4, never multiplied), rest between exercises — which already exists per exercise (0-30 s, mostly 20) and raises demand without adding volume, making it the natural lever for isometrics and breathing — and fixed, for the families that should not scale at all.

One check that did not confirm the founder’s premise, recorded rather than smoothed over: the phase-1 calendar does not show an easy → hard ordering by day. The gentler variants (bird dog con solo extensión, dead bug con pies apoyados) sit on days 3 and 4, after the full versions on day 1; they are distributed across session archetypes rather than ordered by difficulty. The ramp she describes may be across phases, and phases 2-4 of prod_ritual_core have no content yet. Worth her eye at activation.

Full study, with the per-family evidence and the arithmetic: the Progresión del core profundo page produced with this ticket.

Scope

In scope

  • First, the analysis — no code before it. Agree the six rows with the founder against her worked example: absolute series vs multiplier, the repetition figures, and whether the warm-up scales. Record the decided table in the spec; per ADR-0020 the values themselves then belong in the Back Office, not in a code constant. The literature review that feeds this decision was done 2026-08-30 — see ## Progression study below.
  • Then wire the decided table into the live player path for progressive modalities, using the completion count and last effort rating the loader already resolves.
  • Select and honour scale_on_progression per block.
  • Reconcile the displayed version with the served volume (R-565-2), or remove the number if it cannot be made to mean anything.
  • Test-first, per the repo’s bug-fix discipline: the RED test lands before the fix on the same branch, written by tfc-regression-test-writer.

Out of scope

  • Deleting sessionCanvas.server.ts wholesale. Its PROGRESSION_MATRIX and resolveProgressionLevel are the six-level design and are likely the thing to keep; what to do with the rest of that unwired module (getSessionPayload and its DAL) is a separate decision, still expiring 2026-11-17 in .knip.allowlist.json.
  • Phase progression, the level test, integration time. The founder’s correction is explicit that this rule does not touch them.
  • The banner — moved to T568. Hoy avanzamos a la versión progresiva renders from the effort rating alone, with no modality test, so it is false in Legacy as well as here. T568 silences it now, independently of this ticket and of T65; this ticket may switch it back on once the served volume actually differs, and R-568-1 forbids restoring the rating-only condition.

Blockers / dependencies

founder restated the sequence: no está diseñado el contenido de ritual Core, únicamente está el del ritual Core Legacy y además no está todavía completo. The progressive modality is a derivation of the base session, so it cannot scale anything until the session it derives from exists and is finished. An earlier revision of this spec treated the seeded scaffold as the content this ticket would operate on; it is not.

  • Blocks Ritual Core going on sale, but sits behind Legacy, not in front of it.

Open questions

  • Where is “must ship before Ritual Core goes on sale” recorded so it cannot be forgotten? Recommendation, and T562’s job since it owns that file: a short pre-sale list in _docs/01-core/thefittclub-product.md § 3.1 naming this ticket and T566.
  • What are the six rows? The founder’s example implies absolute series (3 at level 6) and roughly ×2.5 repetitions; the matrix today reads them as multipliers and yields 6 × 10.8. Her example was explicitly illustrative — this is the decision the analysis must produce.
  • How many completions reach level 6? — ANSWERED from the schedule, 2026-08-30. Math.min(6, completions + 1) reaches level 6 on the 6th completion of that session, and the phase-1 calendar delivers exactly that: 21 days served by 16 distinct sessions, each scheduled 3 or 6 times per lap (5 sessions at 6, 11 at 3). So the constant is not arbitrary — it matches the content. What remains for the founder is whether it is acceptable that a member tops out some sessions in 21 days and others only in 42, since the loop restart is what carries the 3-per-lap sessions to six.
  • Does the warm-up scale? The matrix says yes from level 3; production carries scale_on_progression = 1 on two warmup rows and 0 on the other eight.

Affected areas (for activation pass)

  • DB tables: read-only — session_blocks.scale_on_progression, session_progress.rpe, product_user_progress.progressive_versions
  • Services (app/services/): player.server.ts
  • Routes (tripartite): ($lang).player.$slug.*
  • i18n namespaces: player (only if the fix changes what is true)
  • Domain logic (app/lib/domain/): none — the pure logic is app/lib/progressive-overload.ts

613-legacy-technique-cards-production-per-phase.md

613 — Technique cards for Ritual Core Legacy: 27 candidates decided per phase, produced per family

Status: Active Stage folder: 02-active Mode: MODE 2 Branch: codex/613-f1-approved-techniques PR: https://github.com/gala1234/thefittclub/pull/1693 (single integrated F1 PR; #1688 superseded, branch kept) Started: 2026-09-11T20:40:53Z Domain: content-migration Track: content-migration Effort: L Hito: Beta Model: mixed Blocking: no

Branch override (T124 precedent). The founder’s integration authorization of 2026-09-11 mandates isolated branches per tranche; codex/613-f1-approved-techniques carries the number inside its first 28 characters (T685). Effort L means the activation is not fold-eligible; because she authorised activation and implementation of this tranche in one instruction, the activation commit is the first commit of the branch and the single PR carries both — her review of that PR is the activation checkpoint.

Brief

T606 D10: 27 técnicas candidatas y solo 3 fichas (las de F1). La hoja D10 fija fase, día y origen; este ticket produce las fichas por familia y las cablea al desbloqueo. El 2026-09-11 aprobó cinco nuevas de F1 y pidió integrarlas ya, con las tres originales tal cual.

Goal

As a member advances through the four phases, the technique cards unlock on the first session where the founder actually teaches each technique — one card every two or three days, never all on day one — and each card is her explanation, rendered ES and EN.

What “done” looks like — observable, not argued

Tranche 1 (F1, approved 2026-09-11):

  1. SELECT count(*) FROM product_techniques WHERE product_id = 'prod_ritual_core_legacy' on prod → 8 (the three original cards + five new), and SELECT count(*) FROM session_techniques WHERE session_id LIKE 'ts_rc_p1_legacy_%' → 8, on the sessions D10 decided: s01 (toning, chill pose, the lift), s03 (hypopressives, 360°, three breaths), s04 (cobra), s07 (fire).
  2. npm run media:publish-f1-techniques -- --verify → 26 files (5 × ES/EN × 1080/720 videos, 5 library covers, 1 program image) hash to the manifest; npm run db:diagnose-media-parity -- --env=prod finds every key.
  3. In the library, the five new cards render their approved 16:11 covers; opening one in the viewer plays the ES or EN video without cropping her at the edges on a phone.
  4. products.image_key for prod_ritual_core_legacy is the approved program image; the public homepage hero and the session thumbnails are unchanged.
# Items 1 and 2 read prod and R2, item 3 is the screen: checked by hand at QA (the runner reaches no database, bucket or browser).
# The seed carries the eight F1 cards on the sessions D10 decided
npx vitest run tests/unit/seeds/613-f1-techniques.test.ts
# A card unlocks on the session that teaches it, per mode; only an entitled member gets its media
npx vitest run tests/unit/services/techniques.mode-aware-unlock.test.ts tests/unit/services/media-access.technique-entitlement.test.ts
npx vitest run tests/component-dom/TechniqueViewer.test.tsx

Still open when this tranche lands (the ticket does NOT close): the three remakes (Tonificación v5, Hipopresivos v12, Fuego v3 — approved as ES 720p review renders; their EN/1080 derivatives are draft in t613-entrega-final/v1/delivery.json), the seven further F1 cards the founder is producing, F2–F4, and the fifteen-card covers.

Problem

The technique mechanism exists (F1 precedent: three cards, T65) but the library stopped at three. The backlog (scripts/zenler/tecnicas-biblioteca-backlog.md) holds 27 candidates mined from her transcripts — where she EXPLAINS, not where she counts — with phases decided for 11 (decoaptación → F1, dinámicos → F2, core + elemento → F2, isométricos → F3, torsión → F3, respiración 360 → F1, 3 tipos de respiración → F1, chill pose → F1, cobra → F1, …) and six new F4 candidates (breathing pattern for strength, the weak-leg rule, costal breathing to go faster, exhalation through the whole movement, ball massage, strong-and-flexible). Zero cards produced. The audit’s D10 table per phase lists each candidate with its evidence passage; the D10 sheet collects her verdict per row (hallazgos.json F*-D10-*).

Premise validation

  • Validated 2026-09-04 against prod (product_techniques = 3 rows, session_techniques for legacy = 3) and the backlog file at vault HEAD.
  • 2026-09-11 (activation, re-checked against the deliveries and the code):
    • Five deliveries carry a founder approval quoted verbatim in T613-EDITORIAL-INDEX.md and ASSETS_MANIFEST.json (Lo tenemos !, perfecto, vamos a por otra ficha, Esta perfecta, la tenemos, Apruebo, me encanta!!!, perfecto, vamos a por otra, se ingeniosa); their 20 MP4s hash-match verification.json. The library covers are approved in t613-portadas-lote-1/v2/receipt.json (lo veo bien), whose scope excludes the portrait player posters and the PNG sources.
    • Copy. Each card’s text is the approved piece’s own on-screen copy (each version’s .jsx, itself sourced from her clips), not new prose; a caution appears only where the piece says one (R-T612-1).
    • One image was serving two consumers. The library tile (16:11) and the portrait viewer (9:16) both read thumbnailKey; a 16:11 cover behind a 9:16 frame with object-fit: cover crops her face and hands — the receipt’s own note for chill pose, cobra and the lift. Portrait posters are not approved, so the honest consumer split is: library = the approved cover; viewer = the video’s own first frame (no poster) — in the player lesson and the library review modal alike. And the frame itself letterboxes (object-fit: contain) instead of cropping when the viewport is not 9:16.
    • products.image_key cannot be seeded. catalog-content-seed.sql (the prod→preview snapshot) upserts the product row from production on every reseed, so a seed literal would be reverted; the approved program image reaches the database through migration 0089, guarded (image_key IS NULL) so a later Back Office choice is never overwritten.
    • Both unlock routes examined. unlockSessionLinkedTechniques (gamification queue, explicit user_technique_unlocks) and the implicit derivation from session_progress in listTechniqueLibraryForUser / getLatestUnlockedTechnique both key on the completed session id. Today Ritual Core Legacy has one modality (standard), so a completion is the whole session and the D10 first-encounter link is exact. The moment an Express cut of a Legacy session exists (T565 family), both routes must consider what the modality actually included — recorded as R-T613-3 below so the contract outlives this tranche; no modality-aware unlock is built here because no such modality is served.
    • The three original cards: ids, videos, thumbnails and sessions untouched. The user explicitly chose to use them as they are; the remakes’ approval covers ES 720p review renders only.

Scope

In scope

  • The five approved cards as category: technique exercises (exercises-core-f1-techniques.ts), their product_techniques rows, and session_techniques on the D10 first-encounter sessions.
  • The asset manifest (drizzle/seeds/catalog/technique-assets-f1.ts) and the verify-and-publish path (scripts/media/publish-f1-technique-assets.ts, npm run media:publish-f1-techniques).
  • The consumer split (library cover vs viewer first frame) and the viewer letterbox.
  • Migration 0089 for the program image.
  • Durations for the ten new 1080p keys in exercise-video-durations.json.

Out of scope

  • The remakes and the seven cards in production (later tranches, same manifest shape).
  • A per-modality unlock rule (no Express modality is served for Legacy today; R-T613-3 records the obligation).
  • Serving the 800×550 small covers (recorded by hash; no consumer today).
  • A new UI for techniques (the Library already unlocks them).

Blockers / dependencies

  • none (input: her D10 verdicts)
  • T606, T610 (glossary), T614 (re-cuts of F1-F3), T567 (the method document names the techniques), T625 (phase PDFs, same session shelf), T565 (modalities; the unlock-by-content obligation).

Decisions

  • 2026-09-04 — hers: tu explicacion de porque wimhof funciona en isometricos es brutal, hay que mostrarla en el seed y documentos → the Wim Hof card (#7) carries it (see the pending-era text in git history for the physiology); the hypopressive card (#5) presents the technique as a tool of posture, breathing and decoaptation, not the method’s core.
  • 2026-09-04 — D10 audited by the agent against the complete transcripts and approved by the founder (cuando acabes con D10, apruebalo): all 27 rows carry an approved unlock phase + first-encounter day in verdicts/D10_F{1..4}.json.
  • 2026-09-04 — hers, looking at the Library with the three F1 cards unlocked: veo bien todas las tecnicas seleccionadas y su desbloqueo la primera vez que se apliquen, las tecnicas las montamos usando ia.
  • 2026-09-04 — hers: technique videos are phase material the member keeps at hand as they unlock — ver como los colocamos en la fase para que los tenga a mano.
  • 2026-08-15 (hers) — cada técnica se desbloquea en la fase donde la alumna la encuentra POR PRIMERA VEZ.
  • 2026-08-17 — unlock spacing ~1 every 2-3 days (backlog Objetivo dopamina).
  • 2026-09-05 — from the delegated D6 audit: the three F1 technique cards carry copy that is not hers — rewrites landed with T612.
  • 2026-09-11 — hers (relayed by the editorial owner, INTEGRACION-F1-ALCANCE-AUTORIZADO.md): integrate the five approved new techniques now with the three originals as the current usable versions; do not wait for the remakes or the seven missing cards; never report a complete fifteen. Library covers lo veo bien; player-poster crops explicitly not approved.
  • 2026-09-11 — activation (agent): the five new ids are ex_core_f1_tech_{respiracion_360,tres_respiraciones,chill_pose,cobra,ascensor}; keys phase1/techniques/<slug>-<locale>.mp4 (+-720p sibling) and public/phase1/techniques/<slug>-library.jpg; first-encounter sessions from D10_F1.json; sort_order = order of appearance in the session with the original card first.

Open questions

  • When and how often a card unlocks — unchanged from the pending spec (decided 2026-09-04: (a) + (b): a card is presented before the first session that teaches it and kept afterwards; the gaps are filled with extras that are not techniques). The extras calendar proposal stays in git history of the pending spec; nothing here changes the mechanism.
  • The three remakes: which exact files are approved for integration once EN/1080 derivatives exist — read t613-entrega-final/v1/delivery.json at that moment; today only the ES 720p review renders are approved.

Acceptance criteria

  1. Verdict coverage 27/27 (D10_F*.json) — met 2026-09-04.
  2. Produced cards wired and unlocking (query above); one member-facing check per phase on the Library — tranche 1 covers the five F1 cards.
  3. No unapproved poster or draft render is referenced by any key the seed writes.

QA status (2026-09-12, tranche 1)

The QA harness ran on the candidate: spec-conformance pass, every checkbox, the design rubric (pass on the final files) and the comprehension judge — receipts in tests/qa-theaters/ticket-613-legacy-technique-cards-production-per-phase-theater.md. The comprehension judge returned fail (5/5 personas, worst shared blocker 3 readers) on two sentences that pre-date this ticket and sit outside its diff: the facet badge Técnicas 3/10 (computed over every owned product in LibrarySurface.tsx while the shelf counts the selected one) and the library intro Es tuyo mientras sigas en el club. (library.json). The five cards’ own names and descriptions produced no blocking quote. Per 03-qa-ticket.md the harness stops here and the founder decides: accept with a documented reason (and a ticket for the badge scope + the intro sentence) or rework. The spec stays in 02-active/ — the receipt gate refuses a 03-qa/ spec without a passing comprehension verdict. Since 2026-09-12 this tranche ships in the single integrated F1 PR (branch codex/f1-legacy-integration), which supersedes #1688 without deleting its branch.

Pre-QA gate notes (AI review, PR #1688)

  • Round 1 (review 5183451185, head 30caa9c): 0 [BLOCKER]; 1 design [CONCERN] (object-fit: contain on the shared .tv-frame) answered as intended and recorded (R-T613-4: .tv-frame has one consumer, TechniqueViewer, mounted by the player lesson and the library sheet; all technique videos are 1080×1920; scoping the rule would restore the crop on the originals); 3 [NIT] accepted — TFC_ASSETS_ROOT for the assets path, the test docstring reworded to the R-T612-2 negative guard, the e2e affordances addressed by role. No security concern.
  • Round 2 (review 5183824961, head 1240c55): every hunk reviewed belongs to T699, brought in by the main merge 85e87cde3; 0 findings on T613 code. Its T699 [CONCERN] (post-Sunday accumulator re-derived in FaseActualCard) is recorded on #1686.
  • Accepted deferrals: none that touch this contract. Non-blocking hygiene noted by the design reviewer: PlayerTechniqueLesson.tsx:34 still forwards posterUrl={technique.posterUrl}, which resolves to undefined on this branch (libraryFromSession emits no posterUrl); pinned by the e2e assertion that the viewer’s <video> carries no poster.

Regression contract

Strict, non-optional. Any future change touching the same area must respect every invariant below.

Scope under contract

  • Eight technique cards for prod_ritual_core_legacy (three originals untouched + five approved), each linked to the session scheduled on its approved D10 day, unlocking by completed session through both routes.
  • Every media key a card points at is an approved delivery by sha256: ES/EN 1080p + 720p sibling, the 16:11 library cover; no draft, remake derivative or portrait poster.
  • The portrait viewer letterboxes and carries no landscape poster; the library tile shows the cover.
  • A card’s bytes are entitled by ownership of a product that registers the card.

Out of contract

  • The remakes and the further F1 cards (later tranches, same manifest shape), a per-modality unlock rule (R-T613-3 records the obligation for the T565 family), the 800×550 small covers, a new UI for techniques.

Schema / DB invariants

  • product_techniques for prod_ritual_core_legacy = 8 rows; session_techniques on ts_rc_p1_legacy_s01 (toning, chill pose, the lift), s03 (hypopressives, 360°, three breaths), s04 (cobra), s07 (fire) with unique per-session sort_order and the original card first.
  • exercise_video_durations carries the ten new 1080p keys; legacy-session-duration-cache equals the computed minutes — after the founder’s twelve F1 coverage corrections landed in the integrated PR (2026-09-12: clipCoversBothSides: true on stretch_s1_02/03/04, stretch_s2_03/04/05, stretch_s3_02, tone_cT1_05, tone_cT2_02/03, tone_cT4_02 and tone_cT3_05 — eight per side, alternating, one clip), s01 35, s03 27, s04 34, s08 29 (1693 s), s18 29 (1729 s); migrations 0090 (minutes) and 0091 (flags) move production, the source of the snapshot every seeded environment replays.
  • products.image_key for the legacy product is set by migration 0089 only when NULL; the seed never writes it.

HTTP behavior

  • GET /media/phase1/techniques/<slug>-<locale>.mp4 as an owner → 200/206 video/mp4; refunded, other-product or anonymous → 403.
  • GET /media/public/phase1/techniques/<slug>-library.jpg → 200 image/jpeg.

UI behavior

  • Library › Ritual Core Legacy › Técnicas: 8 tiles; after day 1 exactly Tonificación, Chill pose and El ascensor unlocked; Cobra locked with its unlock line; EN names on /en/.
  • Opening an unlocked card shows the review sheet (dialog) with the cover; Reproducir mounts the viewer (dialog) on that locale’s 1080p video, no poster attribute, object-fit: contain.

Equivalence table

ScenarioInputExpected HTTPExpected DB state
Owner plays Chill pose (ES)GET /media/phase1/techniques/chill-pose-es.mp4206 video/mp4unchanged (no unlock, no minutes)
Owner with day 1 completed opens the library/es/panel/biblioteca2003 unlocked / 5 locked derived from session_progress + session_techniques
Refunded member plays any cardsame key403unchanged
Reseed twicenpm run verify:local ×2n/a8 product_techniques, 8 session_techniques, no duplicates

Known limitations / deferred

  • Express/Base/Progresiva modalities for Legacy do not exist yet; R-T613-3 binds the modality tranche.

  • R-T613-1..6 below are the named invariants each test pins.

  • R-T613-1 — A technique unlocks on the first session of the phase where she first teaches it, never earlier. Testable: tests/unit/seeds/613-f1-techniques.test.ts pins each new card to the session scheduled on its approved D10 day.

  • R-T613-2 — Every media key a technique card points at is an approved delivery, identified by sha256. Testable: the manifest test (26 distinct hashes, versions from the approved folders, no poster/draft path) and publish-f1-technique-assets.ts --verify where the deliverables exist.

  • R-T613-3 — An unlock reflects what the member actually performed. Both unlock routes (queue + implicit session_progress) key on the completed session; while Legacy serves a single modality this is exact. Any modality that serves a subset of a session’s exercises (Express) must not unlock a technique that subset does not include merely by the parent session id — the T565-family change that adds such a modality owns the test.

  • R-T613-4 — Two consumers, two images. The library tile reads the 16:11 cover; the portrait viewer (player lesson and library review modal) renders no landscape cover as its poster and letterboxes the video (object-fit: contain) rather than cropping it.

  • R-T613-5 — The three original cards keep their identities and media until an approved remake replaces them explicitly.

  • R-T613-6 — A technique card’s bytes are entitled by product ownership, not by block membership. A member with a completed purchase of a product that registers the card (product_techniques) streams its video in either language; a refunded member, a member of another product and a stranger are refused. Testable: tests/unit/services/media-access.technique-entitlement.test.ts (RED against the pre-T613 gate: the owner got 403 on Chill pose) and tests/e2e/library/613-f1-techniques.spec.ts (the local rung fetches the ES and EN videos through /media/).

GEO baseline

Not applicable — every surface this ticket touches is private (library and player behind entitlement).

Affected areas (hardened at activation 2026-09-11)

  • DB tables: exercises + exercise_translations (5 new technique rows per locale, via the exercises seed), product_techniques (+5), session_techniques (+5), products.image_key for prod_ritual_core_legacy (migration drizzle/migrations/0089_t613_legacy_program_image.sql, guarded, rollback inside).
  • Seeds: drizzle/seeds/catalog/exercises-core-f1-techniques.ts (the five cards), drizzle/seeds/catalog/technique-assets-f1.ts (manifest), drizzle/seeds/catalog/products/ritual/ritual-core-legacy-sql.ts (first-encounter links with per-session sort_order), drizzle/seeds/catalog/exercise-video-durations.json (+10 keys).
  • Services (app/services/): player.server.ts — resolveTechniques no longer passes the library cover as the viewer poster. media-access.server.ts — exerciseInPurchasedContent also entitles an exercise registered to a purchased product in product_techniques (R-T613-6; found by the local rung, not by review). No signature change.
  • Components / styles: app/components/library/TechniqueReviewModal.tsx — no poster prop; app/styles/app.css — .tv-frame object-fit: contain. The design-review and comprehension receipts apply at QA because component/CSS files changed.
  • Routes (tripartite): none.
  • i18n namespaces: none — card copy is catalog data (exercise_translations), not UI copy.
  • Domain logic (app/lib/domain/): none.
  • Scripts / tooling: scripts/media/publish-f1-technique-assets.ts, package.json media:publish-f1-techniques.
  • Tests: tests/unit/seeds/613-f1-techniques.test.ts, tests/unit/services/media-access.technique-entitlement.test.ts, tests/e2e/library/613-f1-techniques.spec.ts (full tier); the existing ritual-core-legacy-sql, 612-legacy-copy-her-words-only, seed-applies-to-migrated-schema and legacy-session-duration-cache suites must stay green.
  • Assets checkout: read-only; manifests untouched.

Receipts — tranche 1 (2026-09-11, branch codex/613-f1-approved-techniques, PR #1688)

Every line below is a tool result from the implementing session; nothing is inferred.

CheckResult
tests/unit/seeds/613-f1-techniques.test.ts9/9 — originals preserved by id + video key + session; exactly five new cards; 26 distinct sha256 (5 × ES/EN × 1080/720 + 5 covers × 2 sizes + program image); seed keys = manifest keys; 720p sibling shape; durations map (+10); D10 first-encounter sessions (chill pose + the lift → day 1 / s01; 360° + three breaths → day 3 / s03; cobra → day 4 / s04) with unique per-session sort_order and the original card first; copy rules (R-T612-1); program image by migration, not seed.
tests/unit/services/media-access.technique-entitlement.test.tsRED against the pre-T613 gate (owner refused, 403) → GREEN after exerciseInPurchasedContent learned product_techniques (R-T613-6).
npx vitest run tests/unit/services128 files / 1245 tests green; the seeds suites (ritual-core-legacy-sql, 612-legacy-copy-her-words-only, seed-applies-to-migrated-schema, legacy-session-duration-cache with the updated 45/27/44 minutes) green.
npm run media:publish-f1-techniques -- --verify / --put=local26/26 files hash + size match the manifest; 26 objects placed in the local miniflare buckets for the rung.
npm run preflight:smoke:local with tests/e2e/library/613-f1-techniques.spec.ts tagged @smoke for the run (tag removed before commit)5/5 on wrangler pages dev (:8788), 1280×800: viarapida (day 1 completed) sees 8 tiles / 3 unlocked / Cobra locked; Chill pose tile background = /media/public/phase1/techniques/chill-pose-library.jpg → 200 image/jpeg; modal → play → video.tv-frame src /media/phase1/techniques/chill-pose-es.mp4, no poster, Range GET → 206 video/mp4, duration > 70 s; EN member: English names, ascensor-en.mp4 streamed. First run of the same spec was the RED that surfaced R-T613-6.
npm run typecheckexit 0.
pre-commit chain (both commits) · pre-push (i18n schema, language of record, architecture intent, route i18n handle, design drift, knip, eslint)PASS, no --no-verify. One pre-push failure on the way (six expect(value, message) calls rejected by vitest/valid-expect) fixed and folded into the implementation commit before it left the machine.
CI on PR #1688, implementation head f0ed2f9a6 (an earlier receipt named 4a097f401, the pre-amend hash that never left the machine — corrected here)all checks green: Language + frontmatter + board, Typecheck, Build (local rung), Test (vitest unit + component + dom), Gates (full-repo lints + migrations + supply chain), Audit (design + layout + endpoints + a11y), Mutation (WARN-only, no survivor reported as blocking), Cloudflare Pages, PR preview smoke E2E, Lighthouse.

Where the material is right now: source files on the branch; objects in the local buckets only (thefittclub-media-dev, prefix local/); seeded DB local only (verify:local); the experience above verified on the local rung. Preview and production carry nothing from this tranche until the founder runs the checkpoints in the PR body (db:migrate:prod → content reseed → media:publish-f1-techniques -- --put=prod → db:diagnose-media-parity -- --env=prod).


Tranche 2 (2026-09-13, branch fix/735-f1-test-rows-out-and-the-three-remade-cards, PR #1727)

Folded into this ticket at the founder’s word — metelo en T613, lo importante es que prod ya tenga todo — rather than opening a number of its own. Two things landed in one run, because they share their proof: production media parity going from two failures to zero.

The three remakes are released

Tranche 1 wrote that the three original cards stay as they are «until an explicitly approved remake arrives», because the approved remake files were ES 720p review renders only. That arrived: founder, on the draft status their EN/1080 renders still carried in t613-entrega-final/v1/delivery.json — Debían haber estado aprobadas, están todas bien.

F1_TECHNIQUE_REMAKES in drizzle/seeds/catalog/technique-assets-f1.ts carries tonificación v5, hipopresivos v12 and fuego v3 — ES/EN at both rungs, every file by sha256 + size. Deliberately NOT in F1_TECHNIQUE_ASSETS: a remake re-cuts a card that exists, so it adds no exercise row, no D10 wiring and no 16:11 library tile. Durations moved with the cut (51 → 70, 54 → 72, 61 → 64) in exercise-video-durations.json and, in production, by scripts/db/one-off/t613-remade-technique-durations.sql — the content snapshot replays those rows after the seed (T340), so a seed literal would be reverted.

Two traps this tranche paid for, both about picking a file:

  • The ES 720p delivery.json records is not the 1080p’s sibling. It names the REVIEW render from the vN/ folder — the copy the founder watched — and that file is a different encode: tonificación’s runs 69.0 s at 30 fps against the delivery’s 69.5 s at 60 fps. Publishing it would have served one cut on a good connection and another on a thin one. Every 720p here comes from the same vN-delivery/ folder as its 1080p, verified identical in duration and frame rate (R-T613-8).
  • v12-delivery/ holds two files that both say “delivery”. hipopresivos-es-v12-1080p.mp4 (16.3 MB, 71.6 s) is the cut; hipopresivos-es-v12-delivery-1080p.mp4 (4.6 MB, 70.0 s) is an earlier calibrated pass. The name is the trap; the length and the bitrate are the tell.

Covers. Tranche 1 left these three on the per-locale 9:16 poster they shipped with. The founder found all three stale in the Library the same day — la imagen de Hipopresivos no se ha actualizado, then las imagenes de Breath of Fire y Toning (4-phase breathing) tampoco son las nuevas. Hipopresivos’ was the worst: a different woman in a different room, and in small caps TÉCNICA FUNDAMENTAL · ≈ 3 MIN over a piece that now runs 1:12. Offered the v12’s own opening frame, the design team’s draft cover, or a separate ticket, she chose the cover — La portada de agua y mármol — and each card’s two poster keys now carry that card’s own delivery still. The keys and the D1 rows do not move; only the bytes behind them. The 16:11 library-tile convention the five new cards use is still not what these three wire.

The two parity failures were not missing assets

RowWhat it actually wasReferenced object
sess_ritual_core_day_1duration_minutes 0, zero scheduled days, zero progress; its three items point at W3Schools’ Big Buck Bunny sample and a mov_bbb.pdf that is not a PDFpublic/session/505f1593-…/Core F1 — Tone base A.png
tech_rc_breathslug test, category magic, title «Test» in both locales, an Unsplash thumbnailthe derived -720p.mp4 of private/exercise/tech_rc_breath/livestyle_landscape.MP4

The founder had asked for the day-1 thumbnail to be taken from the assets and uploaded. There is no such file. S3 ListObjectsV2 on 2026-09-13 returned the whole public/session/ prefix EMPTY in thefittclub-media-public, thefittclub-media-private and thefittclub-media-dev (both preview/ and local/): the row records a Back Office upload that never landed. Shown that, and that the second row is her own «Test» exercise, she chose to delete both — scripts/db/one-off/t613-f1-test-fixtures-cleanup.sql, each DELETE carrying its own NOT EXISTS precondition, with the seed snapshot sanitised in the same change so no reseed resurrects them (the T65 lesson, where the snapshot re-created 42 dummies on every reseed until #1491).

Regression contract — tranche 2

  • R-T613-8 — a remake’s 720p approvedSource comes from the same vN-delivery/ folder as its 1080p, and both report the same durationSeconds. Pinned by tests/unit/seeds/613-f1-techniques.test.ts › every remake file is the delivery render, and its 720p is the 1080p’s true sibling.
  • R-T613-9 — a remake carries no libraryKey, and a replaced cover lands on the card’s own public/phase1/techniques/<slug>-{es,en}.jpg, 1080×1920. Pinned by the same file › a remake brings new bytes for the SAME keys.
  • R-T613-10 — exercise-video-durations.json carries the re-cut lengths (70 / 72 / 64) and no key naming a render version. Pinned by › the durations map carries every new 1080p key.
  • R-T613-11 — neither sess_ritual_core_day_1 nor tech_rc_breath appears in drizzle/seeds/public/catalog-content-seed.sql, in any table.

Receipts — tranche 2

Every line is a tool result from the session; nothing is inferred.

CheckResult
npm run db:diagnose-media-parity -- --env=prodbefore: ✗ 2 referenced object(s) MISSING from R2 of 764 · after: ✓ PARITY OK — all 761 referenced objects exist in their target bucket.
npm run media:publish-f1-techniques -- --verifyall 44 files match the approved manifest by sha256 + size (26 → 44: the three remakes’ 12 videos and their three covers on both per-locale keys).
npm run media:publish-f1-techniques -- --put=prod44 objects written; the six cover objects then re-downloaded from R2 and hash-checked against the manifest, all six ✓.
prod-guard exec --label='t735-f1-test-fixtures-cleanup'15 changes / 14 rows written (the 4 session_item_translations go by cascade). Backup backups/prod-20260913-125742Z-t735-f1-test-fixtures-cleanup.sql.
prod-guard exec --label='t735-remade-technique-durations'7 changes / 6 rows written; re-queried: 70 / 72 / 64 in both locales.
npx vitest run tests/unit/seeds/30 files, 273 tests, all green.
npx tsc --noEmitno error in the changed files.
pre-commit + pre-push chainPASS, no --no-verify. Three gate failures fixed on the way: two frontmatter enums, a board line over 200 chars, and four vitest/no-conditional-expect errors from an if (r.cover) branch, rewritten as unconditional assertions.

Naming note: the two one-off files ran under the labels t735-* — they were written before the founder folded this work into T613, and the prod-guard backup keeps that name. The files themselves are t613-*; the backup above is the receipt that resolves the difference.

Where the material is right now: production R2 and production D1 carry everything above. The repo change (manifest, publish script, durations, snapshot sanitation, tests) is on PR #1727 and not yet merged.

Still out of scope

The seven F1 cards whose four videos are approved in delivery.json (core-resistencia, tilt-pélvico, cambiar-postura, isométricos, torsión, lado-débil, fuerza-respiración) have no exercise row, no D10 wiring and draft library covers. decoaptación, masaje diafragmático and respiración costal are still incomplete deliveries. Fifteen is still not what is delivered.


625-legacy-phase-pdfs-remade-with-corrected-copy.md

625 — The phase PDFs re-made with the copy she already corrected, then served as phase material

Status: Active Stage folder: 02-active Mode: MODE 2 (F1 tranche under QA since 2026-09-12 — stopped at the comprehension gate, see ## QA status; the ticket stays open for F2–F4 and the capsule) Branch: codex/625-f1-approved-pdfs PR: https://github.com/gala1234/thefittclub/pull/1693 (single integrated F1 PR; #1685 superseded, branch kept) Started: 2026-09-11T16:33:43Z Domain: content-migration Track: content-migration Effort: M Hito: Beta Model: mixed Blocking: no

Model: mixed. Re-making the documents (layout, copy in her voice) is editorial work owned by the assets checkout (Astra). The seed wiring, the migration, the entitlement test and the R2 publish path are the technical tranche. The boundary is the moment an approved PDF exists as a file with a verified hash.

Branch override (T124 precedent). The relevo of 2026-09-11 mandates codex/625-f1-approved-pdfs (worktree .worktrees/t625-f1-integration) instead of the feat/625-… convention. The number sits inside the first 28 characters (T685). Effort M means the activation is NOT fold-eligible; because the founder authorised activation and implementation of this tranche in one instruction, the activation commit is the first commit of the same branch and the single PR carries both — her review of that PR is the activation checkpoint, not a separate PR.

Brief

Los PDF de fase rehechos con el copy que ella corrigió. El 2026-09-11 aprobó los tres de F1 en español e inglés, con sus portadas (Los pdfs en en y es estan aprovados por mi parte, asi como sus portadas), y los adelanta al resto; la guía extensa de hipopresivos pasa a cápsula.

Goal

A member opening the first session of a phase finds that phase’s material — in F1, today, the three approved documents — with the text the founder decided in September 2026, not the text Zenler shipped in 2023. Opening a document grants nothing: no phase unlock, no completion, no training minutes.

What “done” looks like — observable, not argued

This tranche (F1, approved 2026-09-11):

  1. SELECT count(*) FROM session_items WHERE item_type = 'pdf' AND session_id = 'ts_rc_p1_legacy_s01' on prod → 3, and 0 on every other ts_rc_p%_legacy_% session.
  2. npx tsx scripts/media/publish-legacy-phase-pdfs.ts --verify → the three files hash to the manifest and the R-T625-1 scan finds zero occurrences of sistema inmune, decoadaptación and cerrar la diástasis.
  3. npm run db:diagnose-media-parity -- --env=prod → the three private/session_item/… keys exist in thefittclub-media-private.
  4. The player’s resource cards on F1’s first session read Respiración en cuatro tiempos, Un buen hipopresivo, Volver a sentir in /es/ and Breathing in four stages, Hypopressives, step by step, Feeling it again in /en/ — three different cards per language, each opening its own language’s document in the resource viewer.
  5. The start button of that session is enabled with the documents unopened: they are consultable material, not a prerequisite, and never add minutes, mastery or phase progression.
# Items 1 and 3 read prod, item 2's publish script reads R2: checked by hand at QA (the runner reaches no database or bucket).
# The seeded keys point at the approved files (sha256), free of the withdrawn strings
npx vitest run tests/unit/seeds/legacy-phase-pdfs-approved-files.test.ts
# Only a member entitled to the product gets the document
npx vitest run tests/unit/services/media-access.phase-pdf-entitlement.test.ts
# Items 4 and 5: three consult cards per locale, the start button enabled with the documents unopened
npx vitest run tests/component/player-intro-resources.test.tsx tests/unit/domain/session-resources.test.ts

Still open when this tranche lands (the ticket does NOT close): the F2 documents (editorially approved on 2026-09-11 — Wim Hof and Cuidarme como un todo, ES/EN — but not part of this F1 product tranche), F3 and F4 (the founder may widen each phase’s set on review), and the extensive hypopressives guide as a capsule, whose format and destination are undecided.

Problem

The four fichas and the guide are content the lifetime members paid for and cannot reach today (session_items has zero pdf rows). T610 read all five and found the blockers:

  • ficha-resumen-fase3.pdf and ficha-resumen-fase4.pdf — both close with Con los cambios propuestos aquí ademas mejorará mucho vuestro estado de ánimo y sistema inmune. Her 2026-09-04 decision replaces the immune half with te ayuda a descansar y a gestionar el estrés. An immune-system claim is a health claim; it is the one line in the five that must not ship.
  • guia-hipopresivos-vol-2.pdf — writes decoadaptación twice. Her rule, 2026-09-05: decoaptación, always.
  • ficha-resumen-fase1.pdf and ficha-resumen-fase2.pdf — clean. They waited anyway: she chose to publish the set together rather than drip it (superseded on 2026-09-11 for F1, see Decisions).

The text cannot be patched in place: the fichas are a Canva-style export laid out glyph by glyph, so replacing a sentence means re-making the page. The editorial pass (assets checkout, deliverables/t625/) re-made the F1 material as three new documents rendered from HTML with embedded fonts and a real text layer.

Sources: 99_Archivo/Backups_TheFittClub/01_Ritual_Core/Fase_{1..4}_*/Materiales/*.pdf (vault), extracted text in scripts/zenler/AUDITORIA-LEGACY-2026-09-04/inventory/pdf/; the re-made F1 set and its verification.json in the assets checkout deliverables/t625/v2/ and deliverables/t625/v3-hipopresivos/.

Premise validation

  • 2026-09-06 (T610 activation): the five PDFs read line by line, prod session_items pdf count = 0, and the app’s PDF path confirmed working end to end (session_items.item_type='pdf' → player.server.ts → the resource overlay), so no new surface is required.
  • 2026-09-11 (this activation, re-checked against the code because the plan changed):
    • Three approved files exist with the hashes the editorial owner recorded (v2/verification.json, v3-hipopresivos/verification.json); the hypopressives v2 (9de5878f…) is NOT approved and is excluded by the manifest.
    • The key shape the pending spec carried was wrong. private/legacy/<slug>/<locale>/pdf.pdf is parsed by media-access.server.ts as a structured key with entity type legacy, which no branch entitles — every member would have received 403. The Back Office’s own shape for an item’s file, private/session_item/<item id>/<file>, is entitled by the item’s product ownership and is what the seed uses. Pinned by tests/unit/services/media-access.phase-pdf-entitlement.test.ts.
    • Three PDFs on one session are indistinguishable today. The player labels every pdf item with the type label (Documento PDF), and session_item_translations has no title column. Three identical cards is a defect she would see in one minute. The contract therefore adds a nullable title to the translations side-table (ADR-0010: localized text lives there) — additive migration 0088; every existing item keeps its type label.
    • Reading time. A pdf item with duration_seconds = NULL is charged the T325 interim 3′; three of them would have moved F1’s first session by nine minutes on the dashboard hero, the player header and the start CTA. These are resources she keeps at hand, not exercise minutes (relevo 2026-09-11), so the seed writes an explicit 0. tests/unit/seeds/legacy-session-duration-cache.test.ts is the guard that would have gone red under NULL. The 43 min the player shows today is the OLD single-modality session as seeded — it is not the approved F1 audiovisual routine (Base 30:22 in the reviewed prototype); that is a separate technical tranche (T565 family) which PDF wiring neither implements nor claims.
    • The existing mechanism gated the workout — resolved in this tranche. PlayerIntroTheory treated every non-routine item as a mandatory resource: the start CTA stayed locked until each card had been opened, and the viewed state is client-only (reset on every visit). With three documents on day 1 the member would have had to open all three before her first workout, and again on every return. The founder’s collection is consultable (relevo 2026-09-11), so the split is now explicit in gatesSessionStart: a theory video or audio still gates, exactly as since T06; a PDF is listed and openable, shows no Obligatorio flag, is left out of the n/m obligatorios count, and never locks the start button (R-T625-6).
    • Reaching the shelf again. ts_rc_p1_legacy_s01 is scheduled on day 1 only. After day 1 the member reaches the documents by re-entering that session (phase loop, or the day-1 card from the phase list), not from the days that follow. T613’s extras calendar and T624’s “outside the day’s session” shelf are where a permanent place would come from.
    • Found in the browser (Step 5.5): the resource viewer never opened on a desktop. PlayerResourceOverlay wrapped itself in .drawer-scrim, the session-map drawer’s backdrop, which app.css sets to display: none from 1024px (the drawer becomes a sidebar there). At 1280px the overlay’s bounding box was null; at 390px it filled the screen. Since the “viewed” mark is set on close, a laptop member could never clear the required-resources gate — invisible until now because no Legacy session carried a non-routine item. Fixed in this tranche with the viewer’s own .rv-scrim (same look, every width); pinned by the DOM test and by tests/e2e/player/player-phase-material.spec.ts at 1280px.
    • Observed, not changed: the very first navigation to the player right after an EN sign-in bounced player → /en/onboarding/prod_ritual_core_legacy → /en/dashboard once, and the same URL answered 200 with the intro 1.5 s later (the ES run did not bounce). Looks like the dashboard’s first-visit bookkeeping racing the player loader’s onboarding check; outside this ticket, noted for whoever owns the dashboard/onboarding gate.

Scope

In scope

  • Re-making the documents with the corrected copy, in her layout and her voice (editorial, assets checkout).
  • The three copy rules from 2026-09-04/05 applied to every served document: no sistema inmune; decoaptación, never decoadaptación; any cerrar la diástasis wording → una faja que funciona.
  • The seed manifest of approved files (ritual-core-legacy-pdfs.ts: key, title, sha256, bytes, pages) and the session_items / session_item_translations rows on each phase’s first session — F1’s three in this tranche.
  • The title column on session_item_translations (migration 0088) and the player reading it.
  • The verify-and-publish path to R2 (scripts/media/publish-legacy-phase-pdfs.ts): hash check against the manifest, R-T625-1 text scan, wrangler r2 object put per target.
  • The resource viewer’s own scrim (.rv-scrim), so the documents open on a desktop width — the defect this tranche made reachable (Premise validation).

Out of scope

  • Serving the covers. The ten localized covers are approved editorial preparation for a future consultable collection; the viewer shows the PDF itself. Their identities (sha256 per master PDF / master PNG / preview PNG, per locale) are recorded in the seed manifest and nothing else — no collection UI, schema or unlock rule.
  • The F2–F4 documents and the hypopressives capsule (they stay in this ticket, in later tranches).
  • Persisting the viewed state across visits (a PDF no longer needs it; a theory video still forgets it on reload — pre-existing, unchanged).
  • A Back Office field for the new title (the BO upsert preserves it; editing it is a follow-up if she wants to rename from the BO).
  • The F3 intro PowerPoint, and the lifestyle-change texts becoming native app screens.

Blockers / dependencies

  • none
  • T610 (found the blocker and recorded this destination), T325/T346 (PDF reading time), T561 (the guides pattern), T49 (the health-claim line), T613 (the extras calendar that would give the documents a day of their own), T624 (the shelf outside the day’s session), T344 (media parity gate).

Decisions

  • 2026-09-06 — hers: ninguna hasta que estén las cinco corregidas. The F1 and F2 fichas were clean and could have shipped; she chose the set over the drip.
  • 2026-09-06 — the phase PDF is served once per phase, on the phase’s first session, not on all 21 (T610 activation): four rows instead of eighty-four, and the member is not handed the same document every day.
  • 2026-09-11 — hers, superseding the 2026-09-06 “set or nothing” for F1: the three re-made F1 documents are approved and go in ahead of F2–F4. F1 = Respiración en cuatro tiempos (v2), Un buen hipopresivo (v3, the extended one with common errors, corrections, tips and the morning practice — never v2), Volver a sentir (v2). Six PDFs in total for now, with the option to widen F2–F4 on review; the extensive hypopressives guide will be made and becomes a capsule, not a seventh PDF. No translation requested.
  • 2026-09-11 — activation (agent): key shape private/session_item/<item id>/<slug>.<locale>.pdf; duration_seconds = 0; a per-locale title on session_item_translations. Rationale under Premise validation.
  • 2026-09-11 — hers, later the same day: Los pdfs en en y es estan aprovados por mi parte, asi como sus portadas. The three English documents under fase-1/en/ are real approved files (1c93f6ca…, bdd0df31…, 93c90738…), so each item now carries an en row with its own key and English title — Breathing in four stages, Hypopressives, step by step, Feeling it again (the titles the covers catalogue records). The Spanish fallback is no longer how the EN member is served. The ten covers are approved and recorded by hash; not served.
  • 2026-09-11 — product-flow resolution relayed by the editorial owner, consistent with her consultable collection: opening the PDFs is not a prerequisite for starting the exercise on every visit. Implemented as gatesSessionStart (PDF never gates; theory video / audio unchanged).
  • 2026-09-11 — the approved files stay in the assets checkout (read-only to the product repo; the editorial owner keeps the manifest). The manifest entries there still read status: draft; the founder’s direct approval is recorded here and in the seed manifest, and the R2 upload is a founder-run step through the publish script once she wants the objects live.

Open questions

  • Should phase material be mandatory before the first workout? Resolved 2026-09-11 (editorial-owner relay of the founder’s consultable collection): option (b) — a pdf-specific rule lists the cards without gating the CTA. Persisting the viewed state (c) stays out.
  • Whether the fichas for F2–F4 are re-made from her original source files or re-laid out from the extracted text — answered in practice for F1 (re-rendered from HTML by the editorial pass); F2–F4 follow the same path unless she says otherwise.
  • The F2 ficha’s food list: the editorial review confirmed the gluten/maíz/trigo exclusion does appear in the rendered F2 ficha (the pending spec’s premise was wrong). Her 2026-09-04 decision drops it; applies at the F2 remake.

Acceptance criteria

  1. Prod serves the approved pdf session_items rows on the phases’ first sessions — three on F1 in this tranche, the remaining phases as each set is approved.
  2. Zero occurrences of sistema inmune, decoadaptación and cerrar la diástasis in the text of every published PDF (publish-legacy-phase-pdfs.ts --verify).
  3. A member who owns Ritual Core Legacy opens each document from the player; a member who does not is refused (403).

QA status (2026-09-12, F1 tranche)

The QA harness ran on candidate 2675e3914: spec-conformance pass, every checkbox, the design rubric and the comprehension judge — receipts in tests/qa-theaters/ticket-625-legacy-phase-pdfs-remade-with-corrected-copy-theater.md. The comprehension judge returned fail (5/5 personas, worst shared blocker 4 readers) on two sentences that pre-date this ticket — DESBLOQUEAS AL COMPLETAR naming the same technique the intro already offers under Técnica recomendada, and ELEGIDA EN TU PANEL under an undefined ESTÁNDAR pill. Neither string is in this diff (intro_unlocks_eyebrow, recommended_technique, the modality pill), and the one T625 sentence a reader stumbled on (Recursos de esta sesión) was ruled a single-reader stumble. Per 03-qa-ticket.md the harness stops here and the founder decides: accept with a documented reason (the blockers are the player intro’s own copy, on main today) or a copy ticket for the intro. The spec therefore stays in 02-active/ — the receipt gate refuses a 03-qa/ spec without a passing comprehension verdict — and the tranche is not merged until she rules. Since 2026-09-12 this tranche ships in the single integrated F1 PR (branch codex/f1-legacy-integration, her decision Montemos entonces un unico PR pra todo), which supersedes #1685 without deleting its branch.

Pre-QA gate notes (AI review, PR #1685)

  • Round 1 (review 5183256054, head 8a06c95): 0 [BLOCKER], 0 [CONCERN], 3 [NIT]. All three accepted and fixed in 2675e3914: DEFAULT_LEGACY_PDF_SOURCE reads TFC_ASSETS_ROOT (founder path as fallback); --verify is an explicit, accepted flag and unknown arguments abort; .rv-scrim carries its own prefers-reduced-motion guard (--motion-base is 280 ms and app.css has no global reduced-motion block). Pre-existing, out of scope, recorded: .drawer-scrim and .resource-viewer (rv-slide-in, translateY) have no guard either.
  • Round 2 (review 5183823387, head 06171b3): every hunk reviewed belongs to T699, brought in by the main merge 372bc6de2 that cleared the CONFLICTING state; 0 findings on T625 code. The two T699 [CONCERN]s (arc legend role="group" under role="button"; leading-zero dash with round caps) are recorded on #1686, the PR that introduced them. No net-new security concern in any round.
  • Accepted deferrals: none that touch this contract.

Regression contract

Strict, non-optional. Any future change touching the same area must respect every invariant below.

Scope under contract

  • F1’s first session (ts_rc_p1_legacy_s01) carries exactly three pdf session items, each with an es and an en translation row, own file key per locale, own title per locale, duration_seconds = 0.
  • A phase PDF is consultable: listed on the intro, openable at every width, never a prerequisite for starting the workout, never a source of minutes, mastery or phase progression.
  • The gate serves the document only to a member with a completed purchase of the product that schedules the session.
  • The bytes behind every seeded key are the approved files, identified by sha256, free of the three withdrawn strings.

Out of contract

  • The covers (recorded by hash, not served), F2–F4 documents and the hypopressives capsule (later tranches of this ticket), persisting the viewed state, a Back Office field for title, the F3 intro PowerPoint.

Schema / DB invariants

  • session_item_translations.title exists, nullable (migration 0088); a NULL title renders the type label.
  • SELECT count(*) FROM session_items WHERE item_type='pdf' AND session_id='ts_rc_p1_legacy_s01' = 3; 0 on every other ts_rc_p%_legacy_% session.
  • Six session_item_translations rows for those items: (item, 'es') and (item, 'en'), content_key = private/session_item/<item id>/<slug>.<locale>.pdf, distinct titles per locale.
  • Reseeding is idempotent: the purge deletes the per-locale rows before the items and re-emits the same six rows (no duplicates).

HTTP behavior

  • GET /media/private/session_item/<item>/<slug>.<locale>.pdf as an owner → 200/206 from the private bucket; as a refunded member, a member of another product or anonymous → 403.
  • The private/legacy/<slug>/… shape the pending spec proposed → 403 for everyone.

UI behavior

  • /es/panel/reproductor/rc-p1-legacy-t01e01 intro lists three .ds-attach-card.is-consult cards titled Respiración en cuatro tiempos, Un buen hipopresivo, Volver a sentir; /en/dashboard/player/… lists Breathing in four stages, Hypopressives, step by step, Feeling it again. No Obligatorio flag, no x/y count, start button enabled with the documents unopened.
  • Clicking a card opens .resource-viewer over .rv-scrim at 390 px and at 1280 px; the iframe points at that locale’s /media/ key; Escape closes it and marks the card is-viewed.
  • A theory video or audio on a session still gates: 0/1 obligatorios, lock line, start disabled until viewed.

Equivalence table

ScenarioInputExpected HTTPExpected DB state
Owner opens ES documentGET /media/private/session_item/si_ts_rc_p1_legacy_s01_pdf_respiracion_cuatro_tiempos/respiracion-cuatro-tiempos.es.pdf200/206 application/pdfunchanged (no progress, no unlock, no minutes)
Owner opens EN documentsame item, .en.pdf200/206unchanged
Refunded member opens eithersame keys403unchanged
Owner starts the session without opening any PDFintro start CTAn/a (client)session proceeds; nothing written for the PDFs
Reseed twicenpm run verify:local ×2n/a3 items / 6 rows, no duplicates

Known limitations / deferred

  • The viewed state of a PDF is client-only and resets on reload (pre-existing for videos; harmless for consultable material).

  • R-T625-1..7 below are the named invariants each test pins.

  • R-T625-1 — No phase PDF served by the app contains a withdrawn claim. Testable: verifyApprovedPdf (scripts/media/lib/legacy-phase-pdfs-verify.ts) extracts the text of every manifest file and fails on any forbidden string; tests/unit/seeds/legacy-phase-pdfs-approved-files.test.ts runs it wherever the deliverables exist and pins the scan itself everywhere.

  • R-T625-2 — A phase PDF is entitled by product ownership, never public. Testable: tests/unit/services/media-access.phase-pdf-entitlement.test.ts (owner → private bucket; refunded / stranger → forbidden; the private/legacy/… shape → forbidden).

  • R-T625-3 — A phase PDF charges no training minutes. Testable: the seed test asserts duration_seconds = 0 on every pdf row; legacy-session-duration-cache.test.ts keeps the seeded minutes equal to the computed ones.

  • R-T625-4 — Three documents on one session read as three different cards. Testable: sessionItemLabel unit test + the seed test asserting three distinct titles.

  • R-T625-5 — The resource viewer opens at every width, desktop included. Testable: tests/component-dom/PlayerResourceOverlay.test.tsx (the viewer owns .rv-scrim, never .drawer-scrim) and tests/e2e/player/player-phase-material.spec.ts (1280px: click → viewer visible with the document’s title; Escape → card reviewed).

  • R-T625-6 — A phase PDF never gates the workout; a theory video or audio still does. Testable: tests/unit/domain/session-resources.test.ts (gatesSessionStart), tests/component/player-intro-resources.test.tsx (three PDFs → no Obligatorio, no count, start enabled; a theory video → 0/1 obligatorios, lock, start disabled until viewed), and the e2e spec (start enabled with the documents unopened).

  • R-T625-7 — The EN member reads the English document under its English title. Testable: seed test (an en row per item with its own key and a different sha256 / title from es), media-access test (both keys entitled), the e2e spec (/en/… cards read the English titles and the viewer loads ….en.pdf).

GEO baseline

Not applicable — every surface this ticket touches is private (the player’s resource overlay behind entitlement). No ($lang) public route is added or changed.

Affected areas (hardened at activation 2026-09-11)

  • DB tables: session_item_translations gains title text (nullable) — migration drizzle/migrations/0088_t625_session_item_title.sql, additive, rollback comment inside. session_items: 3 new pdf rows on ts_rc_p1_legacy_s01 (sort_order 1–3, duration_seconds 0). session_item_translations: an es and an en row each (content_key = private/session_item/<item id>/<slug>.<locale>.pdf, title = that language’s document name) — six rows.
  • Schema: app/db/schema/catalog.ts — title on sessionItemTranslations.
  • Services (app/services/): player.server.ts — both resource-link builders select title and label the card with sessionItemLabel(tx, itemTypeLabel(type)). No signature changes. media-access.server.ts unchanged (the structured session_item branch already entitles the key).
  • Domain logic (app/lib/domain/): new session-item-label.ts — sessionItemLabel(rows, fallback): own-locale title, else es, else the type label. New session-resources.ts — gatesSessionStart(kind): pdf → false, everything else → true.
  • Components / styles: app/components/player/PlayerResourceOverlay.tsx — root class drawer-scrim → rv-scrim; app/styles/app.css — new .rv-scrim rule beside the resource-viewer base (fixed, inset 0, z-index 9000, the drawer scrim’s colour and animation). PlayerIntroTheory.tsx — the required count, the lock line and the start button consider gating resources only; a PDF card carries is-consult instead of is-mandatory, no Obligatorio flag (still Revisado once opened). PlayerSession.tsx — the sidebar-jump guard applies the same rule. No new copy; the design-review and comprehension receipts apply at QA because component files changed.
  • Tooling: package.json gains media:publish-legacy-pdfs; .knip.jsonc ignores the optional poppler binaries the verifier shells out to.
  • Routes (tripartite): none. The Back Office session editor keeps writing content_key/subtitle_key and leaves title untouched on upsert.
  • i18n namespaces: none — player.kind_pdf exists in both locales; the document titles are catalog data, not UI copy.
  • Seeds: drizzle/seeds/catalog/products/ritual/ritual-core-legacy-pdfs.ts (the manifest) and ritual-core-legacy-sql.ts (emitLegacyPhasePdfs, guarded to a session the builder emits; purge of the per-locale rows before their items).
  • Scripts: scripts/media/publish-legacy-phase-pdfs.ts + scripts/media/lib/legacy-phase-pdfs-verify.ts.
  • Tests: tests/unit/seeds/ritual-core-legacy-sql.test.ts (T625 block), tests/unit/seeds/legacy-phase-pdfs-approved-files.test.ts, tests/unit/domain/session-item-label.test.ts, tests/unit/services/media-access.phase-pdf-entitlement.test.ts, tests/component-dom/PlayerResourceOverlay.test.tsx (scrim ownership), tests/e2e/player/player-phase-material.spec.ts (full tier).
  • Assets checkout: read-only. No manifest state is changed from here.

Implementation receipts (2026-09-11, F1 tranche — second pass, bilingual + consultable)

Everything below is from tool runs in the implementation sessions; what was not run says so. The first pass (ES-only, gating PDFs, two gates bypassed for missing binaries) is superseded by this one; its bypasses are recorded in the commit history and were closed here.

  • Approved files verified, both locales — tests/unit/seeds/legacy-phase-pdfs-approved-files.test.ts ran against the editorial deliverables on the founder’s machine: 6 files (3 ES under v2/ + v3-hipopresivos/, 3 EN under fase-1/en/), sha256 + byte size equal to the manifest, page counts 3 / 7 / 4 per locale, pdftotext scan finds none of the forbidden strings (Spanish list + immune system / close the diastasis). Hypopressive ES is v3 (9379499a…), never v2. The publish CLI (npm run media:publish-legacy-pdfs -- --put=local) ran through the same verifier and placed the six objects in the local bucket under the seeded keys (wrangler r2 object put … --local, six Upload complete).
  • Gates that the first pass skipped, now run with the locked dependencies installed (npm ci in this worktree): npm run audit:layout → clean (725 modules); npm run knip → no findings after registering the publish CLI as an npm script and ignoring the optional poppler binaries in .knip.jsonc; tests/unit/maintenance/audit-layout-app-scripts.test.ts → 7 passed. Pre-commit chain on the follow-up commit: every gate green, including audit-layout and lint-duplication (jscpd now installed). Pre-push chain: i18n schema, language of record, architecture intent, route i18n handle, design drift, knip, ESLint — all green; pushed without --no-verify.
  • Suites: npm run typecheck exit 0 (run without a pipe, so the exit code is real). Node project: 4964 passed, 1 todo (the neutralised scratch file). DOM project: 637 passed. New: tests/unit/domain/session-resources.test.ts, tests/component/player-intro-resources.test.tsx (SSR, both locales, real player.json copy).
  • Seed against the migrated schema: seed-applies-to-migrated-schema and legacy-session-duration-cache green with the six rows and migration 0088 — the seeded session length is unchanged (the PDFs charge 0 s).
  • Browser (Step 5.5), local rung npm run preflight:smoke:local (wrangler pages dev over the built bundle + the verify:local D1, Chromium 1280×800), legacy fixture, /es/panel/reproductor/rc-p1-legacy-t01e01 and /en/dashboard/player/rc-p1-legacy-t01e01 with productId=prod_ritual_core_legacy — tests/e2e/player/player-phase-material.spec.ts, 2 passed:
    • /es: three is-consult cards titled Respiración en cuatro tiempos, Un buen hipopresivo, Volver a sentir; no n/3 obligatorios count, no lock line, Empezar sesión enabled with nothing opened; each card opens the viewer at 1280px with its title and a gated /media/… iframe; Escape marks the card reviewed; the button stays enabled.
    • /en: the cards read Breathing in four stages, Hypopressives, step by step, Feeling it again; the first opens …/respiracion-cuatro-tiempos.en.pdf — the English row’s own object, not the Spanish fallback.
    • The earlier HTTP-level check (first pass) had already recorded 200 application/pdf with the manifest byte count for the owner and 403 for a member without the product / 401 anonymous; the media-access unit test now pins both locales’ keys.
  • CI on PR #1685: attempt 1 on the first-pass commit was cancelled by the docs push; attempt 2 failed only on knip (the three findings fixed above; Test, Build, Typecheck, Mutation green). The follow-up push (bilingual + consultable + gate fixes, merged with main at 3c0940ea5) is the head the founder reviews; its checks are read from the PR, not claimed here.
  • Not done here, by design: no object was uploaded to preview or production R2 and no row was written to any remote D1 — the publish is a founder-run step (npm run db:migrate:prod → content seed → npm run media:publish-legacy-pdfs -- --put=prod → npm run db:diagnose-media-parity -- --env=prod). The assets manifests were not touched. tfc-product-truth --env=prod could not be run in the session (shell gate), so the prod pdf count of 0 rests on T610’s 2026-09-06 measurement.

§8 — QA tickets (full specs)

(none active)


§9 — Pending backlog (summary)

  • 105-pwa-native-ux-patterns — 105 — PWA native UX patterns (push, ⌘K search, FAB empezar sesión) · track=mvp · effort=L · domain=pwa, global UI · brief=Diseñar e implementar tres patrones UX que diferencian una PWA bien hecha de una “web instalada”: pu…
  • 111-tfc-ai-pulse-skill — 111 — Skill tfc-ai-pulse: structured quarterly AI tooling review (parked) · track=infra · effort=S · domain=other (meta — Claude Code skill / dev tooling) · brief=Convert continuous FOMO about AI tooling updates (Anthropic, Gemini, MCP, Claude Code) into a bounde…
  • 112-github-org-migration-branch-protection — 112 — Migration to a GitHub Organization on the Team plan for branch protection enforcement (parked) · track=infra · effort=XS · domain=other (infra / devops — repo administration) · brief=Cuando se active: migrar el repo desde la cuenta personal gala1234 a una organización con plan Git…
  • 115-journal-write-surface — 115 — Journal write surface (member-facing entry creation UI) · track=mvp · effort=M · domain=dashboard · brief=Add the member-facing UI for creating journal entries, completing the value chain that T05 (schema +…
  • 126-d1-per-pr-branching — 126 — D1 per-PR branching (PARKED — deferred follow-up) · track=infra · effort=M · domain=infra · brief=Per-PR D1 database isolation so smoke E2E (T122) and manual preview testing don’t share state across…
  • 127-otel-distributed-tracing — 127 — OpenTelemetry distributed tracing (PARKED — deferred follow-up) · track=infra · effort=L · domain=infra · brief=Full OpenTelemetry instrumentation across *.loader.server.ts and *.action.server.ts, exporting t…
  • 130-brand-vocabulary-ssot-investigation — 130 — Brand / product vocabulary SSOT (with mandatory ADR-0005 investigation) · track=infra · effort=L · domain=content-migration · brief=Decide dónde vive la SSOT canónica del vocabulario de marca/producto (Cápsula, Ritual, Hito, Embajad…
  • 160-jsx-a11y-eslint10-override-removal — 160 — Remove eslint-plugin-jsx-a11y ESLint-10 peer override (upstream-gated) · track=infra · effort=XS · domain=other · brief=When eslint-plugin-jsx-a11y publishes a release whose peerDependencies.eslint includes ^10, bu…
  • 162-harden-migration-validation-ci — 162 — Harden the migration-validation CI job (close the latent-baseline gap) · track=infra · effort=S · domain=other · brief=The migrations CI job only applies the chain when a PR touches drizzle/migrations/*.sql, so a de…
  • 164-in-app-notifications-header-badge — 164 — In-app notifications: header badge + center (consumes T98 slot) · track=mvp · effort=M · domain=global UI · brief=Make the bell slot that T98 reserved (non-functional) in the member header actually work: an unr…
  • 168-account-recovery-email-switch-and-new-device-alert — 168 — New-device sign-in alert · track=mvp · effort=M · domain=auth · brief=Avisar por correo cuando alguien entra desde un dispositivo o un sitio nunca vistos. La otra mitad d…
  • 18-admin-routes-tripartite-refactor — 18 — Admin routes: tripartite convention + scaffold (strangler, not big-bang) · track=infra · effort=S · domain=admin · brief=Admin routes: tripartite convention + scaffold (strangler, not big-bang refactor).
  • 181-ritual-core-sales-page-hito3 — 181 — Ritual Core: sales page Hito 3 (máxima conversión) · track=mvp · effort=L · domain=other · brief=Rediseñar /ritual-core como sales page de máxima conversión para Hito 3: CTA “Prueba gratis: Cápsu…
  • 19-multi-ritual-weekly-distribution — 19 — Multi-ritual weekly distribution algorithm · track=post-mvp · effort=M · domain=dashboard · brief=Multi-ritual weekly distribution algorithm
  • 196-per-product-bitacora-diario-seguimiento — 196 — Per-product Bitácora + Diario (“Tu seguimiento” in module detail) · track=mvp · effort=M · domain=dashboard · brief=Generalizar Bitácora (métricas/clínico) y Diario (notas + IA) para que funcionen por-producto y se e…
  • 20-stripe-checkout-and-webhooks — 20 — Stripe checkout + custom page + webhooks · track=mvp · effort=L · domain=schema · brief=Activate paid product access end-to-end via Stripe so users can purchase Rituals (subscription) and …
  • 206-retention-action-event-emission — 206 — Retention: action-event emission (T57 slice C) · track=mvp · effort=M · domain=analytics · brief=Emite los momentos “de acción” de la retención (primera sesión, ritmo formado, evaluación/transición…
  • 207-retention-moment-driven-email-cadence — 207 — Retention: moment-driven celebratory cadence (T57 slice D) · track=mvp · effort=M · domain=email · brief=Cablea los emails celebratorios “lo lograste” a los momentos de acción (primera sesión, ritmo formad…
  • 208-retention-in-app-surfaces — 208 — Retention: in-app surfaces (T57 slice E) · track=mvp · effort=M · domain=dashboard · brief=Los momentos de ausencia y de vuelta: la pantalla de pausa a los 7 días, la bienvenida tras un lapso…
  • 209-retention-bo-dashboard — 209 — Retention: Back Office dashboard (T57 slice F) · track=mvp · effort=L · domain=admin · brief=El panel de retención en el Back Office: 4 pestañas (Rituales / Módulos / Cápsulas / cross-product) …
  • 213-meta-capi-purchase-dedup-checkout — 213 — Meta CAPI: deduplicated Purchase from app checkout (pixel + server) · track=mvp · effort=L · domain=analytics · brief=Cuando la app sustituya a Zenler, cada compra debe disparar el Purchase de Meta por dos vías dedup…
  • 22-gifting-vouchers — 22 — Gifting / gift_vouchers · track=mvp · effort=M · domain=schema · brief=Allow a user to purchase a product as a gift. Generate a unique redeem code; recipient redeems with …
  • 24-app-bilingual-completeness-pass — 24 — App bilingual completeness pass · track=mvp · effort=M · domain=other · brief=Audit every component, loader, action, and namespace to ensure every user-facing string exists in bo…
  • 255-unify-admin-bo-design-carveout — 255 — Unify the admin-BO design carve-out into a single shared source · track=infra · effort=S · domain=infra · brief=The “admin Back Office is exempt from the santuario design rubric” path list is copy-pasted into thr…
  • 259-admin-assets-mobile-horizontal-overflow — 259 — Fix horizontal overflow on /admin/assets (mobile) · track=polish · effort=S · domain=infra · brief=/admin/assets overflows the viewport width on mobile, so the whole page is pannable/zoomable into …
  • 277-wire-billing-entitlements-subscription-ui — 277 — Wire real billing/entitlements to the profile Subscription UI · track=mvp · effort=L · domain=billing · brief=Replace the mock plan-selector/invoices/purchases/perk in the profile Subscription section with the …
  • 279-magazine-public-surface — 279 — Magazine: the public surface /es/magazine · /en/magazine from the definitive design · track=mvp · effort=L · domain=design · brief=Montar el magazine público (/es/magazine · /en/magazine + detalle por slug
  • 280-prensa-press-page — 280 — Prensa /prensa · /press: public press surface (net-new) · track=post-mvp · effort=M · domain=design · brief=Página pública de Prensa (/es/prensa · /en/press): material citable para periodistas — boilerpla…
  • 282-leads-growth-insights — 282 — Leads growth insights (cross-leads analytics) · track=mvp · effort=M · domain=admin, analytics · brief=BO analytics surface showing lead funnel performance: lead→user conversion rate by source, weekly ne…
  • 288-english-translation-quality-sweep — 288 — English translation quality sweep (detect ES-in-EN + translate) · track=mvp, content-migration · effort=L · domain=content-migration · brief=Audit every translation source — public/locales/en/*.json plus the 11 DB *_translations tables (…
  • 29-perf-sla-and-happy-path-e2e — 29 — Pre-launch verification: happy-path E2E theater (the perf budget moved to T804) · track=mvp · effort=M · domain=other · brief=Verify the <200ms p95 SLA stated in thefittclub-product.md Layer 1 holds under realistic load in p…
  • 308-dedup-admin-exercises-id-admin-exercises-new — 308 — Dedup: admin.exercises.$id ↔ admin.exercises.new (two clones, 20L + 30L) · track=infra · effort=S · domain=infra · brief=Collapse the two code clones shared between the exercise create and edit
  • 309-dedup-exerciselibrary-server — 309 — Dedup: exerciseLibrary.server.ts (39L intra-file clone) · track=infra · effort=M · domain=infra · brief=Collapse a 39-line / 614-token intra-file code clone into a single source of
  • 310-modal-tm-tier-visual-adoption — 310 — Modal .tm-* token-tier visual adoption (surface ticket) · track=polish · effort=M · domain=other · brief=Land the next iteration of the modal design system: adopt the staging .tm-*
  • 318-separate-journaling-consent-from-onboarding — 318 — Separate the journaling consent from the onboarding consent · track=mvp · effort=M · domain=compliance · brief=One health_data consent unlocks both onboarding personalisation (EU) and the journal → Anthropic (…
  • 323-bo-drip-sequence-controls — 323 — BO drip-sequence controls (enable/disable + cadence) · track=mvp · effort=M · domain=email, back-office · brief=A BO surface to control our own drip send path (the surviving control half of the
  • 326-workers-paid-cron-capacity — 326 — Upgrade to Workers Paid: restore cron capacity (post-beta, revenue-gated) · track=post-mvp · effort=S · domain=infra · brief=The background Worker is on Workers Free, capped at 5 cron triggers per account
  • 328-bo-broadcast-markdown-body — 328 — BO broadcast body: safe Markdown rendering · track=post-mvp · effort=S · domain=email · brief=T321 P0 renders the broadcast body as plain text (blank line → paragraph, single newline →
  • 336-facebook-dynamic-reviews-geo — 336 — Dynamic Facebook reviews in Home’s GEO Review schema · track=post-mvp · effort=L · domain=infra · brief=Replace T335’s 3 hardcoded testimonials with real reviews pulled live from the TheFittClub Facebook …
  • 339-prep-exercise-detail-sheet — 339 — Prep-exercise detail sheet: video + why-it-was-added + dosing, with start-session CTA · track=mvp · effort=M · domain=dashboard · brief=V2 of the prep-mode loop (founder ask, 2026-07-03): tapping the compensation exercise in the prep ba…
  • 34-bo-admin-stripe-panel — 34 — BO admin: Stripe customer + purchases panel · track=post-mvp · effort=M · domain=admin · brief=Give the admin BO a unified view of each user’s Stripe state (customer ID, active subscriptions, rec…
  • 341-r2-media-key-entity-id-divergence — 341 — R2 media key ↔ entity ID divergence (accept + entity-agnostic GC) · track=infra · effort=S · domain=infra · brief=The BO draft-first upload flow uploads media before the final sess_…/ex_… ID
  • 346-pdf-wordcount-reading-time-pdfjs — 346 — PDF reading-time from auto word count (pdf.js extraction) — dep-bump child of T325 · track=mvp · effort=XS · domain=admin · brief=Automatically estimate a session PDF handout’s reading time from its word count,
  • 359-bo-leads-tag-filter — 359 — BO leads list: filter by tag · track=post-mvp · effort=S · domain=admin · brief=Add a tag filter (namespace + optional key/value) to the BO leads list so the founder can view — a…
  • 363-membership-seniority-tiers-and-phase-milestones — 363 — Membership seniority tiers + phase milestones (recognition, not a losable ladder) · track=post-mvp · effort=L · domain=account · brief=Extend the T274 credential badge from two roles into a seniority ladder (how long she has been a…
  • 383-tap-target-system-rule-and-consent-parity — 383 — Tap targets: land the system rule, starting with consent parity · track=mvp · effort=M · domain=compliance · brief=Withdrawing consent is a ~36px target where granting is 44px — Art. 7(3) asks they be equally easy. …
  • 385-ambassador-bo-oversight-and-code-revocation — 385 — Ambassador BO oversight: visibility, leak alerts, code revocation · track=mvp · effort=L · domain=admin · brief=The ambassador programme has no operator surface: nowhere to see who refers whom, no warning when on…
  • 387-q3-personalization-seed-from-zenler-survey — 387 — Q3 personalization seed: Semana-0 survey → migrated members’ physical profiles · track=content-migration, mvp · effort=M · domain=content-migration · brief=Aplicar la «Encuesta - Semana 0» (archivada por T300) al perfil físico de las socias migradas que di…
  • 388-retag-legacy-session-blocks-modality — 388 — Re-tag legacy session blocks to the resolved product-modality (T358 data follow-up) · track=infra, content-migration · effort=S · domain=schema · brief=Re-etiquetar los bloques de las sesiones legacy a la product-modality que la UI resuelve (standard…
  • 39-funnel-analytics-and-events — 39 — Funnel analytics + event tracking · track=mvp · effort=M · domain=other · brief=Capture the events thefittclub-strategy.md §9 (“Métricas y sistema de control”) depends on — signu…
  • 391-dedup-private-loader-preamble — 391 — Extract the shared private-loader preamble · track=infra · effort=M · domain=infra · brief=Extraer el preámbulo compartido de los loaders privados (imports +
  • 392-ci-wrangler-preview-deploy — 392 — Deploy the PR preview from CI with wrangler, not the Cloudflare builder · track=infra · effort=M · domain=infra · brief=Desplegar la preview de cada PR desde CI (wrangler pages deploy build/client) en vez de
  • 394-pricing-ssot-and-machine-readable-offers — 394 — Pricing SSOT + machine-readable Offer schema on the public sales surface · track=mvp · effort=M · domain=billing, infra · brief=Give the app one pricing source of truth, reconcile the stale prototype prices on /ritual-core, an…
  • 395-agent-readable-catalog-and-agentic-commerce-readiness — 395 — Agent-readable catalog endpoint + agentic-commerce readiness · track=post-mvp, infra · effort=L · domain=infra, billing · brief=Publish one versioned, cacheable JSON document describing plans, availability and sign-up entry poin…
  • 397-full-specs-vs-code-audit — 397 — Full specs-vs-code audit (Fable session) · track=infra · effort=L · domain=other · brief=Primera auditoría completa de las 295+ specs cerradas contra el código real: qué prometen los contra…
  • 398-file-size-gate-diff-only — 398 — File-size gate (diff-only pre-commit + full-repo trend) · track=infra · effort=S · domain=infra · brief=Un gate que impide que nazca el próximo archivo gigante: pre-commit bloquea archivos NUEVOS que supe…
  • 401-af-link-focus-indicator — 401 — Focus indicator for .af-link anchors · track=polish · effort=XS · domain=design · brief=Give .af-link anchors a system focus indicator. They are keyboard-reachable and carry the browser’…
  • 402-autonomy-health-fails-open-without-jq — 402 — fix: autonomy-health reports “salud OK” when jq is missing · track=infra · effort=XS · domain=infra · brief=Without jq, every outcome count in autonomy-health.sh silently becomes 0, so the script prints “…
  • 408-bo-content-sync-coverage-and-scope — 408 — BO content sync: real coverage, one table list, and per-group scope · track=infra · effort=L · domain=admin · brief=The BO’s Content Management panel moves 17 of the ~30 content tables — guides, media, onboarding and…
  • 410-testimonial-wall-and-ui-consumption — 410 — Public testimonial wall + UI consumption from the SSOT · track=mvp · effort=L · domain=design · brief=El muro público de historias: moderno y cinematográfico, con las historias aprobadas en las palabras…
  • 411-testimonial-points-per-product-and-profile — 411 — Club points for testimonials: per-product amounts, profile display, in-product prompts · track=mvp · effort=M · domain=other · brief=Escribir una historia da puntos del Club, distintos según el producto (Ritual, Módulo, Cápsula). Los…
  • 412-testimonial-media-upload — 412 — Image and video in testimonials · track=mvp · effort=L · domain=other · brief=Que una historia pueda llevar foto o vídeo, con su propio permiso aparte del texto: una mujer puede …
  • 419-instagram-messenger-inbound — 419 — Instagram + Facebook Messenger inbound on the shared AI assistant · track=mvp · effort=M · domain=other · brief=Extends T33’s inbound AI assistant to Instagram DMs and Facebook Messenger: same brain, voice and es…
  • 421-fix-audit-skills-trusts-file-order — 421 — fix: audit-skills.sh trusts file order for “last used”, so a merge can fake a STALE verdict · track=infra · effort=XS · domain=infra · brief=audit-skills.sh takes the LAST matching line as a skill’s most recent use, but a merge
  • 442-precache-scope-first-visit-bandwidth — 442 — Scope the precache: 686 kB on the first visit · track=polish · effort=S · domain=infra · brief=El service worker precachea todo el build, así que la primera visita a cualquier página
  • 443-one-name-per-phase-across-surfaces — 443 — One name per phase, across every surface a member can see · track=polish · effort=M · domain=content-migration · brief=Hay cinco vocabularios distintos para la misma progresión de Ritual Core, y la misma
  • 444-withdrawal-waiver-checkbox-and-refund-windows — 444 — The withdrawal-waiver checkbox, and the refund window each product actually gets · track=mvp · effort=M · domain=compliance · brief=Hoy la web promete 14 días de desistimiento a todo el mundo, incluidas las Cápsulas, porque
  • 449-whatsapp-media-support — 449 — Receiving photos and videos on WhatsApp · track=post-mvp · effort=L · domain=compliance · brief=Actually receive the photos and videos T448 currently declines. Mostly a data-protection
  • 453-ai-review-subscription-billing — 453 — Pay the reviewer from the subscription instead of API tokens · track=infra · effort=M · domain=infra · brief=Anthropic documenta la vía: CLAUDE_CODE_OAUTH_TOKEN con claude-code-action factura contra la
  • 456-pr-autopilot-defer-visual-sweep-to-final-round — 456 — PR Autopilot pays the full visual-invariants sweep on every intermediate round, not just the final one · track=infra · effort=M · domain=infra · brief=Every push PR-Autopilot (T257) makes while converging a PR — including a one-line
  • 458-magazine-content-schema — 458 — Magazine content schema in D1 (posts + per-locale translations + authors + media) · track=mvp · effort=L · domain=schema · brief=Las tablas de D1 donde viven las piezas del magazine — cuatro arquetipos, cuerpo por
  • 459-bo-magazine-cms — 459 — Back Office: magazine CMS (/admin/magazine) — block composer, state machine, EN pipeline · track=mvp · effort=L · domain=admin · brief=El CMS del Back Office para el magazine: compositor de bloques, flujo Borrador →
  • 460-blog-to-magazine-rename-sweep — 460 — Rename sweep: everything called “blog” becomes “magazine” · track=mvp · effort=S · domain=other · brief=La palabra de marca es magazine, no blog: renombrar el enlace del footer, los
  • 461-lint-unused-vars-to-zero — 461 — Lint to zero (1/4): no-unused-vars + stale disable directives · track=infra · effort=XS · domain=infra · brief=Clear the 96 mechanical ESLint warnings (95 @typescript-eslint/no-unused-vars + 1 stale `eslint-di…
  • 462-lint-label-has-associated-control-to-zero — 462 — Lint to zero (2/4): label-has-associated-control (92 form labels) · track=mvp · effort=M · domain=admin · brief=Wire the 92 <label> elements that are not associated with any control (htmlFor/id, or wrapping…
  • 463-lint-control-has-associated-label-to-zero — 463 — Lint to zero (3/4): control-has-associated-label (186 — triage first) · track=mvp · effort=L · domain=other · brief=Give the 186 controls with no accessible name one — mostly icon-only buttons needing aria-label — …
  • 464-lint-interaction-rules-to-zero — 464 — Lint to zero (4/4): the 22 interaction findings + close the ratchet at 0 · track=mvp · effort=M · domain=player · brief=Make the 22 non-native interactive elements (<div onClick> scrims, drop zones, clickable cards) re…
  • 465-magazine-audio-tts-and-listen-surface — 465 — Magazine audio: TTS at publish, real recordings, and the listen surface · track=post-mvp · effort=L · domain=other · brief=La segunda puerta de entrada a cada pieza: voz sintética generada al publicar (o
  • 470-pregnancy-notice-gift-and-send-settings — 470 — The maternity coupon in the postpartum notice, and the settings the sends deserve · track=mvp · effort=M · domain=email · brief=T469 ships the pregnancy waitlist’s two promised sends. Its second email — the
  • 492-surface-the-descent-signal — 492 — Surface the descent signal · track=mvp · effort=S · domain=admin · brief=A woman stepping back a phase is a strong product signal. The data will exist from T432
  • 493-engine-answers-editable-after-onboarding — 493 — Engine-input answers stay changeable after onboarding · track=mvp · effort=M · domain=onboarding · brief=Cuatro respuestas que calibran su plan (transverso, respiración, fisio previa, partos) no
  • 494-onboarding-stage-media-and-hygiene — 494 — The onboarding stage gets its delivered media, plus the surface’s hygiene sweep · track=polish · effort=S · domain=onboarding · brief=La banda oscura del onboarding reserva el sitio de una foto/vídeo que nadie pinta — por
  • 500-seed-answers-engine-era-alignment — 500 — Seed fixture answers realign with the engine-era onboarding set (+ committed FK-integrity check) · track=infra · effort=S · domain=infra · brief=Trim the seeded Ritual Core answers to the 3 questions the flow asks, with values they accept; extra…
  • 503-idempotency-keys-for-member-mutations — 503 — One idempotency key closes the whole double-submit class (absorbs T478 A4 + A5) · track=mvp · effort=S · domain=player · brief=Un mismo mecanismo — una clave de intento que la base de datos rechaza si ya existe — cierra los tre…
  • 505-airplay-remote-playback-button-player — 505 — “Watch on the TV” button in the player (Remote Playback: AirPlay + Cast) · track=post-mvp · effort=M · domain=player · brief=Un botón en la cinta del player que abre el selector de televisiones del propio navegador — AirPlay …
  • 512-member-transition-pwa-reinstall-redirect — 512 — Member transition: PWA reinstall banner + old-host redirect + migration comms · track=infra, content-migration · effort=S · domain=player · brief=Everything members see on migration day: a one-time re-login, a friendly banner to reinstall the hom…
  • 513-break-glass-reverse-proxy-off-cloudflare — 513 — Break-glass reverse proxy off Cloudflare (block-collision escape hatch) · track=infra · effort=S · domain=infra · brief=A cheap backup server (~1-2 €/month) outside Cloudflare, pre-configured and left off. If some Saturd…
  • 519-smoke-verdict-hostage-to-a-comment-write — 519 — The smoke E2E verdict is hostage to a comment write · track=infra · effort=XS · domain=infra · brief=pr-e2e.yml fails its own job when GitHub refuses the comment it posts to report the
  • 520-numbers-are-data-metric-face-rule — 520 — A number is a datum, and nothing in the repo knows it · track=infra · effort=M · domain=design-system · brief=Make “a number is a datum” a rule the repo can see: written in the design SSOT, asked by
  • 528-the-design-workbench-still-holds-the-copy-and-the-law-t468-deleted — 528 — The design workbench still holds the copy and the law T468 deleted · track=mvp · effort=S · domain=design · brief=The design workbench still describes the auto-test as it worked before T468: with the three texts th…
  • 53-magazine-editorial-policy-and-geo — 53 — Magazine editorial policy + GEO playbook (the rules the publish gate enforces) · track=mvp · effort=M · domain=compliance · brief=La política editorial del magazine — qué se puede afirmar, cómo se cita, qué
  • 533-dynamic-member-segments — 533 — Dynamic member segments: combinable predicates over the member universe · track=mvp, infra · effort=M · domain=email · brief=La audiencia de socias de T530 es “producto sí/no”. Este ticket la hace dinámica y combinable — “soc…
  • 534-bo-phase-unlock-highlights — 534 — BO-curated “what opens in this phase” for the earned-phase ceremony · track=mvp, polish · effort=S · domain=admin · brief=Las tarjetas «Nuevo en tu fase» de la ceremonia T523 hoy son números derivados (sesiones, técnicas, …
  • 54-multi-currency-pricing — 54 — Multi-currency + multi-region pricing strategy (LATAM + EU) · track=mvp · effort=L · domain=other · brief=Enable TheFittClub to sell across Spanish-speaking LATAM (MX, AR, CL, CO, PE — minimum) and Eurozone…
  • 545-she-chooses-to-step-back-a-week — 545 — She chooses to step back a week · track=post-mvp · effort=M · domain=dashboard · brief=Cuando la erosión ya está corriendo, hoy le quita semanas sin decírselo y sin que ella
  • 550-measure-phase-screen-comprehension — 550 — Measure phase-screen comprehension with real members · track=infra · effort=S · domain=dashboard · brief=Una pregunta de tres botones debajo de «¿Cómo voy en mi fase?» que mide cuántas socias reales entien…
  • 551-instrument-phase-screen-behaviour — 551 — Instrument whether the phase screen changes behaviour · track=infra · effort=S · domain=analytics · brief=Dos eventos que miden si la pantalla «¿Cómo voy en mi fase?» hace su trabajo — si abre el desplegabl…
  • 555-the-session-close-note-loses-its-focus-ring — 555 — The session-close bar may cover the last line of the document · track=mvp · effort=XS · domain=player · brief=Dos hallazgos sobre la pantalla de cierre de sesión de T539, que ya está fusionada y viva.
  • 557-the-phase-screen-is-unreachable-without-an-engine — 557 — The phase screen disappears when the ritual has no progression engine, and says nothing · track=mvp · effort=S · domain=dashboard · brief=De la fundadora, 2026-08-28, con una captura de la preview: `y en ritual Core Legacy no veo
  • 566-photo-lock-against-the-single-counter — 566 — Build the progress-photo lock the documentation already promises · track=mvp · effort=M · domain=dashboard · brief=domain-rituals.md §7 promete que la segunda foto de progreso se desbloquea tras semanas cumplidas.…
  • 576-locale-safety-r2-namespace-and-string-change — 576 — lint-locale-safety R2: resolve the namespace, and re-scan when a STRING gains a placeholder · track=infra · effort=S · domain=infra · brief=El gate que existe para el {{product}} en crudo no lo cazó: compara claves `sin mirar el namespace…
  • 587-second-copy-of-ritual-core-media-and-d1-backup-gaps — 587 — Backups: a second copy of every Ritual Core video outside Cloudflare, and the three gaps around the D1 backup · track=infra, content-migration · effort=M · domain=infra · brief=Los vídeos de Ritual Core Legacy y de Ritual Core viven en un solo sitio (R2). La base de datos
  • 588-session-hardening-cookie-cache-revocation-and-signed-url-expiry — 588 — Revoked sessions lose access on the next protected request · track=infra · effort=M · domain=auth · brief=Una sesión revocada seguía entrando incluso en administración. Consultar su vigencia en el servidor …
  • 589-compliance-divergences-from-the-2026-09-03-audit — 589 — Compliance divergences from the 2026-09-03 audit: what the canonical docs say the code does, and it does not · track=infra · effort=M · domain=compliance · brief=Cuatro documentos canónicos de cumplimiento describen lo contrario de lo que hace el código:
  • 591-account-and-ci-credential-hardening — 591 — Account and CI credential hardening: 2FA attested, one CI token split by scope, and what an automated attacker meets first · track=infra · effort=S · domain=infra · brief=Un solo token de Cloudflare en GitHub sirve a cinco workflows con permiso sobre Workers, D1 y R2:
  • 593-diastasis-self-check-guide-lead-magnet — 593 — Diastasis self-check guide: a fourth lead magnet on the guides page · track=post-mvp · effort=M · domain=other · brief=Gala, 2026-09-03: Hazlo. Apúntalo como ticket. Puede estar en nuestra página de guías. Una guía de…
  • 594-private-routes-gate-themselves-guardian — 594 — Guardian: every private route gates itself, member side included (the T585 class, generalised) · track=infra · effort=S · domain=auth · brief=Gala, 2026-09-03: De 585 sacamos un guardián para no volver a tener este problema en el futuro?. E…
  • 602-bo-support-reply-from-ticket — 602 — Answer a support message from its own screen, so the conversation lives where the policy can be kept · track=mvp · effort=M · domain=admin · brief=Responder a soporte desde su ficha en el BO: el email sale por Resend, la respuesta queda junto al m…
  • 616-legacy-symptom-questionnaires-per-phase — 616 — A short symptom questionnaire opens and closes every Legacy phase: the product’s own evidence · track=post-mvp · effort=L · domain=other · brief=Del contraste con la evidencia (T606): un cuestionario breve de síntomas (ICIQ-UI SF o PFDI-20, los …
  • 617-exercise-tags-in-the-database-and-back-office — 617 — Every exercise carries its granular tags in the database, and the Back Office shows them · track=post-mvp · effort=M · domain=content-migration · brief=La fundadora, 2026-09-04: `guardar todas las etiquetas de cada ejercicio en la base de datos… que se…
  • 624-legacy-open-outside-the-days-session — 624 — What the member opens outside the day’s session: the two self-measurements and the two free breathing practices · track=content-migration · effort=M · domain=content-migration · brief=T610 gave four Zenler videos a destination but not a home: the two F1 self-measurements and the two …
  • 627-legacy-counts-that-contradict-her-voice — 627 — The eleven Legacy counts where the clip says one number and the app asks for another · track=content-migration · effort=S · domain=content-migration · brief=T611 aligned the counts she had ruled on and wrote «cualquier cuenta sobre la que ella no se haya pr…
  • 628-legacy-phase-and-evaluation-intros-have-no-home — 628 — The phase and evaluation intro videos were cut and never given a home · track=content-migration · effort=S · domain=content-migration · brief=Tres vídeos de intro están cortados y sin ficha: la intro de la evaluación de F3, la intro de fase d…
  • 63-beta-program-design — 63 — Beta program design + execution (1-2 months free, polish before paid launch) · track=mvp · effort=M · domain=other · brief=Design and run a 1-2 month closed beta with non-paying users immediately before the paid launch.…
  • 631-sculpt-gym-hero-cta-under-the-fold — 631 — The Sculpt gym session pushes the hero CTA under the fold · track=polish · effort=S · domain=dashboard · brief=En Ritual Sculpt, modalidad Gimnasio, el botón de empezar queda 27 px bajo el pliegue en el móvil. S…
  • 632-no-gate-sees-contrast-on-a-control-behind-a-click — 632 — No gate can see contrast on a control that only exists after a click · track=infra · effort=M · domain=infra · brief=Salió de T633, el bug del selector de idioma invisible. Gala lo encontró mirando, no un gate —
  • 64-friction-stacks-content-loop — 64 — Friction stacks: compress the IG production loop from 15 to 5 steps · track=infra · effort=M · domain=other · brief=Reducir el coste cognitivo + de manos de producir 1 pieza de contenido (IG, blog, newsletter) de **~…
  • 641-one-calendar-month-helper-for-every-retention-sweep — 641 — Five copies of the same month arithmetic, and the same bug lived in all five · track=infra · effort=S · domain=infra · brief=El mismo cálculo de «resta N meses a hoy» está escrito cinco veces en el repo, y el mismo
  • 645-nothing-detects-two-specs-sharing-a-ticket-number — 645 — Nothing detects two specs sharing a ticket number · track=infra · effort=S · domain=infra · brief=El 06-09 hubo que renumerar seis veces la misma rama porque main le iba quitando los números
  • 646-social-login-apple — 646 — Social login: Apple (Sign in with Apple) · track=mvp · effort=M · domain=auth · brief=Añadir Continuar con Apple al registro, sobre el mismo carril que T170 abrió para
  • 647-google-consent-screen-carries-the-real-mark — 647 — The Google consent screen carries TheFittClub’s real mark · track=polish · effort=S · domain=auth · brief=La pantalla de Google donde una socia acepta entrar con su cuenta sale hoy sin logo,
  • 648-retire-the-dead-configs-from-the-abandoned-stack — 648 — Retire the dead third-party configs from the abandoned stack · track=infra · effort=XS · domain=infra · brief=Al montar el login con Google salió que la consola de Google Cloud sigue llena de restos
  • 649-the-contrast-gate-discards-resting-pseudos-in-silence — 649 — The contrast gate discards resting-state pseudo-classes in silence · track=infra · effort=XS · domain=infra · brief=El test que comprueba que una socia puede leer el selector de idioma sobre la cabecera
  • 650-the-locked-signup-button-never-says-what-unlocks-it — 650 — The locked CREAR MI CUENTA button never says what unlocks it · track=mvp, polish · effort=S · domain=auth · brief=En el registro, CREAR MI CUENTA sale apagado y no dice qué lo enciende. Salió del juez
  • 654-the-design-gate-never-runs-on-a-pushed-pr — 654 — fix: on a PR opened by the agent, the design gate never runs at all · track=infra · effort=S · domain=infra · brief=La auditoría de diseño solo corre al ABRIR una PR. Pero cuando la PR la abre el agente por
  • 656-nothing-stops-a-relative-image-url-leaving-our-pages — 656 — Nothing stops a relative image URL from leaving our own pages · track=infra · effort=XS · domain=infra · brief=getPublicUrl devuelve ahora una ruta relativa en vez de una dirección completa. Hoy no hay
  • 659-three-videos-carry-an-ai-generation-watermark — 659 — Three background videos carry a burned-in AI-generation watermark · track=mvp, polish · effort=S · domain=design · brief=Tres vídeos de fondo llevan grabada la estrella de cuatro puntas de la IA que los generó, y dos
  • 660-the-credential-scrub-test-runs-a-stale-copy — 660 — fix: the test guarding the credential scrub runs a stale copy of it · track=infra · effort=XS · domain=infra · brief=El test que dice comprobar el borrado de credenciales antes de escribirlas en un resumen público
  • 661-a-still-for-every-background-video-resolved-by-slot — 661 — fix: the auto-test goes black when the video host is blocked, and per-placement CSS cannot fix it · track=mvp, polish · effort=S · domain=design · brief=Las ocho pantallas del auto-test —una página pública de captación— salen en negro con el icono
  • 662-the-default-familys-third-question-is-carrying-the-failures — 662 — The default family’s third question is carrying the failures · track=infra · effort=M · domain=infra · brief=T651 midió la familia default y las dos pantallas puntuaron exactamente igual
  • 663-the-play-button-flashes-before-the-still-replaces-it — 663 — fix: the play button flashes for an instant before the still replaces it · track=mvp, polish · effort=S · domain=design · brief=Ella, probando T637 en su iPhone con Modo de bajo consumo, 2026-09-06: `funciona, pero en
  • 671-stale-consent-version-should-it-re-gate — 671 — Should a grant on a superseded consent version re-gate the Art. 9 features? · track=mvp · effort=S · domain=compliance · brief=Pregunta abierta que salió sola al cerrar T379, no un fallo: si una socia dio su
  • 673-the-marketing-consent-ledger-is-never-written — 673 — Nothing ever writes a marketing consent row, so the re-engagement email can never send · track=infra · effort=S · domain=compliance · brief=consent_log no tiene ni una fila de marketing — ni concedida ni retirada. Así que el
  • 674-bo-suppression-list-view — 674 — The suppression list is the authority on who we never write to, and nobody can look at it · track=infra · effort=M · domain=admin · brief=email_suppressions decide a quién no le escribes nunca, no la barre nadie, y no hay una sola
  • 675-campaign-then-lift-the-leads-hold — 675 — The campaign, and only then the leads hold comes off · track=infra · effort=M · domain=email · brief=El barrido ya borra en seis categorías; leads sigue en hold y esta es su pareja. Primero
  • 676-the-contrast-checker-passes-by-omission — 676 — The token contrast checker passes by omission on anything nobody wrote down · track=infra · effort=S · domain=infra · brief=Salió al minar --color-success-on-dark (T161 follow-up, PR #1603): el checker de contraste
  • 678-formatter-authority — 678 — Give the repo a formatter, so no session re-wraps code nobody asked it to · track=infra · effort=S · domain=infra · brief=Este repo no tiene formateador: ni prettier, ni script, ni regla de estilo. Cada sesión mete sus def…
  • 680-nothing-links-to-a-sale-until-checkout-exists — 680 — Nothing links to a sale until checkout exists · track=mvp · effort=S · domain=billing · brief=Suya, 2026-09-07, tras ver el recorrido de compra conducido de punta a punta: `aún no
  • 686-a-force-push-makes-the-pre-push-gate-say-it-checked — 686 — A force-push makes the pre-push gate say it checked when it did not · track=infra · effort=S · domain=infra · brief=Empujar tras un rebase hace que el pre-push diga «solo documentación» y se salte los gates, aunque…
  • 687-the-skill-usage-log-rides-in-every-reviewed-diff — 687 — The skill-usage log rides in every reviewed diff · track=infra · effort=S · domain=infra · brief=.claude/state/skill-usage-log.jsonl sale en el diff de casi toda PR: el pre-commit le añade líneas…
  • 688-the-recovery-queue-removed-the-wrong-button — 688 — The recovery queue takes the wrong button away without offering the right one · track=polish · effort=XS · domain=admin · brief=Dos observaciones que el tfc-design-reviewer dejó anotadas al cerrar T684, ninguna bloqueante:…
  • 691-dashboard-server-is-five-services-wearing-one-name — 691 — dashboard.server.ts is five services wearing one name · track=infra · effort=L · domain=dashboard · brief=dashboard.server.ts: 3.220 líneas, 17 dependientes y cinco dominios dentro — journal, completa…
  • 693-ci-internal-dedup-gates-vs-audit — 693 — ci.yml pays twice for the same answer (T537 phase 2) · track=infra · effort=S · domain=infra · brief=La fase 2 de T537, la única que quedaba con dinero dentro. Dos trabajos del mismo
  • 694-the-player-e2e-suite-has-never-run-against-a-slug-that-exists — 694 — The player E2E suite has never run against a slug that exists · track=infra · effort=S · domain=player · brief=Los 12 tests E2E del reproductor apuntan a rc-p1-legacy-s01, que es un ID, no un slug: la semi…
  • 695-sessioncanvas-is-a-second-reader-of-a-schema-the-player-already-serves — 695 — sessionCanvas.server.ts is a second reader of a schema the player already serves · track=infra · effort=S · domain=player · brief=575 líneas que leen las mismas tablas que el reproductor y a las que no llama ninguna pantalla: su ú…
  • 696-repo-layout-rules-without-a-gate — 696 — The rest of repo-layout.md: which rules nobody checks, and which are simply false · track=infra · effort=L · domain=infra · brief=T683 cerró una regla de repo-layout.md que nadie comprobaba y dijo que no fue a buscar
  • 698-a-program-cannot-say-coming-soon-only-on-or-off — 698 — A program can only say the journal is on or off, never “coming soon” · track=post-mvp · effort=M · domain=dashboard · brief=Ella, 2026-09-09: `Posiblemente, cuando se implemente la funcionalidad journal, deberemos
  • 700-email-funnels-follow-the-opening-of-sales — 700 — Email funnels follow the opening of sales · track=mvp · effort=M · domain=email · brief=Adaptar los emails de los funnels cuando se abran las ventas: revisar lo que prometen, a quién llega…
  • 701-broadcast-preview-follows-the-recipient-language — 701 — Broadcast preview follows the recipient language · track=mvp · effort=S · domain=email · brief=Poder revisar la versión española e inglesa de un broadcast antes de enviarlo, con el mismo idioma q…
  • 702-account-recovery-remembers-the-request-language — 702 — Account recovery remembers the request language · track=mvp · effort=M · domain=auth · brief=Responder en inglés a quien pidió recuperar su acceso desde el formulario inglés, aunque no se encue…
  • 704-bo-system-email-reference — 704 — Read every system email in the Back Office · track=polish · effort=M · domain=email · brief=Consultar en el Back Office qué correos envía el sistema, a quién, cuándo y para qué, con una entrad…
  • 706-mature-the-live-member-journey-before-expanding — 706 — Mature the live member journey before expanding the product · track=post-mvp, polish · effort=L · domain=analytics, other · brief=Suya, 2026-09-10: `crea ticket para que tras salir a producion podamos dar esa maduracion
  • 712-metodo-asks-for-ten-screens-on-a-phone — 712 — /metodo asks for ten screens of scroll on a phone · track=mvp · effort=L · domain=design · brief=/metodo mide 10,2 pantallas en un móvil y las cuatro fases son el 39% de eso. La fundadora lo dijo…
  • 715-descargar-gratis-does-not-say-it-costs-an-email — 715 — «Descargar gratis» does not say it costs an email · track=mvp, content-migration · effort=S · domain=design · brief=Hallazgo del juez de comprensión durante el QA de T714, no reportado por ella.
  • 716-the-fifty-three-frozen-drift-pairs — 716 — The 53 frozen drift pairs are measured, not resolved · track=infra · effort=L · domain=design · brief=T709 dejó de perseguir la deriva y la midió: 53 pares congelados entre app.css y el SSOT en la…
  • 717-the-shadow-family-cannot-decide-its-black — 717 — The shadow family cannot decide its black, and 133 declarations ignore it · track=infra, polish · effort=L · domain=design · brief=Trece tokens de sombra y dos negros distintos sin regla que diga cuál. Da casi igual: de las 194 som…
  • 718-the-handoff-rules-nobody-checks — 718 — The handoff package states four rules and enforces none of them · track=infra · effort=M · domain=infra · brief=Los cuatro defectos del paquete de diseño que salieron en T707 los cazó ella mirando un preview, no …
  • 720-the-design-handoff-still-draws-the-siguiente-card-t670-removed — 720 — The design handoff still draws the “Siguiente” card T670 removed · track=polish · effort=S · domain=design · brief=El taller de diseño y su copia en staging siguen dibujando la tarjeta «Siguiente» que T670 retiró (`…
  • 721-react-router-8-is-a-migration-not-a-dependabot-bump — 721 — React Router 7 → 8 is a migration, not a Dependabot bump · track=infra · effort=L · domain=infra · brief=Dependabot abrió tres PRs para subir React Router de 7.18.2 a 8.3.1 como bumps sueltos. No lo son: v…
  • 723-the-settle-gate-is-unsatisfiable-when-the-reviewer-does-its-job — 723 — The pre-QA settle gate is unsatisfiable exactly when the reviewer is doing its job · track=infra · effort=S · domain=infra · brief=Salió del cierre de T719, PR #1708. El
  • 724-two-gates-can-be-made-to-agree-with-the-change-they-are-judging — 724 — Two gates can be made to agree with the change they are judging · track=infra · effort=M · domain=infra · brief=Salió del QA de T719, PR #1708, y no lo
  • 725-mandatory-is-a-hardcoded-type-rule-not-a-back-office-field — 725 — Whether a document, audio or theory video is mandatory is a code rule, not a Back Office field · track=post-mvp · effort=M · domain=admin · brief=12-09: `Pensaba que el que un PDF fuera obligatorio o no era algo configurable, como con las técnica…
  • 726-the-library-has-no-shelf-for-the-documents-and-audios-she-unlocked — 726 — The library has no shelf for the documents and audios she has unlocked · track=post-mvp · effort=M · domain=dashboard · brief=12-09, tras ver los tres documentos de F1 vivir sólo dentro del reproductor: `me gustaría más adelan…
  • 727-training-data-foundation-from-first-session — 727 — Connect training prescriptions and observed practice from the first session · track=infra, mvp · effort=L · domain=analytics · brief=Preparar la recogida básica desde el primer entrenamiento: conectar qué sesión se ofreció, su versió…
  • 728-phase-advancement-from-traceable-training-evidence — 728 — Refine phase advancement using traceable training evidence · track=mvp · effort=L · domain=player · brief=Afinar el motor con datos de lo prescrito y lo realizado. Aprender técnicas y acumular constancia no…
  • 729-the-repo-still-points-at-a-desktop-that-moved — 729 — The repo still points at a Desktop that moved · track=infra · effort=S · domain=infra · brief=Los repos salieron del Escritorio a ~/code el 12-sep y 19 rutas absolutas del repo apuntan ya a un…
  • 732-a-new-common-string-reaches-her-as-a-raw-key — 732 — A new common string reaches an installed member as a raw key · track=mvp · effort=S · domain=infra · brief=El 2026-09-13, probando T731 en el móvil, la pantalla enseñó PDF.PAGE_MARK en vez de `Página 1 · d…
  • 733-member-pricing-signal-and-named-free-seats — 733 — Member pricing asks a column nobody fills, and a free seat has no name · track=mvp · effort=M · domain=billing · brief=El 5% de socia se decide por user_purchases.amount > 0, y en producción esa columna vale 0 en las …
  • 736-an-agent-can-widen-its-own-authority-unreviewed — 736 — fix: an agent can widen its own authority and nothing stops the merge · track=mvp · effort=S · domain=infra · brief=La fundadora, el 2026-09-13, revisando la seguridad de T722: `necesito que tomes las medidas
  • 737-the-week-card-says-what-does-not-subtract-and-never-what-does — 737 — fix: the week card says what does NOT subtract and never what does · track=mvp · effort=XS · domain=dashboard · brief=De la lectora 5 del juez de comprensión, ronda 7, que es exactamente la mujer a la que le pasa:
  • 738-the-phase-card-clips-her-phase-counter-on-every-phone — 738 — fix: the phase card clips «Fase 1 de 6» on every phone it is read on · track=mvp · effort=S · domain=dashboard · brief=Medido, no estimado, el 2026-09-13 mientras T722 pasaba la rúbrica de diseño: en la tarjeta de fase,
  • 739-the-empty-dashboard-promises-a-capsule-the-catalogue-does-not-have — 739 — fix: the empty dashboard promises a welcome capsule the catalogue does not have · track=mvp · effort=S · domain=dashboard · brief=Encontrado por Gala en producción, 2026-09-13, en la auditoría manual del criterio 12 de
  • 740-measure-the-video-invocation-share — 740 — Measure what video actually costs the Worker, before moving it anywhere · track=infra · effort=M · domain=infra · brief=En T730 el vídeo salió del alcance: moverlo lo dejaba en un host ajeno, y España bloquea eso. Su mot…
  • 744-deploy-serves-code-whose-schema-is-not-there — 744 — Deploy serves code whose schema is not there · track=infra · effort=L · domain=infra · brief=Ella, 2026-09-14, al abrir el Back Office: tenemos el admin de produccion roto. Séptima
  • 745-the-drift-report-lands-where-she-looks — 745 — The migration-drift report lands where she looks · track=infra · effort=S · domain=admin · brief=Ella, 2026-09-12, sobre otro aviso: `yo no quiero ese aviso, porque me llegan mil cosas de
  • 746-alerting-is-dimensioned-for-volume — 746 — Alerting is dimensioned for volume, so a fully-broken route goes quiet as traffic grows · track=infra · effort=M · domain=analytics · brief=El aviso de errores existe y mide porcentaje sobre todo el tráfico. Eso funciona hoy con
  • 747-the-other-back-office-loaders-were-never-audited — 747 — The other Back Office loaders were never audited for the shape T743 fixed · track=infra · effort=M · domain=admin · brief=T743 arregló una lectura que podía tumbar el panel entero. Hay 68 rutas de Back Office
  • 749-preflight-and-ci-disagree-about-coverage — 749 — preflight and CI disagree about coverage, so the local gate trains you to trust it wrongly · track=infra · effort=S · domain=infra · brief=Gala, 2026-09-14, preguntando cómo dejaría la app un arquitecto senior para una auditoría de
  • 750-a-doc-only-head-commit-leaves-a-pr-with-no-checks — 750 — A doc-only head commit leaves a PR with zero checks and a pending status · track=infra · effort=S · domain=infra · brief=Gala, 2026-09-14: la app tiene que pasar una auditoría de salida a bolsa. Un PR cuya última
  • 751-a-control-that-cannot-run-is-indistinguishable-from-one-that-passes — 751 — A control that cannot run is indistinguishable from one that passes · track=infra · effort=M · domain=infra · brief=Gala, 2026-09-14, sobre estar lista para una auditoría. El monitor de bloqueo español lleva
  • 752-the-egress-backstop-reports-where-nobody-is-looking — 752 — The egress backstop reports into a Worker log nobody watches · track=infra · effort=S · domain=infra · brief=Gala, 2026-09-14. El respaldo de salida que acaba de entrar avisa en producción en vez de
  • 753-the-download-token-travels-in-a-query-string — 753 — The guide download token travels in a query string · track=infra · effort=L · domain=infra · brief=Gala, 2026-09-14, sobre estar lista para una auditoría de salida a bolsa. El enlace de descarga
  • 754-the-ai-reviewer-spends-its-budget-on-files-the-pr-does-not-contain — 754 — The AI reviewer spends its budget on files the PR does not contain · track=infra · effort=S · domain=infra · brief=Gala, 2026-09-14, decidiendo el paso 8 de la PR #1747 como lo haría un arquitecto senior con
  • 755-step-8-has-no-defined-way-to-pass-other-than-the-tool-agreeing — 755 — Step 8 has no defined way to pass other than the tool agreeing twice · track=infra · effort=S · domain=infra · brief=Gala, 2026-09-14, sobre decidir como un arquitecto senior con una auditoría de salida a bolsa
  • 756-the-invocations-script-dies-on-a-field-cloudflare-removed — 756 — The invocations script dies on a field Cloudflare removed, and blames the token · track=infra · effort=S · domain=infra · brief=Gala, 2026-09-14, preparando la batería para cerrar lo que se pueda cerrar. `T730 lleva desde
  • 757-a-returning-visitor-receives-an-obsolete-document — 757 — A returning visitor receives an obsolete document · track=infra · effort=M · domain=infra · brief=Evitar que una visitante que vuelve vea Método sin estilos o navegación antigua después de un despli…
  • 758-the-self-assessment-hides-why-submission-failed — 758 — The self-assessment hides why submission failed · track=polish · effort=S · domain=onboarding · brief=Mostrar qué ha fallado al enviar el auto-test y cuánto esperar si se alcanza el límite, conservando …
  • 759-keyboard-focus-reaches-the-hidden-shopping-bag — 759 — Keyboard focus reaches the hidden shopping bag · track=polish · effort=S · domain=design · brief=Al abrir preferencias de cookies con teclado, llevar el foco al panel visible y evitar que pase por …
  • 760-password-reset-email-and-landing-use-different-locales — 760 — Password reset email and landing use different locales · track=polish · effort=S · domain=email · brief=Acordar un idioma coherente entre la solicitud, el correo y la página de nueva contraseña, sin cambi…
  • 761-direct-image-upload-selects-an-unusable-reference — 761 — Direct image upload selects an unusable reference · track=polish · effort=S · domain=admin · brief=Corregir la carga de portadas del BO: anunció éxito, pero hubo que volver a elegir la imagen desde l…
  • 762-restrict-training-extraction-without-removing-public-discovery — 762 — Restrict training extraction without removing public discovery · track=infra · effort=M · domain=infra · brief=Reducir la extracción automatizada para entrenamiento, manteniendo las páginas públicas encontrables…
  • 763-security-validation-becomes-a-repeatable-regression-suite — 763 — Security validation becomes a repeatable regression suite · track=infra · effort=M · domain=infra · brief=Convertir las reproducciones locales en pruebas mantenidas: deben fallar con el código vulnerable y …
  • 764-verified-mailbox-authority-for-lead-mutations — 764 — Verified mailbox authority for lead mutations · track=infra · effort=L · domain=auth · brief=Crear una comprobación del correo reutilizable: conocer una dirección no debe autorizar cambios ni r…
  • 765-pregnancy-withdrawal-survives-anonymous-submissions — 765 — Pregnancy withdrawal survives anonymous submissions · track=infra · effort=M · domain=compliance · brief=Una petición anónima no puede deshacer una baja de embarazo ni renovar el consentimiento. La reactiv…
  • 766-anonymous-lead-submissions-cannot-rewrite-an-existing-contact — 766 — Anonymous lead submissions cannot rewrite an existing contact · track=infra · effort=L · domain=email · brief=Impedir que otra persona cambie nombre, idioma, segmentación o estimaciones de un contacto usando so…
  • 767-public-guide-flow-cannot-disclose-contact-history-or-assessment — 767 — Public guide flow cannot disclose contact history or assessment · track=infra · effort=L · domain=auth · brief=Cerrar la cadena guía → identificador → estimaciones: la respuesta pública no debe revelar historial…
  • 768-email-auth-throttling-admits-attempts-atomically — 768 — Email authentication throttling admits attempts atomically · track=infra · effort=L · domain=auth · brief=Evitar que intentos simultáneos esquiven el límite por correo. Medir cuántos llegan a autenticación …
  • 769-security-remediation-release-and-evidence-closeout — 769 — Security remediation release and evidence closeout · track=infra · effort=M · domain=infra · brief=Cerrar la revisión con pruebas independientes, despliegue controlado y evidencia por hallazgo. Una P…
  • 770-revalidate-media-expiry-and-webhook-claims-separated-from-session-revocation — 770 — Revalidate media expiry and webhook claims separated from session revocation · track=infra · effort=M · domain=infra · brief=Conservar por separado los antiguos puntos de T588 sobre caducidad de medios y webhook, sin retrasar…
  • 774-support-copy-sells-to-the-member-and-overstates-the-inbox — 774 — The support page sells the method to a member who already bought, and claims an inbox that does not exist · track=mvp, polish · effort=S · domain=content-migration · brief=/es/soporte se pinta en dos estados y el copy solo está pensado para uno. El héroe y el
  • 776-the-phase-card-counts-phases-nobody-configured — 776 — The dashboard loader fabricates a phase for a ritual it never chose · track=mvp, polish · effort=M · domain=dashboard · brief=Fase 1 de 6 para novata con Ritual Core a 4 fases. El loader fabrica fase, sesiones y objetivo c…
  • 777-a-login-that-fails-on-the-network-says-nothing — 777 — A login that fails on the network says nothing · track=mvp · effort=S · domain=auth · brief=iPhone, /es/registro, 18-09: el fetch del login cayó en la red (TypeError: Load failed), el bo…
  • 778-a-forwarded-server-error-keeps-its-cause — 778 — A forwarded server error keeps its cause · track=infra · effort=S · domain=analytics · brief=224 de los 270 eventos de producción del inventario de T771 son DrizzleQueryError cuyo mensaje es …
  • 787-the-board-line-every-parallel-pr-fights-over — 787 — The board line every parallel PR fights over · track=infra · effort=M · domain=infra · brief=Dos PRs en paralelo, cuatro conflictos el 18-09 y ninguno de código: siempre **Last updated:** y e…
  • 789-the-ai-reviewer-reads-the-spec-it-is-reviewing-against — 789 — The AI reviewer reads the spec it is reviewing against · track=infra · effort=S · domain=infra · brief=En #1767 la review IA preguntó tres rondas lo que el spec respondía desde la segunda: no ve `_docs/*…
  • 790-player-rounds-and-series-from-the-rows — 790 — The player names the round and the series from the rows, not from a repeat counter · track=mvp · effort=M · domain=player · brief=Las sesiones de F2/F3 llevan cada vuelta escrita fila a fila y el player ya no dice «Ronda 2 de 3». …
  • 792-asset-placement-has-one-name-not-three — 792 — An asset placement has one name, not three · track=infra · effort=L · domain=schema · brief=Una foto del BO se llama hoy de tres formas a la vez y la fundadora las ve las tres en el desplegabl…
  • 793-materials-int-to-text-pk-migration — 793 — materials INT→TEXT PK migration (mat_<slug>) · track=infra · effort=M · domain=schema · brief=Migrate materials from an autoincrement INT PK to descriptive TEXT IDs
  • 794-recorded-minutes-fall-back-to-every-mode-sum — 794 — Fix: the minutes recorded for a finished session fall back to the every-mode sum · track=infra · effort=XS · domain=dashboard · brief=Los minutos apuntados a una sesión terminada caen a la suma de los tres modos cuando el servidor no …
  • 795-seed-password-env-leaks-between-test-files — 795 — fix: the seed-password env vars leak from one test file into the next · track=infra · effort=S · domain=infra · brief=Tres tests de semillas dejan SEED_ADMIN_PASSWORD puesta y no la restauran; otros dos sí, cada uno …
  • 796-dashboard-card-progressive-version-hides-its-null — 796 — Fix: the dashboard card’s progressiveVersion hides its null behind a plausible 1 · track=infra · effort=XS · domain=dashboard · brief=En un día sin Progresiva la tarjeta dice que el escalón es el 1, y la verdad es que no hay escalón. …
  • 797-chip-minutes-depend-on-who-is-looking — 797 — Fix: the minutes a chip advertises depend on who is looking at it · track=infra · effort=XS · domain=dashboard · brief=Dos socias abren el panel el mismo día, con la misma sesión, y el chip de Base les puede decir minut…
  • 798-duration-numbers-say-which-number-they-are — 798 — A duration number says which duration it is, so a caller cannot pick the wrong one · track=infra · effort=S · domain=infra · brief=Tres tickets seguidos (T794, T796, T797) son la misma equivocación: coger «la suma de los tres modos…
  • 799-the-seed-banner-names-two-phases-and-emits-three — 799 — Fix: the seed banner names two phases and emits three · track=infra · effort=XS · domain=infra · brief=El SQL sembrado lleva un rótulo que dice «fases 2 y 3» cuando el emisor también escribe la 4. Se dif…
  • 800-two-binding-contracts-no-ci-can-check — 800 — Two binding contracts that no CI run can ever check · track=infra · effort=S · domain=infra · brief=Dos reglas vinculantes (R-T780-5, R-T783-6) dicen que los módulos de fases salen del generador. Esa …
  • 801-verify-generated-markers-round-trip — 801 — A file that says “GENERATED by” is trusted, never checked · track=infra · effort=M · domain=infra · brief=Desde T785, un fichero bajo drizzle/ con la cabecera GENERATED by … se excluye de la revisión IA…
  • 802-settle-gate-carve-out-by-content — 802 — The settle gate excuses a file by its path, never by what changed in it · track=infra · effort=S · domain=infra · brief=El Paso 8 perdona un commit que solo toca _docs/** o *.md porque la documentación no se re-revis…
  • 803-a-first-login-becomes-a-first-session — 803 — A first login becomes a first session: activation of the migrated cohort · track=mvp · effort=M · domain=dashboard · brief=La oleada salió el 17-09: entraron 19 socias legacy y 18 no han entrenado. Ningún ticket convier…
  • 804-a-performance-budget-per-route-before-optimising-anything — 804 — A performance budget per route, before optimising anything · track=infra · effort=S · domain=infra · brief=El 20-09 llegaron dos avisos con p95 de 1398 y 1570 ms contra un umbral de 1000, y ese número no tie…
  • 807-count-the-deploys-that-strand-a-member — 807 — Count the deploys that strand a member, before fixing them · track=mvp · effort=XS · domain=infra · brief=El 21-09 una socia dijo Cuando le doy a comenzar no se activa. Hay un camino en React Router
  • 808-a-deploy-never-strands-a-running-client — 808 — A deploy never strands a running client · track=mvp · effort=M · domain=infra · brief=Que una socia se quede con un botón muerto porque desplegamos mientras ella tenía la app
  • 809-a-forbidden-tells-her-we-broke-something — 809 — A “no puedes entrar aquí” tells her we broke something · track=mvp · effort=S · domain=design · brief=Si entra donde no le toca, le decimos `Algo se rompió por aquí. No es por algo que hayas hecho.
  • 810-the-admin-500-nobody-can-diagnose — 810 — The admin 500 nobody can diagnose · track=infra · effort=S · domain=admin · brief=El 14-09, a las 11:47 de la mañana, /admin dio error cuatro veces en menos de dos minutos.
  • 816-every-form-is-checked-against-its-schema-without-a-fixture — 816 — Every form is checked against its schema, without a fixture · track=infra · effort=S · domain=infra · brief=Que el lint de T812 compare, en cada formulario de las 21 rutas con _intent, los campos que en…
  • 821-a-gap-with-a-ticket-number-accepts-itself — 821 — A gap with a ticket number accepts itself: the founder decides defects and design, not each gap · track=infra · effort=M · domain=infra · brief=La parada cuenta defect; el recibo clean exige cero gap, y cada gap esperaba una lista. Un gap…

§10 — Recently shipped (last 10 by mtime)

  • 89-lint-board-blockers-regex-false-positives — 89 — lint-board-blockers regex false positives on dates and filename slugs · track=infra · effort=XS · domain=other (maintenance tooling)
  • 90-pre-commit-hookspath-and-board-lint-coverage — 90 — Pre-commit hooksPath auto-wire + board lint coverage · track=infra · effort=XS · domain=other (maintenance tooling)
  • 91-pr-subscription-poll-back-protocol — 91 — PR subscription poll-back protocol · track=infra · effort=XS · domain=other
  • 92-circular-evolutionmodal — 92 — Resolve EvolutionChartsPanel ↔ ui/index.ts circular import · track=infra · effort=XS · domain=dashboard
  • 93-a11y-retrofit-jsx-controls — 93 — A11y retrofit: tighten jsx-a11y warnings to errors · track=mvp · effort=L · domain=other · brief=Retrofit the existing 211 TSX files in app/ so the five jsx-a11y rules that T50 had to ship at `wa…
  • 94-breakpoints-tailwind-default-contract — 94 — Breakpoints: Tailwind default contract · track=infra · effort=S · domain=other
  • 95-materials-unified-player-service — 95 — Materials: unified Player-ready service + migrate call-sites · track=mvp · effort=M · domain=player
  • 96-td007-drop-legacy-routines-table — 96 — TD-007: drop legacy routines table + dead material_slugs column · track=infra · effort=S · domain=schema · brief=Cerrar TD-007 dropeando la tabla legacy routines (y su hija routine_exercises) junto con la colu…
  • 97-rebrand-auth-surfaces — 97 — Rebrand: auth surfaces (signup / login / reset-password) · track=mvp · effort=L · domain=auth, public · brief=Aplicar el rediseño del MVP a las superficies de auth pública (signup, login, reset-password, recove…
  • 98-rebrand-nav-footer — 98 — Rebrand: global navigation + footer · track=mvp · effort=M · domain=global UI · brief=Aplicar DESIGN.md v5 al shell global (header + footer) que aparece en toda ruta pública y autenticad…

§11 — Outreach metrics


description: Cumulative metrics for non-dev work (outreach pillars). Updated manually as each piece is delivered. Read by the vault dashboard generator to surface counters alongside the dev MVP metrics.

Outreach metrics — TheFittClub

Convention: add one row per completed piece. The generator counts non-placeholder rows per section. Do not delete rows (history matters); to retire a piece, mark its row with [retired YYYY-MM-DD] in the notes column.


Production model — one topic, four outputs

Critical context (2026-05-13): Instagram has been the single source of every paying customer to date. It is the primary acquisition channel, not a complement. The production model is therefore one topic → quadrant of coordinated outputs:

ChannelOutput per topicCadence
Instagram≥1 post (carousel / reel) + stories roundevery topic — primary channel
Blog1 article (1500-2500 words) at /blogevery topic
Newsletter1 email (600-900 words, links to blog)every topic
YouTube1 video (5-15 min, uses pro setup: cameras / mics / lights already available)every topic once the YouTube cadence starts

The four outputs share the same topic anchor, voice, and editorial guardrails. They reinforce each other and amortize the research/scripting cost across four channels. Tracker covers all four below.


Instagram posts published

The vital channel — 100% of historical conversions came from here. Reactivation is non-negotiable.

#DatePillarFormat (reel / carousel / single / story-set)TopicSavesNotes
(none yet — first row when IG reactivation starts; see T62 cross-channel workflow)

YouTube videos published

Long-form companion to each topic. The pro setup is already in place (cameras, mics, lights). Starts once the editorial cadence stabilizes (post-T62 activation).

#DatePillarTopicDurationViewsNotes
(none yet — placeholder; first video targets one topic also covered by IG + blog + newsletter the same week)

Newsletter emissions

#DatePillarTitleOpen rateClick rateNotes
(none yet — first emission targets H4 in mvp-scope.md → Outreach pillars; depends on T62)

Blog articles published

#DatePillarSlugWord countNotes
(none yet — first article ships under T53; one article per pillar in the first month)

Lead magnet downloads

Aggregated per week (cohort signal — not per-user). Captured from Resend webhooks or analytics dashboard (T55).

Week startingDownloadsPillar (if magnet themed)Notes
(none yet — first row when T61 lead magnet goes live on T36 landing)

Beta sessions completed

Survey + interview interactions during the closed beta (T63). One row per interaction, not per tester.

#DateTester IDType (survey/interview/incident)NPSNotes
(none yet — first row when T63 beta program activates)

How the generator counts

The dashboard generator parses this file and counts the non-placeholder rows in each section’s table. Rows that start with | _(none yet or with the header row pattern are skipped. To add a tracked entry, replace or insert above the placeholder line with a real row in the table’s format.

How to update this file

  1. After publishing a newsletter / blog article / running a beta session, append a row to the matching section.
  2. Use the exact column structure shown — the parser is strict about column counts.
  3. Push to main. The vault dashboard updates automatically on next sync (via .github/workflows/sync-vault-dashboard.yml).
  4. Periodically (monthly suggested) review the cumulative counts and the resulting cadence — if you’re below target on a pillar, that’s a calibration signal to adjust the newsletter schedule or topic mix.