# CODEX — Finalizar Bootstrap de Alexa Skill Factory y preparar Apache Multi-Skill

## Proyecto de trabajo

Trabajar desde:

```text
C:\xampp\htdocs\aws-api-skill
```

Este documento corresponde a la **fase final del bootstrap** de la fábrica de Alexa Skills para radios SignalLive.

NO crear todavía una segunda Skill.

NO crear todavía `radiomp-audio`.

La meta de esta fase es dejar completamente preparada y validada la infraestructura para que una segunda Skill pueda coexistir con Radio Babasónica sin romper la Skill actual.

---

# 1. ESTADO CONFIRMADO

ASK CLI ya está instalado y autenticado.

Versiones registradas:

```text
Windows: 10.0.19045.6466
Node: v24.18.0
npm: 11.16.0
Git: 2.55.0.windows.3
ASK CLI: 2.30.7
```

Perfil ASK:

```text
signal-radio-factory
```

Vendor:

```text
Vendor ID: MPMP5O0JXSS87
Vendor Name: Ciudad Babasonica
Role: ROLE_ADMINISTRATOR
```

Skill existente de referencia:

```text
Radio Babasónica
Skill ID:
amzn1.ask.skill.005dec3e-f214-4e7e-90ba-2d5643adac25
```

Backend:

```text
C:\xampp\htdocs\radio-babasonica-alexa
```

Endpoint:

```text
https://aproposito.ddns.net/radio-babasonica-alexa/public/
```

Stream:

```text
https://aproposito.ddns.net/live/radiobbs/index.m3u8
```

---

# 2. PRUEBAS SMAPI YA CONFIRMADAS

Las siguientes operaciones READ-ONLY ya fueron ejecutadas correctamente:

```text
get-skill-manifest: PASS
get-interaction-model: PASS
get-skill-status: PASS
```

No se ejecutaron escrituras.

## Manifest confirmado

El manifest remoto contiene:

```text
endpoint:
https://aproposito.ddns.net/radio-babasonica-alexa/public/

sslCertificateType:
Trusted

interface:
AUDIO_PLAYER

category:
STREAMING_SERVICE

locale:
es-MX

isExportCompliant:
true

isAvailableWorldwide:
true
```

## Interaction Model confirmado

Invocation name:

```text
radio babasónica
```

Incluye:

```text
PlayRadioIntent
AMAZON.PauseIntent
AMAZON.ResumeIntent
AMAZON.StopIntent
AMAZON.CancelIntent
AMAZON.HelpIntent
AMAZON.FallbackIntent
AMAZON.NextIntent
AMAZON.PreviousIntent
AMAZON.StartOverIntent
AMAZON.RepeatIntent
AMAZON.ShuffleOnIntent
AMAZON.ShuffleOffIntent
AMAZON.LoopOnIntent
AMAZON.LoopOffIntent
```

Skill status:

```text
manifest.lastUpdateRequest.status = SUCCEEDED
```

---

# 3. OBJETIVO DE ESTA FASE

Completar todos los pendientes del bootstrap:

```text
1. guardar Vendor ID
2. actualizar bootstrap results
3. actualizar registry local
4. validar ASK auth final
5. revisar skill existente read-only
6. inspeccionar Apache actual
7. resolver ALEXA_SKILL_ID por proyecto
8. hacer backup antes de cualquier cambio
9. modificar Apache sólo si la solución está clara
10. ejecutar httpd.exe -t
11. NO reiniciar Apache
12. dejar instrucciones para reinicio manual
13. preparar pruebas post-reinicio
14. generar reporte final
```

---

# 4. REGLAS DE SEGURIDAD

NO modificar:

```text
C:\xampp\htdocs\radio-babasonica-alexa
C:\xampp\htdocs\signallive
MediaMTX
mediamtx.yml
FFmpeg
streams
watchdogs
WordPress
app C#
firewall
DNS
certificados SSL
```

