Free

3.000 líneas en un solo commit: por qué las features complejas necesitan plan mode primero

El instinto ante features complejas es "déjame probar algo" — pero las decisiones arquitectónicas se esconden en el tercer modelo, el quinto edge case. El verdadero valor de plan mode es mover la conversación arquitectónica al texto antes del código. Caso real: el sistema de jurado comunitario de Pickful — 3.032 líneas, 119 specs en verde, un solo commit, cero retrabajo arquitectónico después.


Ante una feature compleja, el instinto de la mayoría es "déjame probar algo".

El problema: los sistemas complejos tienen una característica — las decisiones de arquitectura se esconden en el 3ᵉʳ modelo, el 5º edge case, la 8ª regla de puntos. Lanzarte al código y chocar con esas decisiones a medio camino, para volver atrás y cambiarlas, cuesta 10× más que haberlas hablado en texto desde el principio.

Usé el plan mode de Claude Code para construir TopicReview, el sistema de jurado comunitario de Pickful, y vi la versión extrema de esta desigualdad: un commit, 3.032 líneas, 119 specs en verde, entregado de una sola vez. Ninguno de los más de diez commits que siguieron fue un rehacer arquitectónico — todos son ajustes de parámetros, pulido de UI, parches de edge cases. El sistema lleva en pie desde entonces y hoy es central para cómo la comunidad se automodera.

Este artículo trata sobre por qué las features complejas necesitan plan mode primero, qué hace realmente la fase de plan, y cuándo la conversación está lo suficientemente madura para empezar a escribir código.

Qué tan complejo es el sistema

TopicReview es una votación comunitaria que decide si un post de baja calidad se elimina. Se resume en una frase — pero la especificación se despliega en capas:

  • 5 estados: open → voting → decided → appealed → closed
  • 3 veredictos: remove / warn / keep
  • 2 fases: revisión inicial por 12 jurados; apelación por 5 jueces (sorteados entre los 20 usuarios con más puntos)
  • Flujo de puntos multidimensional: 10 pt de penalización provisional, 10 pt de stake de apelación, +5 para jurados que votaron con el veredicto, +10 para jueces que votaron con el veredicto, +3 para denunciantes cuya denuncia fue ratificada, reembolso al ganar una apelación = stake + bonus + penalización provisional
  • 4 tipos de jobs programados: ventana de votación inicial 24h, ventana de apelación 24h, ventana de revisión de apelación 24h, y — pagos a jurados diferidos 24h tras un veredicto remove (porque una apelación podría revertirlo)
  • Flujos paralelos + rollback: si los votos se giran durante la remoción provisional, hay que restaurar el post y reembolsar la penalización; si la apelación revoca el veredicto, se devuelve el stake más un bonus, posiblemente junto con la penalización provisional, y los jurados se recalifican según el nuevo veredicto

La complejidad no está en ninguna regla individual — está en cómo interactúan las reglas entre sí. Cada regla nueva puede disparar un rollback en otra.

Muros contra los que chocás sin plan

Cuando escribís de corrido, los problemas más difíciles no son los hechos visibles — son las preguntas que ni se te ocurrió hacer. Leyendo el código de TopicReview al revés, hay al menos cuatro muros con los que chocarías inevitablemente si te saltearas el plan:

Reglas de elegibilidad de jurados. Parece simplemente User.jurors_and_judges.sample(12). Pero las reglas reales son: excluir al autor del post, excluir a quien lo denunció, excluir a quien ya votó en la ronda inicial (para que no vuelva a votar en la apelación). Tres exclusiones apiladas. Si escribís el modelo de una tirada, te comés una o dos.

Pago diferido de puntos. Un veredicto remove normalmente dispara el pago a los jurados. Pero una apelación puede revocar un remove — y cuando lo hace, los jurados que votaron con el veredicto viejo quedan en el lado equivocado, así que hay que recalcular los pagos contra el nuevo veredicto. Por eso el veredicto remove debe esperar a que cierre la ventana de apelación de 24h antes de pagar a los jurados. Si no escribís esta regla, pagás primero y después terminás intentando recuperar puntos — diez veces más engorroso que pagar tarde.

Diseño de interfaz del job programado. CloseTopicReviewJob parece "cerrar una review". En la práctica maneja tres situaciones:

# Expiración de la ventana de votación inicial
CloseTopicReviewJob.set(wait_until: voting_ends_at).perform_later(review.id)
# Pago diferido a jurados tras un veredicto remove
CloseTopicReviewJob.set(wait: 24.hours).perform_later(review.id, award_juror_points: true)
# Expiración de la ventana de apelación
CloseTopicReviewJob.set(wait: 24.hours).perform_later(review.id, appeal_id: appeal.id)

Sin la planificación previa, escribís la primera firma y en el segundo caso te das cuenta de que la interfaz tiene que cambiar.

El muro más caro: ¿se puede apelar durante la remoción provisional? Cuando los votos remove cruzan el umbral, el post queda oculto (provisional), pero la review sigue en estado voting — no decided. ¿Puede el usuario apelar ya?

  • Sí → tenés que ampliar las transiciones entre decided y appealed
  • No → UX terrible: el post está oculto y el usuario tiene que esperar 24h para poder protestar
  • Elección real de TopicReview: sí, se permite apelar durante la remoción provisional — pero la review tiene que pasar primero por finalize → decided antes de abrir la apelación

Esa sola decisión repercute hacia atrás y cambia los chequeos de parámetros de open_appeal! y la lógica de la máquina de estados. Decidirlo a mitad de camino = reescribir medio sistema.

