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
- Voice & vocabulario
- Brand & posicionamiento (incluye ancla experiencial)
- Design system & rúbrica de evaluación
- Product law (Rituales / Módulos / Cápsulas)
- Strategy
- Founder context (privado) — (not bundled — file absent in repo)
- Active tickets — full specs
- QA tickets — full specs
- Pending backlog — summary (top of queue)
- Recently shipped — summary
- Outreach metrics — current state
§1 — Voice & vocabulario
description: Voz y tono de Gala Calero para TheFittClub. Guía práctica para que cualquier IA o colaborador escriba como la fundadora. Define el estilo, el vocabulario legal, ejemplos reales y un prompt base para generación de contenido.
Sistema de documentos del proyecto:
- Identidad de marca y experiencia emocional:
thefittclub-brand.md- Producto y arquitectura técnica:
thefittclub-product.md- Estrategia de lanzamiento y crecimiento:
thefittclub-strategy.md- Sistema de diseño visual:
thefittclub-design.md
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
3.2 Prohibido (riesgo legal y de marca)
Nota técnica: el linter
content-legal-check.mjshace 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 de | Usar |
|---|---|
| ”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 enorgullecerse | Urgencia 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 sostenible | Infantilizar 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:
diastasis— el dolor más buscadosuelo_pelvico— el más guardado en formato educativorecuperacion_postparto— el más ampliobarriga_postparto— el más emocionalcesarea— audiencia muy fiel y agradecidahipopresivos— 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 IG | DM | Vídeo curso | |
|---|---|---|---|
| Longitud | Media, estructurada | Corta, directa | Larga, rítmica |
| Persona | Gala → vosotras | Gala → tú | Gala + nosotras juntas |
| Tono | Pedagógica + CTA | Clínica + empática | Corporal + íntima |
| Mecánica | Explica el por qué | Resuelve el problema | Guía el cuerpo en tiempo real |
| Imperfección | Oculta | Honesta | Visible y usada como recurso |
| Metáforas | Pocas | Ninguna | Centrales (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.mddefine 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.mddefine las reglas de negocio y arquitectura. Este documento define cómo se comunican esas reglas a la usuaria.thefittclub-strategy.mddefine 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:
-
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”.
-
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…“.
-
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
| Severidad | Comportamiento | Categorías |
|---|---|---|
| ERROR | Bloquea siempre (pre-commit + CI) | Compuestos cliché + verbos imperativos de poder (ES + EN) |
| CAUTION | Bloquea solo bajo TFC_VOCAB_STRICT=1 | Adjetivos hiperbólicos |
Patrones de sustitución recomendados
| Frase prohibida | Alternativa 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:
- Producto y arquitectura técnica:
thefittclub-product.md- Voz y tono de la fundadora:
thefittclub-voice.md- Estrategia de lanzamiento y crecimiento:
thefittclub-strategy.md- Sistema de diseño visual (tokens + rúbrica):
thefittclub-design.md
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.
| Variante | Quién es | Lo que busca |
|---|---|---|
| Sin maternidad | Nunca ha sido madre. Quiere cambiar su composición corporal. | Método con progresión real, no rutinas genéricas. |
| Postparto reciente | 0–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ños | 3+ años desde el parto. Nunca recuperó el cuerpo preparto. | Saber que aún es posible. Método, no resignación. |
| Pre-embarazo | Planea 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 templates | SaaS genérico frío. Sin calidez, sin personalidad, sin cuerpo. |
| Apps médicas / clínicas | La estética clínica activa el miedo, no la confianza. |
| Headspace / Calm | Demasiado blando, demasiado new-age. Paleta pastel + mindfulness genérico. |
| Lululemon / Nike Women | Athleisure 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.
- Precisión antes que emoción. La emoción es el envoltorio, no el contenido.
- La usuaria es inteligente. Nunca se le habla con condescendencia.
- 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.
- La belleza es consecuencia de la salud estructural. La cintura, el abdomen, la seguridad — vienen como resultado, no como promesa.
- El lujo está en los detalles, no en la decoración. Lo superfluo no es lujo: es ruido.
- 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.
- TheFittClub no es para todas. Y no intenta serlo.
- 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:
- Producto y arquitectura técnica:
thefittclub-product.md- Identidad de marca, ancla experiencial y metodología:
thefittclub-brand.md- Implementación de tokens y componentes:
DESIGN.md(raíz del repo)- Voz y tono de la fundadora:
thefittclub-voice.md- Estrategia:
thefittclub-strategy.md
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@themedentro 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 enapp/styles/app.css). - Utilidad
.dashboard-section-anchorpara 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-heightno mide la cabecera real. Dice 52px/64px;.appbarrenderiza ~65px (padding 12px ×2 + control de 40px + hairline). Sirve parascroll-margin, NO para posicionar contra ella — usa flujo y deja que el layout mida.
Reglas para contribuciones UI
- No inventar colores fuera del
@themesalvo transición documentada en este archivo y reflejada enapp/styles/app.css. - Mobile-first; la experiencia debe sentirse “app” coherente con la promesa de marca (ver brand §8).
- 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:
- Identidad de marca y experiencia emocional:
thefittclub-brand.md- Voz y tono de la fundadora:
thefittclub-voice.md- Estrategia de lanzamiento y crecimiento:
thefittclub-strategy.md- Sistema de diseño visual:
thefittclub-design.mdDocumentos técnicos complementarios:
- Pipeline de catálogo y datos editoriales:
thefittclub-private-catalog-data.md
🏆 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_voucherscode 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_statefor 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
progressivemodality, 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 thealternative_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.waitUntilto 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_modalitiesrow 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, isdomain-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 elegirexpress una versión muy reducida para la que quiera hacer algo ese día y no tiene tiempoprogresiva 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):
baseis the Legacy session unchanged. Ritual Core is not a second catalogue.expressandprogresivaare derivations of that session, never separate content.progresivagrows in intensity — series and repetitions — each time the same session is repeated (Layer 2 §2, T565); it does not change which session she does.- 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 exist | Ticket |
|---|---|---|
| 1 | The 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 caller | T565 |
| 2 | The progress-photo lock the documentation promises, expressed against the single banked-weeks counter, enforced server-side, first photo never blocked | T566 |
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 forwardprod_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, slugmembresia-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-inicialis a member ofACCESS_GRANTING_MEMBERSHIPSinapp/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.tsxgroups the membership filter into active/inactive, andadmin.payments.$id.tsxappends 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_MEMBERSHIPScontainingritual-core-inicialmeant 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_MEMBERSHIPis"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 inapp/lib/domain/legacy-membership.ts; the paid-in-full math issummariseFulfilment(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)
- Loader-First: Data fetching belongs in RRv7 loaders. No client-side
useEffectfor initial data. - D1 Relational Purity: No JSON arrays for core relations. Use junction tables and normalized rows (e.g.
member_conditionskeyed offphysical_profiles,exercise_materials, phase schedule links). - Compound Keys: Use composite primary keys where appropriate for idempotency (e.g.
product_user_progress:user_id+product_id; onboarding:product_id+question_id). - Edge runtime in Workers: Request handlers and loaders must stay Edge-safe: no Node-only
fs/path/ Nodecryptoin app code bound to Workers. Tooling (catalog sync, seeds, Drizzle kit) may use Node locally; keep those scripts out of Worker bundles (seedrizzle/seeds/*). - 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 + barrelindex.ts). - [2026-04-26] Docs: Dual catalog pipeline documented — relational canvas + legacy
routinesTS sync (thefittclub-private-catalog-data.md). - [2026-04-26] Docs: Brand identity documentation system established — see
thefittclub-brand.mdand 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:
- Identidad de marca y experiencia emocional:
thefittclub-brand.md- Producto y arquitectura técnica:
thefittclub-product.md- Voz y tono de la fundadora:
thefittclub-voice.md- Sistema de diseño visual:
thefittclub-design.md
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 en15_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)
| Hito | Conservador | Moderado (base) | Plan original |
|---|---|---|---|
| Mes 1 | 5 clientas / 700€ | 10 clientas / 1.400€ | 20 clientas / 2.360€ |
| Mes 3 | 24 clientas / 3.000€ | 40 clientas / 5.100€ | 48 clientas / 7.615€ |
| Mes 6 | 63 clientas / 8.200€ | 104 clientas / 13.500€ | 109 clientas / 17.300€ |
| Mes 9 | 107 clientas / 13.800€ | 176 clientas / 22.800€ | 180 clientas / 28.500€ |
| Mes 12 | 142 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)
| Etapa | Sin voces | Con 1-2 voces (impacto esperado) |
|---|---|---|
| Apertura email blast | 18 % | 20-22 % |
| Signup a Cápsula (sobre aperturas) | 8 % | 10-12 % |
| Completado Cápsula | 55 % | 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
| Herramienta | Rol | Detalle |
|---|---|---|
| Claude Code (remoto en claude.ai/code y local) | Único entorno de desarrollo | Trabaja 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 modelo | i18n, 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, estrategia | opus 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, estrategia | Tareas 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:
- Idea → spec en
01-pending/(harness00-new-ticket.md). - Activación →
02-active/con contrato cerrado. - Implementación: en un
fix:el test de regresión lo escribe un subagente y se confirma en rojo antes del arreglo. - Verificación en navegador con la app local sembrada antes de abrir el PR.
- QA: contrato de regresión + teatro ejecutado; rúbrica de diseño y juez de comprensión en superficies de socia.
- PR con CI y revisión de IA en verde; la fundadora fusiona (o el agente, si el diff es solo prosa).
- Cierre: spec bloqueado en
04-done/.
text
4.2 Producción de contenido
| Herramienta | Rol |
|---|---|
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-E10 | Grabaciones nuevas (guía en 40_Contenido_Redes/Guia_Grabacion_ZV-E10.md). |
| Obsidian | Centro 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
| Herramienta | Rol |
|---|---|
| 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 + Resend | Email transaccional (alta, verificación, recuperación) desde el día 1; el mismo Resend sirve los broadcasts del BO. |
4.4 Soporte
| Herramienta | Rol |
|---|---|
| Sistema de tickets simple | Formulario en la web con acuse de recibo automático: “Te responderemos en menos de 24 horas.” |
| FAQs anticipadas | 5-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.
- 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í.
- Educación (formato largo): YouTube (§5.3), SEO (§5.4) y el email como infraestructura (§5.6).
- 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.
- 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
esyen). 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íodo | Posts/semana |
|---|---|
| Semanas 1-2 | 2 |
| Semanas 3-4 | 3 |
| Semanas 5-8 | 4 |
| Semanas 9-12 (pre-lanzamiento) | 5 |
Proporciones de contenido:
| Tipo | % | Objetivo | Tono |
|---|---|---|---|
| Gancho estético | 40% | Guardados/viralidad | Visual, dewy, piel luminosa, luz lateral |
| Explicación técnica | 30% | Autoridad | Preciso, sin condescendencia, seguridad de ingeniera |
| Detrás de cámaras | 20% | Conexión | Cercano pero no informal, mostrando el estándar de exigencia |
| Testimonial | 10% | Prueba social | Mujeres 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ón | Descuento amiga | Puntos para la embajadora |
|---|---|---|
| Amiga compra Ritual Semestral | 10% (-35€) | 100 pts |
| Amiga compra Ritual Anual | 10% (-50€) | 300 pts |
| Amiga compra Módulo | 10% (-10€) | 50 pts |
| Amiga compra Cápsula | 10% (-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.mdPasos 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
| Producto | Precio | Modelo | Disponibilidad |
|---|---|---|---|
| Cápsula Cero | 0€ | Lead magnet | Día 1 |
| Ritual Semestral | 347€ | 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 checkout | Días 4-7 |
| Ritual Anual «Fundadora» | 497€ | Suscripción anual, precio congelado mientras renueve | Día 1 |
| Cápsula corta | 47€ | Pago único | Mes 3 |
| Cápsula extendida | 67€ | Pago único | Mes 6 |
| Módulo focalizado | 97€ | Pago único | Mes 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
| Concepto | Trimestral 197€ | Urgencia 147€ | Anual 497€ |
|---|---|---|---|
| Precio | 197€ | 147€ | 497€ |
| Stripe comisión (3%) | -5,91€ | -4,41€ | -14,91€ |
| Neto por venta | 191,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
- Calentar la lista antes del blast.
- Urgencia real, no artificial.
- Completado de Cápsula como métrica crítica.
- Retención trimestral: email de renovación en día 85-87, con datos reales de progreso.
- Upsell Cápsula Corta (mes 3).
- Sembrar el ecosistema futuro desde la comunicación.
- Doble mercado desde el día 1: El bilingüismo duplica el mercado potencial sin duplicar el coste de producción.
- 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étrica | Conservador | Moderado | Alto |
|---|---|---|---|
| Signup Cápsula / semana | < 20 | 40-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:
- Tech Beauty: Primer dispositivo físico con parámetros preconfigurados por Gala.
- Expansión angloparlante: El mercado US/UK ya está sembrado desde el día 1 con YouTube y contenido bilingüe.
- 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.mdyAI_PROTOCOL.mden 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)
- Calidad sobre calendario. Si el contenido no está listo, se retrasa el lanzamiento.
- Bilingüismo fundacional. Todo se publica en ES y EN desde el día 1.
- Stripe antes que cualquier feature premium.
- Calentar la lista antes del blast.
- Completado de Cápsula es la métrica más importante.
- El Club de Embajadoras es el motor de adquisición orgánica.
- No añadir herramientas que no reduzcan tiempo de producción de Gala.
- El churn se gestiona en el email de la semana 8-10.
- Cada punto de contacto debe reflejar la identidad de marca.
- La marca no juzga ni presiona.
- TheFittClub no es para todas.
- 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 siestá usando sesión pero agresiva porque está en ritual Core y ha usado la progresiva nose 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):
| Level | Founder’s example | PROGRESSION_MATRIX today, on the real config |
|---|---|---|
| 1 | 2 series × 6 reps | 2 × 6 (loopMult 1, amountMult 1.0) — matches |
| 6 | 3-4 series × 15 reps | 6 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:
| Product | Modalities | Progressive? | Members |
|---|---|---|---|
prod_ritual_core_legacy | 1 (standard) | No (is_progressive = 0) | 64 |
prod_ritual_core | 4 | Yes | 1 |
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:
- 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 withsession_blocks.progression_level(migration0092) 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 contradictla dosis por serie se conserva, andprogressive-overload.tsis a different model again. This ticket does not wake either. - 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 belowExigente. A demanding session or an unanswered question holds the dose.app/lib/domain/ritual-core/progression-ladder.tsis the whole rule, and the player, the card and the session-end write all read it. - The hard threshold is 7, not 9. The player’s own scale calls 7-8
Exigenteand 9-10Al límite(player.json), and her rule is about a session thatresulta exigente— so the hold starts where the screen says it starts (F1-DOC-RPE-ETIQUETAS-2026-09-11). - Scope covers BOTH products.
## BriefsaysSolo 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. - R-565-4’s parenthesis is out of date. Legacy’s full session is no longer
standard: its product-modality row moved to the globalmod_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 bytests/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
progressivemodality, 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 = falseis never scaled. - R-565-4 Non-progressive modalities (
express,base, and Legacy’sstandard) serve exactlybase_loopsand 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:
| Exercise | Level 1 | Level 6 |
|---|---|---|
| Fire breathing | 2 × 30 breaths | 324 breaths |
| Dead bug | 2 × 10 | 108 reps |
| Side plank isometric | 2 × 10 breaths | 108 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 breaths | Examples | Scales? |
|---|---|---|
| The breathing is the exercise | Fire breathing (30), Wim Hof wave (18) | No by volume — 324 breaths is not a progression |
| The breathing is the load | Side 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 studybelow. - 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_progressionper 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.tswholesale. ItsPROGRESSION_MATRIXandresolveProgressionLevelare the six-level design and are likely the thing to keep; what to do with the rest of that unwired module (getSessionPayloadand 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 progresivarenders 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 = 1on 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 isapp/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-techniquescarries 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):
SELECT count(*) FROM product_techniques WHERE product_id = 'prod_ritual_core_legacy'on prod →8(the three original cards + five new), andSELECT 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).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=prodfinds every key.- 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.
products.image_keyforprod_ritual_core_legacyis 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.tsxStill 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_techniquesfor 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.mdandASSETS_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-matchverification.json. The library covers are approved int613-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 withobject-fit: covercrops 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_keycannot 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 migration0089, guarded (image_key IS NULL) so a later Back Office choice is never overwritten.- Both unlock routes examined.
unlockSessionLinkedTechniques(gamification queue, explicituser_technique_unlocks) and the implicit derivation fromsession_progressinlistTechniqueLibraryForUser/getLatestUnlockedTechniqueboth 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.
- Five deliveries carry a founder approval quoted verbatim in
Scope
In scope
- The five approved cards as
category: techniqueexercises (exercises-core-f1-techniques.ts), theirproduct_techniquesrows, andsession_techniqueson 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
0089for 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)
Related
- 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 inverdicts/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 coverslo 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}; keysphase1/techniques/<slug>-<locale>.mp4(+-720psibling) andpublic/phase1/techniques/<slug>-library.jpg; first-encounter sessions fromD10_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.jsonat that moment; today only the ES 720p review renders areapproved.
Acceptance criteria
- Verdict coverage 27/27 (
D10_F*.json) — met 2026-09-04. - Produced cards wired and unlocking (query above); one member-facing check per phase on the Library — tranche 1 covers the five F1 cards.
- 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: containon the shared.tv-frame) answered as intended and recorded (R-T613-4:.tv-framehas 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_ROOTfor 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 themainmerge85e87cde3; 0 findings on T613 code. Its T699[CONCERN](post-Sunday accumulator re-derived inFaseActualCard) is recorded on #1686. - Accepted deferrals: none that touch this contract. Non-blocking hygiene noted by the design reviewer:
PlayerTechniqueLesson.tsx:34still forwardsposterUrl={technique.posterUrl}, which resolves toundefinedon this branch (libraryFromSessionemits noposterUrl); pinned by the e2e assertion that the viewer’s<video>carries noposter.
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_techniquesforprod_ritual_core_legacy= 8 rows;session_techniquesonts_rc_p1_legacy_s01(toning, chill pose, the lift),s03(hypopressives, 360°, three breaths),s04(cobra),s07(fire) with unique per-sessionsort_orderand the original card first.exercise_video_durationscarries the ten new 1080p keys;legacy-session-duration-cacheequals the computed minutes — after the founder’s twelve F1 coverage corrections landed in the integrated PR (2026-09-12:clipCoversBothSides: trueonstretch_s1_02/03/04,stretch_s2_03/04/05,stretch_s3_02,tone_cT1_05,tone_cT2_02/03,tone_cT4_02andtone_cT3_05— eight per side, alternating, one clip), s01 35, s03 27, s04 34, s08 29 (1693 s), s18 29 (1729 s); migrations0090(minutes) and0091(flags) move production, the source of the snapshot every seeded environment replays.products.image_keyfor the legacy product is set by migration0089only when NULL; the seed never writes it.
HTTP behavior
GET /media/phase1/techniques/<slug>-<locale>.mp4as an owner →200/206video/mp4; refunded, other-product or anonymous →403.GET /media/public/phase1/techniques/<slug>-library.jpg→200image/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
posterattribute,object-fit: contain.
Equivalence table
| Scenario | Input | Expected HTTP | Expected DB state |
|---|---|---|---|
| Owner plays Chill pose (ES) | GET /media/phase1/techniques/chill-pose-es.mp4 | 206 video/mp4 | unchanged (no unlock, no minutes) |
| Owner with day 1 completed opens the library | /es/panel/biblioteca | 200 | 3 unlocked / 5 locked derived from session_progress + session_techniques |
| Refunded member plays any card | same key | 403 | unchanged |
| Reseed twice | npm run verify:local ×2 | n/a | 8 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.tspins 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) andpublish-f1-technique-assets.ts --verifywhere 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) andtests/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_keyforprod_ritual_core_legacy(migrationdrizzle/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-sessionsort_order),drizzle/seeds/catalog/exercise-video-durations.json(+10 keys). - Services (
app/services/):player.server.ts—resolveTechniquesno longer passes the library cover as the viewer poster.media-access.server.ts—exerciseInPurchasedContentalso entitles an exercise registered to a purchased product inproduct_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-frameobject-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.jsonmedia: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 existingritual-core-legacy-sql,612-legacy-copy-her-words-only,seed-applies-to-migrated-schemaandlegacy-session-duration-cachesuites 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.
| Check | Result |
|---|---|
tests/unit/seeds/613-f1-techniques.test.ts | 9/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.ts | RED against the pre-T613 gate (owner refused, 403) → GREEN after exerciseInPurchasedContent learned product_techniques (R-T613-6). |
npx vitest run tests/unit/services | 128 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=local | 26/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 typecheck | exit 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.jsonrecords is not the 1080p’s sibling. It names the REVIEW render from thevN/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 samevN-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
| Row | What it actually was | Referenced object |
|---|---|---|
sess_ritual_core_day_1 | duration_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 PDF | public/session/505f1593-…/Core F1 — Tone base A.png |
tech_rc_breath | slug test, category magic, title «Test» in both locales, an Unsplash thumbnail | the 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
approvedSourcecomes from the samevN-delivery/folder as its 1080p, and both report the samedurationSeconds. Pinned bytests/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 ownpublic/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.jsoncarries 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_1nortech_rc_breathappears indrizzle/seeds/public/catalog-content-seed.sql, in any table.
Receipts — tranche 2
Every line is a tool result from the session; nothing is inferred.
| Check | Result |
|---|---|
npm run db:diagnose-media-parity -- --env=prod | before: ✗ 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 -- --verify | all 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=prod | 44 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 --noEmit | no error in the changed files. |
| pre-commit + pre-push chain | PASS, 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 thefeat/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):
SELECT count(*) FROM session_items WHERE item_type = 'pdf' AND session_id = 'ts_rc_p1_legacy_s01'on prod →3, and0on every otherts_rc_p%_legacy_%session.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 ofsistema inmune,decoadaptaciónandcerrar la diástasis.npm run db:diagnose-media-parity -- --env=prod→ the threeprivate/session_item/…keys exist inthefittclub-media-private.- The player’s resource cards on F1’s first session read
Respiración en cuatro tiempos,Un buen hipopresivo,Volver a sentirin/es/andBreathing in four stages,Hypopressives, step by step,Feeling it againin/en/— three different cards per language, each opening its own language’s document in the resource viewer. - 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.tsStill 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.pdfandficha-resumen-fase4.pdf— both close withCon los cambios propuestos aquí ademas mejorará mucho vuestro estado de ánimo y sistema inmune. Her 2026-09-04 decision replaces the immune half withte 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— writesdecoadaptacióntwice. Her rule, 2026-09-05:decoaptación, always.ficha-resumen-fase1.pdfandficha-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_itemspdfcount = 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.pdfis parsed bymedia-access.server.tsas a structured key with entity typelegacy, which no branch entitles — every member would have received403. 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 bytests/unit/services/media-access.phase-pdf-entitlement.test.ts. - Three PDFs on one session are indistinguishable today. The player labels every
pdfitem with the type label (Documento PDF), andsession_item_translationshas no title column. Three identical cards is a defect she would see in one minute. The contract therefore adds a nullabletitleto the translations side-table (ADR-0010: localized text lives there) — additive migration0088; every existing item keeps its type label. - Reading time. A
pdfitem withduration_seconds = NULLis 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 explicit0.tests/unit/seeds/legacy-session-duration-cache.test.tsis the guard that would have gone red under NULL. The43 minthe 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.
PlayerIntroTheorytreated 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 ingatesSessionStart: a theory video or audio still gates, exactly as since T06; a PDF is listed and openable, shows noObligatorioflag, is left out of then/m obligatorioscount, and never locks the start button (R-T625-6). - Reaching the shelf again.
ts_rc_p1_legacy_s01is 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.
PlayerResourceOverlaywrapped itself in.drawer-scrim, the session-map drawer’s backdrop, whichapp.csssets todisplay: nonefrom 1024px (the drawer becomes a sidebar there). At 1280px the overlay’s bounding box wasnull; 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 bytests/e2e/player/player-phase-material.spec.tsat 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/dashboardonce, and the same URL answered200with 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.
- Three approved files exist with the hashes the editorial owner recorded (
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, neverdecoadaptación; anycerrar la diástasiswording →una faja que funciona. - The seed manifest of approved files (
ritual-core-legacy-pdfs.ts: key, title, sha256, bytes, pages) and thesession_items/session_item_translationsrows on each phase’s first session — F1’s three in this tranche. - The
titlecolumn onsession_item_translations(migration0088) 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 putper 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
Related
- 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-localetitleonsession_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 underfase-1/en/are real approved files (1c93f6ca…,bdd0df31…,93c90738…), so each item now carries anenrow 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) — apdf-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
- Prod serves the approved
pdfsession_itemsrows on the phases’ first sessions — three on F1 in this tranche, the remaining phases as each set is approved. - Zero occurrences of
sistema inmune,decoadaptaciónandcerrar la diástasisin the text of every published PDF (publish-legacy-phase-pdfs.ts --verify). - 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 in2675e3914:DEFAULT_LEGACY_PDF_SOURCEreadsTFC_ASSETS_ROOT(founder path as fallback);--verifyis an explicit, accepted flag and unknown arguments abort;.rv-scrimcarries its ownprefers-reduced-motionguard (--motion-baseis 280 ms andapp.csshas no global reduced-motion block). Pre-existing, out of scope, recorded:.drawer-scrimand.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 themainmerge372bc6de2that cleared theCONFLICTINGstate; 0 findings on T625 code. The two T699[CONCERN]s (arc legendrole="group"underrole="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 threepdfsession items, each with anesand anentranslation 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.titleexists, nullable (migration0088); 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;0on every otherts_rc_p%_legacy_%session.- Six
session_item_translationsrows 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>.pdfas an owner →200/206from the private bucket; as a refunded member, a member of another product or anonymous →403.- The
private/legacy/<slug>/…shape the pending spec proposed →403for everyone.
UI behavior
/es/panel/reproductor/rc-p1-legacy-t01e01intro lists three.ds-attach-card.is-consultcards titledRespiración en cuatro tiempos,Un buen hipopresivo,Volver a sentir;/en/dashboard/player/…listsBreathing in four stages,Hypopressives, step by step,Feeling it again. NoObligatorioflag, nox/ycount, start button enabled with the documents unopened.- Clicking a card opens
.resource-viewerover.rv-scrimat 390 px and at 1280 px; the iframe points at that locale’s/media/key; Escape closes it and marks the cardis-viewed. - A theory video or audio on a session still gates:
0/1 obligatorios, lock line, start disabled until viewed.
Equivalence table
| Scenario | Input | Expected HTTP | Expected DB state |
|---|---|---|---|
| Owner opens ES document | GET /media/private/session_item/si_ts_rc_p1_legacy_s01_pdf_respiracion_cuatro_tiempos/respiracion-cuatro-tiempos.es.pdf | 200/206 application/pdf | unchanged (no progress, no unlock, no minutes) |
| Owner opens EN document | same item, .en.pdf | 200/206 | unchanged |
| Refunded member opens either | same keys | 403 | unchanged |
| Owner starts the session without opening any PDF | intro start CTA | n/a (client) | session proceeds; nothing written for the PDFs |
| Reseed twice | npm run verify:local ×2 | n/a | 3 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.tsruns 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 →privatebucket; refunded / stranger →forbidden; theprivate/legacy/…shape →forbidden). -
R-T625-3 — A phase PDF charges no training minutes. Testable: the seed test asserts
duration_seconds = 0on everypdfrow;legacy-session-duration-cache.test.tskeeps the seeded minutes equal to the computed ones. -
R-T625-4 — Three documents on one session read as three different cards. Testable:
sessionItemLabelunit 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) andtests/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 → noObligatorio, 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
enrow per item with its own key and a different sha256 / title fromes),media-accesstest (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_translationsgainstitle text(nullable) — migrationdrizzle/migrations/0088_t625_session_item_title.sql, additive, rollback comment inside.session_items: 3 newpdfrows onts_rc_p1_legacy_s01(sort_order1–3,duration_seconds0).session_item_translations: anesand anenrow 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—titleonsessionItemTranslations. - Services (
app/services/):player.server.ts— both resource-link builders selecttitleand label the card withsessionItemLabel(tx, itemTypeLabel(type)). No signature changes.media-access.server.tsunchanged (the structuredsession_itembranch already entitles the key). - Domain logic (
app/lib/domain/): newsession-item-label.ts—sessionItemLabel(rows, fallback): own-locale title, elsees, else the type label. Newsession-resources.ts—gatesSessionStart(kind):pdf→ false, everything else → true. - Components / styles:
app/components/player/PlayerResourceOverlay.tsx— root classdrawer-scrim→rv-scrim;app/styles/app.css— new.rv-scrimrule 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 carriesis-consultinstead ofis-mandatory, noObligatorioflag (stillRevisadoonce 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.jsongainsmedia:publish-legacy-pdfs;.knip.jsoncignores the optional poppler binaries the verifier shells out to. - Routes (tripartite): none. The Back Office session editor keeps writing
content_key/subtitle_keyand leavestitleuntouched on upsert. - i18n namespaces: none —
player.kind_pdfexists 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) andritual-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.tsran against the editorial deliverables on the founder’s machine: 6 files (3 ES underv2/+v3-hipopresivos/, 3 EN underfase-1/en/), sha256 + byte size equal to the manifest, page counts 3 / 7 / 4 per locale,pdftotextscan 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, sixUpload complete). - Gates that the first pass skipped, now run with the locked dependencies installed (
npm ciin 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, includingaudit-layoutandlint-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 typecheckexit 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, realplayer.jsoncopy). - Seed against the migrated schema:
seed-applies-to-migrated-schemaandlegacy-session-duration-cachegreen with the six rows and migration0088— the seeded session length is unchanged (the PDFs charge 0 s). - Browser (Step 5.5), local rung
npm run preflight:smoke:local(wrangler pages devover the built bundle + theverify:localD1, Chromium 1280×800), legacy fixture,/es/panel/reproductor/rc-p1-legacy-t01e01and/en/dashboard/player/rc-p1-legacy-t01e01withproductId=prod_ritual_core_legacy—tests/e2e/player/player-phase-material.spec.ts, 2 passed:/es: threeis-consultcards titledRespiración en cuatro tiempos,Un buen hipopresivo,Volver a sentir; non/3 obligatorioscount, no lock line,Empezar sesiónenabled 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 readBreathing 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/pdfwith the manifest byte count for the owner and403for a member without the product /401anonymous; 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 withmainat3c0940ea5) 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=prodcould not be run in the session (shell gate), so the prodpdfcount of0rests 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
gala1234a 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.tsand*.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-a11yESLint-10 peer override (upstream-gated) · track=infra · effort=XS · domain=other · brief=Wheneslint-plugin-jsx-a11ypublishes a release whosepeerDependencies.eslintincludes^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
migrationsCI job only applies the chain when a PR touchesdrizzle/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-corecomo 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
Purchasefrom app checkout (pixel + server) · track=mvp · effort=L · domain=analytics · brief=Cuando la app sustituya a Zenler, cada compra debe disparar elPurchasede 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/assetsoverflows 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/magazinefrom 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/*.jsonplus the 11 DB*_translationstables (… - 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.mdLayer 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_dataconsent 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
tagfilter (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-linkanchors · track=polish · effort=XS · domain=design · brief=Give.af-linkanchors 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” whenjqis missing · track=infra · effort=XS · domain=infra · brief=Withoutjq, every outcome count inautonomy-health.shsilently 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.shtrusts file order for “last used”, so a merge can fake a STALE verdict · track=infra · effort=XS · domain=infra · brief=audit-skills.shtakes 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_TOKENconclaude-code-actionfactura 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 needingaria-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.ymlfails 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-safetyR2: 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
mainle 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 Appleal 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 CUENTAbutton never says what unlocks it · track=mvp, polish · effort=S · domain=auth · brief=En el registro,CREAR MI CUENTAsale 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=
getPublicUrldevuelve 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
defaultfamily’s third question is carrying the failures · track=infra · effort=M · domain=infra · brief=T651midió la familiadefaulty 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
T637en 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_logno tiene ni una fila demarketing— 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_suppressionsdecide 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
leadshold comes off · track=infra · effort=M · domain=email · brief=El barrido ya borra en seis categorías;leadssigue 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-pushdiga «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.jsonlsale 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-reviewerdejó anotadas al cerrarT684, ninguna bloqueante:… - 691-dashboard-server-is-five-services-wearing-one-name — 691 —
dashboard.server.tsis 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.ymlpays twice for the same answer (T537 phase 2) · track=infra · effort=S · domain=infra · brief=La fase 2 deT537, 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.tsis 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=T683cerró una regla derepo-layout.mdque 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 —
/metodoasks for ten screens of scroll on a phone · track=mvp · effort=L · domain=design · brief=/metodomide 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.cssy 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
~/codeel 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
commonstring 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_MARKen 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 —
preflightand 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
pendingstatus · 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/soportese 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 6paranovatacon 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: elfetchdel 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
DrizzleQueryErrorcuyo 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=Migratematerialsfrom 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_PASSWORDpuesta y no la restauran; otros dos sí, cada uno … - 796-dashboard-card-progressive-version-hides-its-null — 796 — Fix: the dashboard card’s
progressiveVersionhides 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 cabeceraGENERATED 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*.mdporque 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,
/admindio 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
T812compare, 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 recibocleanexige cerogap, 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
routinestable + deadmaterial_slugscolumn · track=infra · effort=S · domain=schema · brief=Cerrar TD-007 dropeando la tabla legacyroutines(y su hijaroutine_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:
| Channel | Output per topic | Cadence |
|---|---|---|
| ≥1 post (carousel / reel) + stories round | every topic — primary channel | |
| Blog | 1 article (1500-2500 words) at /blog | every topic |
| Newsletter | 1 email (600-900 words, links to blog) | every topic |
| YouTube | 1 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.
| # | Date | Pillar | Format (reel / carousel / single / story-set) | Topic | Saves | Notes |
|---|---|---|---|---|---|---|
| (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).
| # | Date | Pillar | Topic | Duration | Views | Notes |
|---|---|---|---|---|---|---|
| (none yet — placeholder; first video targets one topic also covered by IG + blog + newsletter the same week) |
Newsletter emissions
| # | Date | Pillar | Title | Open rate | Click rate | Notes |
|---|---|---|---|---|---|---|
(none yet — first emission targets H4 in mvp-scope.md → Outreach pillars; depends on T62) |
Blog articles published
| # | Date | Pillar | Slug | Word count | Notes |
|---|---|---|---|---|---|
| (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 starting | Downloads | Pillar (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.
| # | Date | Tester ID | Type (survey/interview/incident) | NPS | Notes |
|---|---|---|---|---|---|
| (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
- After publishing a newsletter / blog article / running a beta session, append a row to the matching section.
- Use the exact column structure shown — the parser is strict about column counts.
- Push to main. The vault dashboard updates automatically on next sync (via
.github/workflows/sync-vault-dashboard.yml). - 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.