salvo que este documento lo permita explícitamente.

NO:

```text
crear nueva Skill
crear radiomp-audio
eliminar Skills
cambiar manifest remoto
cambiar interaction model remoto
crear beta
finalizar beta
enviar certificación
publicar
reiniciar Apache
reiniciar Windows
reiniciar MediaMTX
```

---

# 5. ACTUALIZAR FACTORY CONFIG

Archivo:

```text
C:\xampp\htdocs\aws-api-skill\config\factory.config.json
```

Asegurar que contenga:

```json
{
  "ask_profile": "signal-radio-factory",
  "vendor_id": "MPMP5O0JXSS87"
}
```

Conservar el resto de valores ya existentes.

No reescribir el archivo completo si no es necesario.

Validar JSON después del cambio.

---

# 6. ACTUALIZAR SKILLS REGISTRY

Archivo:

```text
C:\xampp\htdocs\aws-api-skill\config\skills.registry.json
```

Registrar Radio Babasónica como Skill existente externa:

```json
{
  "project_slug": "radio-babasonica-alexa",
  "channel_id": "radiobbs",
  "skill_display_name": "Radio Babasonica",
  "skill_id": "amzn1.ask.skill.005dec3e-f214-4e7e-90ba-2d5643adac25",
  "locale": "es-MX",
  "managed_by_factory": false
}
```

Si ya existe:

```text
actualizar sin duplicar
```

No cambiar:

```text
managed_by_factory=false
```

---

# 7. ACTUALIZAR BOOTSTRAP RESULTS

Archivo:

```text
C:\xampp\htdocs\aws-api-skill\AWS_API_SKILL_BOOTSTRAP_RESULTS.md
```

Actualizar:

```text
Authenticated: YES
Vendor ID: MPMP5O0JXSS87

Manifest read: PASS
Interaction model read: PASS
Skill status read: PASS
No writes executed: YES
```

Actualizar Factory status únicamente al final de esta fase.

---

# 8. REVALIDAR ASK CLI

Ejecutar:

```cmd
ask --version
```

Esperado:

```text
2.30.7
```

Ejecutar:

```cmd
ask smapi get-vendor-list --profile signal-radio-factory
```

Confirmar:

```text
MPMP5O0JXSS87
Ciudad Babasonica
ROLE_ADMINISTRATOR
```

Si falla autenticación:

```text
DETENER FASE
```

No tocar Apache.

---

# 9. READ-ONLY SNAPSHOT DE RADIO BABASÓNICA

Guardar snapshots locales.

Crear:

```text
generated\radio-babasonica-alexa\remote-manifest.json
generated\radio-babasonica-alexa\remote-interaction-model-es-MX.json
generated\radio-babasonica-alexa\remote-status.json
```

Obtener con:

```cmd
ask smapi get-skill-manifest --skill-id amzn1.ask.skill.005dec3e-f214-4e7e-90ba-2d5643adac25 --stage development --profile signal-radio-factory

ask smapi get-interaction-model --skill-id amzn1.ask.skill.005dec3e-f214-4e7e-90ba-2d5643adac25 --stage development --locale es-MX --profile signal-radio-factory

ask smapi get-skill-status --skill-id amzn1.ask.skill.005dec3e-f214-4e7e-90ba-2d5643adac25 --profile signal-radio-factory
```

Guardar stdout exactamente como JSON UTF-8.

No modificar remoto.

---

# 10. INSPECCIÓN DEL BACKEND EXISTENTE

Inspeccionar READ-ONLY:

```text
C:\xampp\htdocs\radio-babasonica-alexa
```

Determinar exactamente cómo se obtiene:

```text
ALEXA_SKILL_ID
```

Esperado:

```php
getenv('ALEXA_SKILL_ID')
```

Documentar:

```text
archivo
clase
método
fallback si existe
comportamiento si variable no existe
```

No cambiar backend.

---

# 11. INSPECCIÓN APACHE