Qué hace realmente la fase de plan

El plan mode de Claude Code es un modo en el que está prohibido escribir código — Claude puede leer el repo, pensar en enfoques, discutir con vos, pero cualquier modificación de archivos queda bloqueada con hard-block hasta que apruebes un plan.

Esa restricción mecánica es el punto: fuerza a que la conversación a nivel arquitectónico ocurra en texto.

Algunas cosas que la fase de plan está haciendo en la práctica:

1. Dibujar la máquina de estados y los roles. 5 estados, 4 roles (jurado / juez / autor / denunciante), lo que cada rol puede y no puede hacer en cada estado — todo en unas líneas de markdown. Unas líneas vs. decenas de archivos. El costo de cambio son dos órdenes de magnitud distintos.

2. Recorrer el flujo de cada rol:

  • Jurado: recibe notificación → abre la review → lee el post y el motivo → vota con reasoning → recibe puntos
  • Autor del post: recibe notificación → ve el veredicto → si es remove considera apelar → pone el stake → espera
  • Juez: recibe la apelación sorteada del top-20 → vota → recibe puntos

Donde sea que el recorrido se traba, sale una pregunta oculta: "¿los jurados ven los votos de otros jurados?", "¿qué puede hacer el autor durante la remoción provisional?"

3. Interrogar edge cases. La fase de plan no diseña el "camino normal" — hace a propósito las preguntas que normalmente no surgen:

  • ¿Y si la ventana cierra con 0 votos? (Decisión final: keep por defecto.)
  • ¿Y si la apelación cierra con 0 votos? (dismissed; stake perdido.)
  • ¿Puede un juez votar un post que él mismo denunció? (No — misma regla de exclusión.)
  • Varios jurados disparan finalize al mismo tiempo — ¿la carrera duplica pagos? (Añadir un campo juror_points_awarded para idempotencia.)

El 95% de estas preguntas no aparece naturalmente mientras escribís código. La fase de plan te obliga a contestarlas una por una.

4. Libro mayor de puntos. El sistema de puntos es tan complejo que discutir no alcanza — hay que dibujar la tabla: cada flujo de puntos con su disparador, su monto y su camino de rollback. Una vez que el libro cuadra, todos los edge cases (reembolso provisional, reembolso de apelación, bonus) se reconcilian.

Hasta qué punto hay que hablar antes de escribir código

Un criterio duro:

  • Podés recorrer cada camino sin trabarte — cada combinación desde abrir la review hasta closed (keep / remove / warn × con / sin apelación × provisional / no) — la podés contar de punta a punta
  • Cada edge case tiene una conducta definida — no "ya veremos", sino "0 votos por defecto es keep", "provisional permite apelar pero primero hay que finalize"
  • No hay "eso todavía no lo pensé" — toda pregunta que puedas formular ya tiene respuesta

Cuando llegás a ese punto, escribir código es traducir el plan a Ruby.

Cómo se ve la fase de ejecución de corrido

La primera entrega de este sistema:

d162f1e Add community moderation system with jury/judge review and appeals
  63 files changed, 3032 insertions(+)
  119 specs, 0 failures

63 archivos, 3.032 líneas, 119 specs en verde. Entregado de una sola vez.

Los más de diez commits que siguieron confirman que la arquitectura aguantó:

Apply legacy penalty (1pt) for posts created before 2026-03-26
Fix topic review appeal bugs: window mismatch and verdict not updated
Add topic_removed status for posts removed by community review
Default to keep verdict when review expires with zero votes
Reduce provisional removal penalty to 1pt during trial period
Allow topic creator to withdraw active reviews
Add handled tab to jury dashboard, fix tabs styling

Cada uno es ajuste / fix / pulido / pequeña feature. Ninguno es "volver a rediseñar la máquina de estados" o "hay que cambiar el modelo de puntos". El esqueleto estaba bien.

Ese es el verdadero beneficio del plan: la ejecución no se interrumpe. No hay "esperá, cómo va este camino" — el plan ya lo cubrió. No hay "no había pensado este edge case" — la fase de plan lo preguntó. No hay "esta interfaz hay que rediseñarla" — el plan ya la resolvió.

Horas escribiendo código, haciendo una sola cosa: traducir un diseño claro al teclado.

Cuándo no usar plan

No toda tarea merece plan:

  • Fixes de bugs simples — localizar + arreglar + agregar regression test; sin discusión previa
  • Refactors mecánicos — renombrar, extraer, mover; el camino es único, plan es un paso de más
  • Un único camino obvio — agregar un GET endpoint, un UI toggle; no hay nada que debatir
  • Prototipos exploratorios — aún no sabés qué querés; hacer algo tosco que funcione vence a pensar más

El beneficio del plan mode viene de bajar el costo de reescritura. Si la tarea no tiene riesgo de reescritura, plan es solo overhead.

Cierre

"Pensar antes de actuar" suena a consejo de personalidad. Plan mode no es eso.

Plan mode es hacer que la conversación a nivel arquitectónico ocurra donde 10 palabras la cambian — no donde tienen que cambiar 30 archivos.

Bajo complejidad, hay que dar vuelta el dicho de la industria "words are cheap, code is expensive" — no significa "escribí código primero y vemos" (eso solo vale cuando la brecha de costo es chica), significa usar esa brecha: poner la conversación cara por delante, en el medio barato.

3.000 líneas en un solo commit se siente increíble. No porque escriba rápido — porque el plan convirtió "escribir" en un acto puramente mecánico.