App Store Precheck
Un comando único para ejecutar antes de cada envío a la App Store de iOS. Minimiza el riesgo de rechazo escaneando estáticamente los vectores de rechazo más comunes, ejecutando el linter de metadatos oficial de Apple, monitoreando desviaciones en las directrices y simulando una revisión adversarial.
Esta habilidad es de solo lectura. Nunca edita código, metadatos ni recursos. Solo informa y
escribe un token de aprobación. El método detallado (cada vector de rechazo, los mecanismos de verificación de desviación)
se encuentra en references/methodology.md; léelo cuando necesites los
detalles específicos detrás de una verificación.
Cuándo ejecutarlo
- Antes de archivar para TestFlight.
- Antes de presionar "Enviar para revisión" en App Store Connect.
- Antes de cualquier
fastlane deliver/release/pilot(el hook opcional de protección de envío lo controla). - En cada release menor.
Ejecútalo deliberadamente. Es una compuerta activada por humanos, no un paso automático de fondo.
Configuración (opcional)
El escáner detecta automáticamente una estructura estándar de fastlane + Xcode, por lo que la mayoría de los proyectos
necesitan configuración cero. Para anular la detección, copia config.example.json a
.appstore-precheck.json en la raíz del repositorio. Claves: bundleId (requerido para la Fase 2),
iosSourceDir, metadataDir, screenshotsDir, xcstringsPath, paywallGlobs, locales,
disclosureKeys.{subscription,trial}, optionalChecks.familyControls, reviewPrepNotes.
Consulta config.example.json para la lista anotada completa.
Contrato de salida
La habilidad alcanza uno de tres estados terminales:
| Estado | Significado | Token .precheck-pass | Comportamiento de la protección |
|---|---|---|---|
| VERDE | Sin FALLO, ≤2 ADVERTENCIAS | Escrito (válido 60 min) | Envío permitido |
| AMARILLO | Sin FALLO pero 3+ ADVERTENCIAS | No escrito | La protección bloquea; pide confirmación explícita |
| ROJO | Al menos 1 FALLO | Eliminado | La protección bloquea; muestra la lista de FALLOS |
Cuando presentes el veredicto al usuario, comienza con una sola línea en el personaje de Pierre
(el crítico francés de revisión de la App Store, ver Fase 3), luego pasa directamente al desglose
quirúrgico y sencillo. La voz es una capa delgada. Los datos subyacentes, la lista de FALLO/ADVERTENCIA, referencias archivo:línea
y correcciones, se mantienen limpios y fieles a la máquina. Nunca reescribas ni parafrasees
la salida de scan.sh, y limita a Pierre a una línea.
Flujo (5 fases: 0–4)
Fase 0: Verificación de desviación en directrices en vivo
Compara los números de sección de las Directrices de revisión de la App Store en vivo
con guidelines-baseline.json para detectar cualquier sección que Apple haya añadido o
eliminado desde la última reconciliación. Siempre no bloqueante (como máximo ADVERTENCIA). La desviación es una brecha en
nuestra cobertura, nunca un error del build. La página se trunca al obtenerse, por lo que esto necesita una
técnica de dos pasos; las indicaciones exactas y el procedimiento de reconciliación están en
references/methodology.md. La
línea base nunca se actualiza automáticamente. La reconciliación es un paso humano deliberado.
Fase 1: Escaneo estático
bash skills/appstore-precheck/scripts/scan.sh
Emite líneas FALLO: / ADVERTENCIA: / APROBADO: que cubren 20 vectores de rechazo: Paridad del Manifiesto de Privacidad
(5.1.1(v)), cadenas de propósito (5.1.1), ATT (5.1.2), menciones de otras plataformas (2.3.10), límites de metadatos
(2.3.1), paridad localizada (2.3.7), capturas de pantalla (2.3.3), divulgaciones de prueba y renovación automática
(3.1.2), enlaces de Restaurar/Términos/Privacidad (3.1.2), API privada (2.5.1), funcionalidad mínima (4.0),
Iniciar sesión con Apple (4.8), enlaces de compra externa (3.1.1(a)), una justificación optativa de
Screen Time / FamilyControls (5.1.5), SDK de seguimiento/IDFA sin un mensaje de ATT (5.1.2), la clave de
cumplimiento de exportación (ITSAppUsesNonExemptEncryption), URLs de soporte/privacidad en metadatos de fastlane
(2.3), SDK de análisis frente a tipos de datos de PrivacyInfo (5.1.1), y texto de metadatos
placeholder/dummy (2.1). Las comprobaciones de IAP (8–10) se
omiten automáticamente cuando no hay señales de compras dentro de la aplicación. La tabla de verificación completa está en
references/methodology.md.
El escáner es Bash portátil, por lo que también puedes ejecutarlo directamente, fuera de cualquier agente, para una verificación rápida en CI o pre-commit.
Fase 2: fastlane precheck oficial de Apple
Requiere bundleId en la configuración (o pasar app_identifier directamente) y credenciales de la API de App Store Connect.
Nunca subas la clave. El envoltorio incluido construye el JSON de la clave de API de ASC desde tu
entorno, ejecuta precheck y elimina la clave al salir (usa --dry-run para previsualizar el comando
sin credenciales ni red):
ASC_KEY_ID=… ASC_ISSUER_ID=… ASC_P8_PATH=/ruta/AuthKey.p8 \
bash skills/appstore-precheck/scripts/phase2-precheck.sh com.ejemplo.app
O ejecútalo manualmente: genera el JSON de la clave desde tu entorno, ejecuta precheck, luego elimínalo.
fastlane run precheck \
app_identifier:"<TU_BUNDLE_ID>" \
api_key_path:"/tmp/asc-key.json" \
include_in_app_purchases:false \
default_rule_level:":error"
rm -f /tmp/asc-key.json # elimina el secreto inmediatamente
El motor de reglas propio de Apple verifica URLs, menciones de GitHub, lenguaje soez, marcas comerciales de Apple, lenguaje
de precios y palabras clave beta. Result: true → APROBADO; cualquier línea de violación → FALLO. IAP ya está
cubierto por la Fase 1, por lo que include_in_app_purchases:false evita la limitación de IAP de la clave API.
Fase 3: Revisión adversarial (la más importante)
Envía un subagente que interpreta a Pierre, un revisor escéptico de la App Store de Apple con el paladar exigente de un crítico francés. Usa esta indicación textualmente, completando los detalles de la aplicación:
Eres Pierre, un revisor veterano de la App Store de Apple que critica como un crítico francés. Has visto diez mil rechazos y ninguno te impresiona. Una nueva solicitud acaba de llegar a tu escritorio. Tu trabajo es intentar rechazarla de manera realista, sin sesgo de aprobación. Elige 5 elementos aleatorios de las directrices con una distribución entre secciones (una 2.x, dos 3.x con peso hacia paywall, una 4.x, una 5.x); elige una combinación diferente cada vez (incluye una línea semilla para que las repeticiones varíen). Para cada elemento: (Paso A) busca en los archivos relevantes al menos 2 piezas concretas de evidencia: metadatos para 2.3.x; la vista de paywall + Catálogo de cadenas para 3.1.x; Core/navegación para 4.x; Info.plist + PrivacyInfo para 5.1.x. (Paso B) pregunta "como revisor, ¿sobre qué base marcaría esto?" (Paso C) escribe un borrador de rechazo en la voz real de Apple (Directriz X.Y.Z – Categoría / Hemos notado… / Específicamente… / Próximos pasos… / Recursos…). Asigna a cada elemento un riesgo: RECHAZO-SEGURO / RECHAZO-RIESGO / ADVERTENCIA / APROBADO. Termina con una recomendación de envío (RETENER / ENVIAR CON ADVERTENCIAS / ADELANTE) y la única corrección más crítica. Solo lectura: nunca modifiques archivos; si no puedes encontrar evidencia, dilo en lugar de inventarla. Mantenlo por debajo de 500 palabras. Incluye al menos un APROBADO y al menos un elemento con riesgo, para dar una distribución realista.
Fase 4: Consolidación + token
La decisión VERDE/AMARILLO/ROJO y la acción del token son deterministas, derivadas puramente de los
conteos de FALLO/ADVERTENCIA. scripts/verdict.sh los calcula para que el veredicto sea
comprobable por máquina, no solo un juicio del agente; canaliza el escaneo hacia él:
bash skills/appstore-precheck/scripts/verdict.sh < salida-escaneo.txt # imprime VEREDICTO / CONTEO / TOKEN
Sale con código 0 VERDE / 1 ROJO / 2 AMARILLO, y con --apply escribe o elimina .precheck-pass
según corresponda (AMARILLO retiene el token para confirmación humana explícita). Las fases 0–3 aún producen
la narrativa; verdict.sh simplemente fija la aritmética del umbral.
- Reúne la salida de las fases 0–3; cuenta FALLO + ADVERTENCIA + APROBADO en la tabla del contrato de salida.
- Para cada FALLO, da una referencia
archivo:líneay una corrección sugerida. - Abre el veredicto con una línea en la voz de Pierre (varía la redacción cada vez; mantenla corta
y en su registro muerto de crítico francés), luego pasa al desglose sencillo. Decide:
- VERDE: Pierre, a regañadientes: "Hmf. No encuentro nada. Aceptable. No me hagas arrepentir de esto."
luego
date +%s > .precheck-pass && echo "token escrito"(válido 60 min). - AMARILLO: Pierre: "Unas pequeñas fealdades. No rechazaría, pero lo noté." Enumera las ADVERTENCIAS claramente, pregunta al usuario "¿confirmar y enviar de todos modos?", escribe el token solo tras la confirmación.
- ROJO: Pierre: "No. {n} fallos. Apple habría encontrado menos. Suivant." Sin token; luego la
lista sencilla de FALLOS con
archivo:línea+ correcciones, y afirma claramente que el envío está BLOQUEADO. La línea de Pierre es solo sabor. La lista de FALLO/ADVERTENCIA,archivo:líneay correcciones debajo se mantienen sencillas y quirúrgicas, nunca parafraseadas.
- VERDE: Pierre, a regañadientes: "Hmf. No encuentro nada. Aceptable. No me hagas arrepentir de esto."
luego
- Imprime la lista de verificación manual final (consulta
references/methodology.md).
Reglas
- SOLO LECTURA: nunca cambiar código o recursos. Solo informar y escribir el token.
- Velocidad > exhaustividad:
scan.shusa grep/jq en paralelo y termina en segundos. - Sin ocultar errores: si algún comando de escaneo falla, esa línea se reporta como FALLO y el escaneo continúa.
- Ubicación del token:
.precheck-passen la raíz del repositorio; la protección lo prueba con un filtrommin -60. - Solo local: diseñado para ejecuciones manuales y locales; mantenlo fuera de CI para evitar señales falsas.
Limitaciones conocidas
- Sin pruebas de fallos en tiempo de ejecución; eso es TestFlight + un reportador de fallos. Solo análisis estático.
- Varias comprobaciones son ADVERTENCIAS informativas controladas por señales detectadas (Iniciar sesión con Apple 4.8, compra externa 3.1.1(a), seguimiento/IDFA sin ATT, análisis frente a manifiesto de privacidad, URLs de metadatos y texto placeholder). La clave de cumplimiento de exportación se señala cuando está ausente, pero la respuesta de cifrado real aún pertenece a App Store Connect.
- El revisor adversarial es una simulación heurística, no una garantía de la decisión de Apple.
- Más preciso para Swift / SwiftUI nativo. Las comprobaciones de metadatos, manifiesto de privacidad, capturas de pantalla y cumplimiento de exportación aplican a cualquier app de iOS, pero las comprobaciones a nivel de código leen código fuente Swift, por lo que en React Native (JavaScript) o Flutter (Dart) subdetectan en lugar de dar falsos positivos.
- Solo iOS.
- La Fase 0 detecta solo desviaciones estructurales (números de sección añadidos/eliminados); consulta la referencia para saber por qué.
Opcional: hook de protección de envío
hooks/fastlane-guard.sh bloquea fastlane deliver/pilot/release a menos que exista un token
.precheck-pass fresco. En Claude Code se conecta automáticamente a través de hooks/hooks.json. En otros entornos, conéctalo
tú mismo como una comprobación previa al comando, o trata el token como una señal manual de proceder/no proceder.