Inspeccionar:

```text
C:\xampp\apache\conf\httpd.conf
C:\xampp\apache\conf\extra\httpd-ssl.conf
```

y cualquier include relevante.

Buscar:

```text
ALEXA_SKILL_ID
SetEnv
SetEnvIf
VirtualHost
Directory
AllowOverride
```

Comando sugerido:

```cmd
findstr /S /N /I "ALEXA_SKILL_ID SetEnv SetEnvIf AllowOverride" C:\xampp\apache\conf\*.conf C:\xampp\apache\conf\extra\*.conf
```

También:

```cmd
C:\xampp\apache\bin\httpd.exe -S
```

Registrar VirtualHost HTTPS real para:

```text
aproposito.ddns.net
```

---

# 12. PROBLEMA A RESOLVER

Existe un riesgo si actualmente se usa:

```apache
SetEnv ALEXA_SKILL_ID "amzn1.ask.skill...."
```

globalmente dentro del VirtualHost HTTPS.

Con dos Skills:

```text
/radio-babasonica-alexa/
/radio-mano-peluda-alexa/
```

cada backend debe recibir su propio Skill ID.

No debe existir un valor global único que aplique a todas las rutas.

---

# 13. EVALUAR ESTRATEGIAS DE AISLAMIENTO

Codex debe comparar al menos estas opciones y elegir la más segura para Apache/XAMPP actual.

## Opción A — SetEnvIf por Request_URI

Ejemplo conceptual:

```apache
SetEnvIf Request_URI "^/radio-babasonica-alexa/" ALEXA_SKILL_ID="amzn1.ask.skill.005dec3e-f214-4e7e-90ba-2d5643adac25"
```

Ventajas:

```text
centralizado
sin tocar backend
fácil de escalar
```

Validar que:

```text
mod_setenvif esté cargado
la variable llegue a PHP
no exista conflicto con PHP/FastCGI/Apache module
```

## Opción B — SetEnv dentro de Directory

Ejemplo conceptual:

```apache
<Directory "C:/xampp/htdocs/radio-babasonica-alexa">
    SetEnv ALEXA_SKILL_ID "..."
</Directory>
```

Evaluar si aplica correctamente al request.

## Opción C — .htaccess por proyecto

Sólo si:

```text
AllowOverride permite FileInfo/All
```

y si no introduce complejidad innecesaria.

## Opción D — config PHP por proyecto

Sólo considerar si Apache resulta poco confiable.

No implementar sin justificar por qué sería mejor.

---

# 14. CRITERIO DE ELECCIÓN

Preferir solución que:

```text
1. no cambie backend
2. no exponga IDs públicamente
3. sea fácil de replicar
4. permita N Skills
5. no use un SetEnv global único
6. sea verificable localmente
7. no afecte otras apps del VirtualHost
```

---

# 15. CREAR APACHE_MULTI_SKILL_PLAN_FINAL.md

Crear:

```text
C:\xampp\htdocs\aws-api-skill\docs\APACHE_MULTI_SKILL_PLAN_FINAL.md
```

Debe contener:

```text
Current state
Detected VirtualHost
Current ALEXA_SKILL_ID directive
Chosen strategy
Rejected alternatives
Exact lines to change
Exact backup path
Expected behavior
Rollback procedure
Validation commands
Post-restart tests
```

---

# 16. BACKUP OBLIGATORIO

Antes de cualquier edición Apache:

crear backup con timestamp.

Ejemplo:

```text
C:\xampp\apache\conf\extra\httpd-ssl.conf.backup-20260821-HHMMSS
```

No sobrescribir backups previos.

Registrar hash SHA-256 de:

```text
original
backup
```

Deben coincidir.

PowerShell:

```powershell
Get-FileHash "C:\xampp\apache\conf\extra\httpd-ssl.conf" -Algorithm SHA256
```

---

# 17. CAMBIO APACHE

Sólo aplicar si:

```text
estrategia clara
backup confirmado
módulo requerido cargado
sintaxis entendida
```

Modificar únicamente lo necesario para Radio Babasónica.

Ejemplo conceptual si se elige SetEnvIf:

```apache
# Alexa Skill ID - Radio Babasónica
SetEnvIf Request_URI "^/radio-babasonica-alexa/" ALEXA_SKILL_ID="amzn1.ask.skill.005dec3e-f214-4e7e-90ba-2d5643adac25"
```

Y remover o comentar el:

```apache
SetEnv ALEXA_SKILL_ID "..."
```

global anterior.

NO agregar todavía segunda Skill.

NO crear Skill ID ficticio para `radiomp-audio`.

---

# 18. VALIDAR APACHE

Ejecutar:

```cmd
C:\xampp\apache\bin\httpd.exe -t
```

Esperado:

```text
Syntax OK
```

Después:

```cmd
C:\xampp\apache\bin\httpd.exe -S
```

Registrar salida relevante.

Si no da Syntax OK:

```text
ROLLBACK INMEDIATO
```

Restaurar backup.

Volver a ejecutar:

```cmd
httpd.exe -t
```

Debe volver a:

```text
Syntax OK
```

---

# 19. NO REINICIAR APACHE

Codex debe detenerse aquí si el cambio fue aplicado.

Mostrar:

```text
WAITING_FOR_MANUAL_APACHE_RESTART
```

El usuario reiniciará Apache desde XAMPP.

No usar:

```text
net stop
net start
httpd -k restart
taskkill
```

---

# 20. CREAR SCRIPT DE VALIDACIÓN POST-RESTART

Crear:

```text
scripts\validate-multi-skill-apache.ps1
```

Debe ser READ-ONLY.

Objetivo:

```text
confirmar que Radio Babasónica sigue funcionando después del reinicio
```

Debe validar:

```text
endpoint HTTPS responde
GET => 405 esperado
POST inválido => JSON controlado
Apache está sirviendo la ruta
Skill backend no expone error de variable ausente
```

No puede fabricar una request firmada válida de Alexa.

Por eso también debe incluir una prueba local segura para confirmar que el backend de Radio Babasónica obtiene el Skill ID correcto.

---

# 21. PRUEBA LOCAL DE ENVIRONMENT VARIABLE

Crear un método de verificación temporal o CLI que NO exponga el Skill ID completo públicamente.

Preferir:

```text
PHP CLI
```

si es posible.

Objetivo:

```text
comprobar que para la configuración Apache elegida
ALEXA_SKILL_ID está disponible en contexto correcto
```

IMPORTANTE:

`SetEnvIf Request_URI` depende de HTTP request y PHP CLI no reproduce Request_URI de Apache.

Si se usa SetEnvIf, la prueba real debe hacerse por HTTP.

En ese caso:

crear temporalmente un archivo de diagnóstico protegido o local-only que devuelva únicamente:

```json
{
  "configured": true,
  "suffix": "ac25"
}
```

Nunca devolver Skill ID completo.

Preferir restringir acceso a:

```text
Require local
```

o usar una ruta temporal accesible sólo desde 127.0.0.1.

Eliminar el diagnóstico al terminar.

---

# 22. PRUEBA HTTP LOCAL POR HOST

Si es posible, probar con:

```cmd
curl.exe -k -H "Host: aproposito.ddns.net" https://127.0.0.1/radio-babasonica-alexa/<diagnostic>
```

o equivalente compatible con el certificado/VirtualHost.

La respuesta debe confirmar:

```text
configured=true
suffix=ac25
```

Después:

```text
ELIMINAR diagnóstico
```

No dejar endpoints de diagnóstico permanentes.

---

# 23. PRUEBA ENDPOINT PÚBLICO POST-RESTART

Después del reinicio manual:

```cmd
curl.exe -i https://aproposito.ddns.net/radio-babasonica-alexa/public/
```

Esperado:

```text
HTTP 405
```

Luego POST inválido:

```cmd
curl.exe -i -X POST ^
  -H "Content-Type: application/json" ^
  -d "{}" ^
  https://aproposito.ddns.net/radio-babasonica-alexa/public/
```

Esperado:

```text
respuesta JSON controlada
NO stack trace
NO 500 por Skill ID
```

---

# 24. PRUEBA SMAPI POST-RESTART

No necesita escribir nada.

Ejecutar:

```cmd
ask smapi get-skill-status --skill-id amzn1.ask.skill.005dec3e-f214-4e7e-90ba-2d5643adac25 --profile signal-radio-factory
```

Debe seguir respondiendo.

---

# 25. PRUEBA FUNCIONAL HUMANA

Codex debe generar instrucciones:

```text
1. abrir Alexa Simulator
2. decir:
   Alexa, abre Radio Babasónica
3. confirmar:
   "Estás escuchando Radio Babasónica."
4. confirmar audio real
5. probar:
   Alexa, pausa
6. probar:
   Alexa, continúa
7. probar:
   Alexa, detente
```

También en Echo físico si el usuario desea validar.

Esta prueba NO puede marcarse PASS automáticamente.

Debe quedar:

```text
PENDING HUMAN TEST
```

hasta confirmación.

---

# 26. PREPARAR SEGUNDA SKILL SIN CREARLA

Actualizar templates para que una futura Skill pueda registrar su ID por proyecto.

La lógica generadora debe producir un fragmento Apache como:

```text
generated\<PROJECT_SLUG>\apache-skill-id.conf.txt
```

Ejemplo genérico:

```apache
# Alexa Skill ID - <SKILL_DISPLAY_NAME>
SetEnvIf Request_URI "^/<PROJECT_SLUG>/" ALEXA_SKILL_ID="<ALEXA_SKILL_ID>"
```

Sólo si esa fue la estrategia aprobada.

No generar valor real hasta que exista Skill ID.

---

# 27. ACTUALIZAR SCRIPTS DE FACTORY

Revisar:

```text
create-radio-skill.ps1
update-radio-skill.ps1
Factory.Common.ps1
```

Objetivo:

cuando una Skill nueva sea creada y obtenga Skill ID:

```text
1. persistir Skill ID
2. generar fragmento Apache
3. detectar si mapping ya existe
4. evitar duplicados
5. hacer backup
6. agregar mapping
7. httpd.exe -t
8. detenerse para reinicio manual
```

No crear Skill nueva en esta fase.

---

# 28. IDEMPOTENCIA APACHE

La función de mapping debe ser idempotente.

Si existe:

```text
PROJECT_SLUG + Skill ID
```

correctos:

```text
NO cambiar archivo
```

Si existe misma ruta con Skill ID diferente:

```text
ERROR
REQUIERE REVISIÓN HUMANA
```

No sobrescribir silenciosamente.

---

# 29. ROLLBACK

Crear función/documentación para:

```text
restaurar último backup válido
```

No automatizar rollback destructivo sin confirmación, excepto si `httpd.exe -t` falla inmediatamente después del propio cambio.

En ese caso sí:

```text
auto-rollback permitido
```

porque restaura el estado previo conocido.

---

# 30. ACTUALIZAR MASTER_STATUS.md

Después de esta fase:

Radio Babasónica:

```text
Project: radio-babasonica-alexa
Channel: radiobbs
Skill Name: Radio Babasonica
Skill ID: amzn1.ask.skill.005dec3e-f214-4e7e-90ba-2d5643adac25
Stage: development
Build: SUCCEEDED
Validation: PASSED / usar último estado conocido
Beta: ACTIVE si se puede comprobar read-only
Echo: HUMAN-CONFIRMED si ya estaba documentado; no inventar
Managed by factory: false
```

No inventar estados no comprobados.

---

# 31. CONSULTAR BETA READ-ONLY SI ES POSIBLE

Si ASK CLI expone:

```text
get-beta-test
get-list-of-testers
```

y existe beta activa, consultar READ-ONLY.

No:

```text
crear
editar
end test
revoke
```

Guardar resultados.

Si la API requiere información adicional no disponible:

```text
NOT RUN
```

No forzar.

---

# 32. ACTUALIZAR BOOTSTRAP FINAL

Después de completar:

```text
AWS_API_SKILL_BOOTSTRAP_RESULTS.md
```

debe decir:

```text
Authenticated: YES
Vendor ID: MPMP5O0JXSS87

Manifest read: PASS
Interaction model read: PASS
Skill status read: PASS
No writes to Alexa resources: YES

Apache multi-skill plan: PASS
Apache backup: PASS
Apache change: PASS / NOT APPLIED
Apache syntax: PASS
Apache restart: PENDING HUMAN / DONE
Post-restart endpoint: PASS / PENDING
Human Alexa test: PASS / PENDING

Ready for DryRun: YES
Ready to create new Skills: YES / NO
```

Sólo marcar:

```text
Ready to create new Skills: YES
```

si:

```text
ASK auth PASS
Vendor ID PASS
templates PASS
scripts PASS
multi-skill Apache strategy PASS
Apache Syntax OK
post-restart environment mapping PASS
```

---

# 33. CREAR REPORTE DE ESTA FASE

Crear:

```text
C:\xampp\htdocs\aws-api-skill\AWS_API_SKILL_MULTI_SKILL_FINALIZATION_RESULTS.md
```

Contenido mínimo:

## ASK

```text
Profile:
Vendor:
Role:
Authenticated:
```

## Radio Babasónica

```text
Skill ID:
Manifest read:
Interaction model read:
Skill status:
```

## Apache

```text
VirtualHost file:
Original directive:
Chosen isolation strategy:
Backup:
Backup SHA256:
Modified:
Syntax:
Restart required:
```

## Environment mapping test

```text
Radio Babasónica mapping:
Expected suffix:
Observed suffix:
PASS/FAIL/PENDING
```

## Regression tests

```text
GET endpoint:
Invalid POST:
Alexa Simulator:
Echo:
Pause:
Resume:
Stop:
```

## Factory readiness

```text
Ready for DryRun:
Ready to create a second Skill:
Blocking items:
```

---

# 34. CRITERIOS DE ACEPTACIÓN

Esta fase sólo se considera terminada cuando:

```text
[ ] Vendor ID guardado
[ ] ASK auth revalidada
[ ] registry actualizado
[ ] snapshots read-only guardados
[ ] Apache inspeccionado
[ ] estrategia multi-skill documentada
[ ] backup Apache creado
[ ] hash backup confirmado
[ ] mapping por proyecto implementado o claramente preparado
[ ] SetEnv global único eliminado si aplica
[ ] httpd.exe -t = Syntax OK
[ ] no se reinició Apache desde Codex
[ ] script post-restart creado
[ ] scripts factory actualizados para mappings futuros
[ ] bootstrap results actualizado
[ ] finalization results creado
[ ] no se creó nueva Skill
[ ] no se modificó Radio Babasónica backend
[ ] no se modificó SignalLive
[ ] no se modificó MediaMTX
[ ] no se publicaron cambios Alexa
```

---

# 35. PUNTO DE DETENCIÓN OBLIGATORIO

Si Codex modifica Apache correctamente:

DETENERSE y mostrar exactamente:

```text
WAITING_FOR_MANUAL_APACHE_RESTART
```

No continuar con pruebas HTTP post-restart hasta que el usuario confirme que Apache fue reiniciado.

---

# 36. SIGUIENTE FASE

Después de completar este documento, la siguiente fase será:

```text
Crear la primera Skill nueva completamente por API/ASK CLI
```

Candidato:

```text
radiomp-audio
```

Pero NO se debe crear durante esta fase.

---

# FIN
