# Yujin Forge -- Estandares de Calidad (SQ)

> **Lectura obligatoria antes de tocar codigo en cualquier
> proyecto Yujin.** Aplica a Sumi (Claude assistant), a
> cualquier colaborador humano, y a cualquier herramienta
> automatizada del pipeline. La violacion de cualquier seccion
> es bug critico, no preferencia.

> Este documento consolida las normas de calidad y entregables
> de Yujin Forge. Se sintetiza con `PROJECT.md` (gobernanza +
> topologia). En caso de conflicto, **este documento prevalece
> sobre cualquier otra preferencia de estilo o conveniencia**.

> Ultima revision: 2026-05-25 (post-bug SyntaxError del panel +
> incorporacion de la regla Pablo-time + agregado de
> volumetrias + stateless + 4 manuales obligatorios).

---

## 0. Principios fundamentales

### 0.1 El tiempo de Pablo es para juicio, no para reproducir bugs

Los humanos tienen tiempo de vida finito. Spending Pablo's
hours on basic bugs (syntax errors, broken buttons, 404s,
missing imports, modals que no abren, files que no cargan,
console errors al cargar) es un debito permanente contra su
budget de vida. **No es recuperable.**

Sumi y CI cazan los bugs basicos ANTES de que Pablo los vea.
Cuando Pablo evalua, evalua decisiones de **alta complejidad
funcional**: "esta voz suena bien para el usuario ADIP?",
"esta extraccion perdio contexto?", "este flujo UX se siente
intuitivo?", "el aleman lee rigido?". Esas son preguntas que
solo el puede contestar. Para esas estan las horas de Pablo,
no para clickear botones que tendrian que andar.

**Esta es la regla mas importante del documento.** Todo lo
demas se deriva de ella.

### 0.2 Cero fallback al codigo legacy del mismo sistema

Si el codigo primario falla, se ARREGLA. **No** se desvia al
renderer / handler / rutina obsoleta del mismo sistema. El
patron `if (newFn) {...} else { legacyFn() }` esta prohibido
cuando ambas vias pertenecen al mismo codebase.

Fallback **legitimo** (NO bloqueado por esta regla):
- Multi-region failover (us-east-1 → eu-west-1).
- Multi-provider (SES → SendGrid, Anthropic Claude → Bedrock
  cuando rate-limited).
- Schema gates idempotentes (table missing → skip silencioso
  con warning + return).
- Cache miss (APCu vacio → DB query).
- Locale i18n (es missing → en → first available).

Cualquier otro fallback es regression disfrazada.

### 0.3 Cero dano silencioso

Cuando el sistema no puede satisfacer un request (ambiguo, no
encontrado, bloqueado, gate fallo), **debe** throw o devolver
`is_error: true` con un mensaje estructurado nombrando el
remedio. **NO** debe adivinar + degradar + esperar.

### 0.4 Calidad industrial

Naming claro. Errores estructurados. Provenance emitida (trace
en pizarra para chat tools, audit log para acciones en DB).
Docs sincronizadas. Nada hardcoded que pertenezca a un catalogo.
Nada que un reviewer pueda llamar atajo.

### 0.5 Agnostico por default

Los layers del sistema saben de primitivas (formatos de
documento, providers de voz, tool_use de Claude, file
scaffolding, schemas de manifest NAC3). Saben **nada** de
ninguna app especifica. Logica especifica de aplicacion vive
en templates, manifests, plugins, decorators — nunca en el
runtime.

### 0.6 Definicion de "proyecto Yujin"

**Un proyecto Yujin es CUALQUIER codebase tocado por Forge**,
en cualquiera de estas dos modalidades:

1. **Proyectos nuevos** creados por Forge:
   - `yf new <slug>` -- scaffold inicial desde template.
   - `yf migrate ... --ai-silent` que produce un decorated output.
   - Scaffold generado por el spec ingest pipeline
     (bloque 4.5: drag-drop spec -> Claude extract -> plan ->
     approve -> escribir archivos).
   - Cualquier proyecto que arranque su vida desde Forge.

2. **Proyectos existentes** modificados por Forge:
   - `yf migrate <existing-repo>` con o sin `--apply`.
   - File edits via chat panel + tool dispatches
     (forge.git_commit, forge.run_app, etc).
   - Decoration que Forge inyecta en una app pre-existente.
   - Cualquier commit que tenga "Co-Authored-By: Forge" o
     equivalente.

**No hay opt-out.** Si Forge toco el proyecto, **el proyecto
es Yujin y queda sujeto a este SQ**.

Esto vale tanto para apps propias (CRM Yujin, conduit,
yujin.app) como para apps de adopters (ADIP, third-party).
Si quieren que Forge ayude, aceptan el SQ.

### 0.7 Componentes obligatorios en TODO proyecto Yujin

Todo proyecto Yujin (segun sec 0.6) **debe** incluir:

1. **NAC-3 decoration** al nivel apropiado para el target
   (HTML estatico, React app, Vue app, Vanilla JS). Cada
   elemento interactivo carga `data-nac-id` + `data-nac-role`
   + `data-nac-action` segun el contrato NAC-3.

2. **Yujin Pilot embebido -- OBLIGATORIO**, no opcional.
   Pilot es el chat + voice cockpit multi-modelo que drives
   la app desde lenguaje natural. La razon de la
   obligatoriedad:

   - Sin Pilot, el end-user no tiene como hablarle a la app
     decorada con NAC-3 -- los hooks existen pero nadie los
     invoca.
   - Pilot es lo que convierte "una app decorada" en "una
     app Yujin" desde el punto de vista del usuario final.
   - Pilot impone una experiencia consistente cross-product
     (mismo modal, mismas opciones de provider, misma
     pizarra de trace).
   - Pilot es la unica via reconocida para inyectar la
     dispatcher de NAC-3 disambiguation con el modelo cheap-
     fast (ver memoria `nac3-disambiguation-model-split`).

   No se acepta "el cliente no quiere Pilot". Si el cliente
   no quiere Pilot, no es proyecto Yujin -- Forge no lo
   toca. Esa conversacion va a Pablo, no al desarrollador
   que arma el proyecto.

   La inyeccion de Pilot la hace `yf migrate --with-pilot`
   automaticamente, o `yf pilot install <dir>` explicito.
   El test de aceptacion del proyecto verifica que Pilot
   carga + dispatch llega + provider keys persisten
   (cubierto por la suite visual del proyecto, sec 2.2).

3. **10 idiomas canonicos NAC3** en strings user-facing
   (ver sec 2.6).

4. **Los 4 manuales** del sec 3 (INFRASTRUCTURE,
   ARCHITECTURE, USER_MANUAL, MAINTENANCE_MANUAL).

5. **Tests de cobertura visual al 100%** (sec 2.2).

6. **Pre-development checklist completo** (sec 4) antes de
   cualquier modificacion.

La ausencia de cualquiera de estos 6 componentes es bug
critico del proyecto, no preferencia. Forge debe negarse a
shipping un proyecto Yujin con componentes faltantes.

### 0.8 Dual mode de comunicacion: didactico vs tecnico

Forge expone sus consultas, ronda de clarificacion y
resultados en **dos modos**, configurables por proyecto y
cambiables en runtime:

**(a) Modo didactico (default para usuarios no-dev):**

- Exposicion **minima** de datos tecnicos (no stack traces,
  no nombres de archivos / lineas, no jerga JS / SQL).
- **Mayor autonomia**: Forge decide los detalles tecnicos
  internos por su cuenta y solo consulta al usuario lo
  estrictamente necesario para entender que quiere lograr.
- Consultas siempre en lenguaje natural orientado a
  resultados ("cuantos usuarios al mismo tiempo?", no
  "concurrent connections cap?").
- Mensajes de progreso: "ya generamos el formulario de
  registro", no "wrote `app/register.tsx` (42 lines)".
- Errores presentados como acciones: "no pude leer este PDF.
  Probemos con otro archivo?", no "ParseError at line 87".

**(b) Modo tecnico (para programadores avanzados):**

- Exposicion **completa**: archivos tocados, lineas
  modificadas, tool calls disparados, latencias, tokens, etc.
- **Involucra al usuario** en las decisiones tecnicas:
  "elegimos Postgres o SQLite para este target? Costos vs
  portabilidad..."
- Surface diffs antes de aplicar; pide confirmacion para
  cambios irreversibles.
- Stack traces visibles; errores con error_id + request_id.
- Mensajes de progreso con metadata: "scaffolded
  `app/register.tsx`, 42 lines, 3 components".

**Activacion:**

1. Per-proyecto: `yujin.forge.json` lleva `"mode":
   "didactico" | "tecnico"`. Default: `"didactico"`.
2. Runtime via chat: comando `/modo didactico` o
   `/modo tecnico` (alias EN: `/mode didactic`,
   `/mode technical`). Se persiste en `yujin.forge.json`.
3. Runtime via CLI: `yf chat --mode didactico|tecnico` o
   variable de entorno `YF_MODE=tecnico`.

**Contrato:** ambos modos respetan la misma arquitectura
(stateless, multi-tenant, etc). El cambio de modo afecta
**solo la capa de presentacion + el nivel de consulta**, no
los outputs funcionales.

**Implementacion (referencia):** el server inyecta `mode` en
el system prompt del LLM + el panel UI consulta `mode` para
decidir si renderiza diffs / stack traces / tool latencias.
Cambiar el modo NO requiere recargar -- el siguiente turno
ya usa el modo nuevo.

### 0.9 Test Playwright -- aprobacion visual explicita

El test visual de un proyecto Yujin debe **mostrar todas las
pantallas aplicativas al usuario** y exigir su OK explicito
o registro de pedidos de modificacion. No es suficiente que
los tests pasen verdes en CI; el usuario tiene que **ver**
cada pantalla.

Flujo obligatorio:

1. La suite Playwright captura screenshot de **cada pantalla
   aplicativa** del proyecto (entry, hub, list views, detail
   views, modals, forms, error states) bajo
   `tests/visual/evidence/<scenario>/<lang>/<browser>.png`.

2. Forge expone un comando `yf review-screens` que renderiza
   una galeria local con todas las screenshots organizadas
   por flow + idioma + breakpoint. El usuario navega y marca
   cada una con:
   - **OK explicito** (verde) - se promueve a baseline.
   - **Pedido de modificacion** (rojo) - se registra el
     comentario; Forge abre un issue / task para el ajuste.
   - **No revisado** (amarillo) - bloquea release.

3. **Gate**: no hay release si quedan screenshots "no
   revisadas" o "pedido de modificacion sin resolver".

4. La galeria opera en ambos modos (sec 0.8): didactico
   muestra solo la imagen + boton OK / pedir cambio; tecnico
   incluye selector breakpoint + lang + browser + diff vs
   baseline.

Esto vive como capa SOBRE la regresion visual (sec 6) -- la
regresion garantiza que no hay drift entre runs; este punto
garantiza que el usuario aprobo la version actual al menos
una vez.

### 0.10 Consulta de target: desktop+mobile vs mobile-pure

En el pre-development checklist (sec 4), Forge **debe**
preguntar al usuario:

- **Target**: ¿la app es desktop compatible con mobile
  (responsive web) o **solo mobile** (RN/PWA mobile-only)?
- **Set de funcionalidades por target**: si la respuesta es
  "ambos", consultar que features estan solo en desktop, solo
  en mobile, o cross. Esto es input al `spec.plan` -- afecta
  scaffolding, layout patterns, voice loop strategy, ingest
  flows, etc.

La respuesta queda escrita en `yujin.forge.json`:

```json
{
  "target": "responsive" | "mobile-only" | "desktop-only",
  "feature_split": {
    "desktop_only": ["bulk-edit", "csv-export"],
    "mobile_only": ["geolocation", "camera-ingest"],
    "shared": ["..."]
  }
}
```

Esta consulta es **obligatoria** porque cambia:

- El template scaffold (web/Expo/PWA).
- Los componentes NAC3 disponibles (algunos primitives no
  tienen contraparte mobile sin refactor).
- Las queries de spec.extract (un "lista de clientes" en
  desktop tiene paginacion + bulk; en mobile es scroll
  infinito + swipe).
- Los manuales (USER_MANUAL adapta screenshots y flujos por
  target).
- La estrategia de voice loop (mobile prefiere on-device
  STT por latencia / privacy).

Mode-didactico (sec 0.8) presenta la pregunta como:
"¿queres que la gente la use en su computadora, en su
celular, o en los dos?"

Mode-tecnico la presenta como: "target: responsive (web
desktop + mobile breakpoints) vs mobile-only (Expo RN
single-target) vs desktop-only (Electron / web only). Feature
split JSON?"

### 0.11 Autonomia operacional via vault de credenciales

Forge debe poder ejecutar el ciclo completo
**analisis -> desarrollo -> commit -> push -> publish ->
ejecucion** sin exponer claves al usuario ni a los logs.

Esto requiere:

1. **Mecanismo unificado de ingreso de credenciales al
   vault.** Slots tipados, ABM completo, encrypted at rest
   (AES-256-GCM), con UI en chat y CLI:

   - **Repositorios git**: GitHub PAT (`github_token`),
     GitLab token (`gitlab_token`), Bitbucket app password
     (`bitbucket_token`), generic ssh key (`ssh_key`).
   - **Registries**: npm (`npm_token`), pypi
     (`pypi_token`), maven (`maven_token`),
     docker (`docker_token`), homebrew (`homebrew_token`).
   - **AI providers**: Anthropic (`anthropic`), OpenAI
     (`openai`), Google (`google_voice`), ElevenLabs
     (`elevenlabs`), Whisper API si separado.
   - **Cloud**: AWS access key + secret (`aws_access_key_id`,
     `aws_secret_access_key`), GCP service account JSON
     (`gcp_service_account`), Azure SP
     (`azure_service_principal`).
   - **App-specific** (apps relacionadas al proyecto):
     Slack bot (`slack_bot_token`), Discord
     (`discord_bot_token`), Twilio (`twilio_*`), Stripe
     (`stripe_*`), Sendgrid (`sendgrid_*`), Mailgun
     (`mailgun_*`), Linear (`linear_token`), Notion
     (`notion_token`), Figma (`figma_token`).
   - **Custom**: cualquier slot definido por el proyecto en
     `yujin.forge.json::vault_slots[]`.

2. **API contract**:

   - `POST /api/vault/keys { name, value, kind?, expiry? }`
     - `kind` = `repo | registry | ai | cloud | app | custom`
     - `expiry` opcional, dispara rotacion alert.
   - `GET /api/vault/keys` -> lista slots con
     `value_preview: '****abcd'`, NUNCA el raw.
   - `DELETE /api/vault/keys/{name}`.
   - `POST /api/vault/test/{name}` -> prueba la credencial
     contra el servicio (e.g. para `github_token`, hace
     `GET https://api.github.com/user` y devuelve si
     responde 200).

3. **Inyeccion sin exposicion al usuario**:

   Forge consume credenciales **server-side only**. Reglas:

   - Comandos shell ejecutados por Forge **nunca** ven la
     credencial en el comando (ni en logs ni en history del
     shell). Se inyectan via `env: { GITHUB_TOKEN: ... }` en
     el `spawn()`, no como argv.
   - Tool calls de Claude **nunca** reciben el valor raw.
     Reciben referencias (`{ vault_ref: "github_token" }`).
     El servidor resuelve la ref al momento de invocar la
     API externa.
   - Mensajes al usuario en chat **redactan** secretos
     pegados accidentalmente. Si un texto contiene un
     pattern de token conocido (`ghp_*`, `sk-ant-*`, etc),
     se reemplaza por `****redacted****` antes de mostrar.
   - Logs server-side aplican la misma redaccion.

4. **Lifecycle completo autonomo (escenarios soportados):**

   - **Inicializar repo nuevo**: GitHub repo create + first
     commit + push, usando `github_token` del vault.
   - **Commit + push**: cualquier momento, usando
     `github_token` (no SSH key del user que pueda no estar).
   - **Publicar a npm**: `npm publish --tag X` con
     `npm_token` inyectado via `NPM_TOKEN` env.
   - **Publicar imagen Docker**: `docker push` con
     `docker_token`.
   - **Ejecutar la app en el cloud**: deploy a AWS / GCP /
     Azure con la credencial cloud correspondiente.
   - **Llamar APIs externas durante runtime**: cualquier
     tool call que requiera un secret lo resuelve via
     vault sin pasar por el modelo Claude.

5. **Audit trail**:

   Cada uso de una credencial genera una linea en
   `vault.audit.log` (encrypted, append-only) con:
   `{ ts, slot_name, op, request_id, success }`. El
   contenido del valor NO se loggea. La intencion es que el
   user pueda auditar **que credenciales se usaron y cuando**
   sin exponer el valor.

6. **UX por modo (sec 0.8):**

   - **Didactico**: el chat consulta "tenes una clave de
     GitHub configurada para que pueda hacer commits?"
     y si no, ofrece "queres pegarla aca? la guardo cifrada
     y nunca te la vuelvo a pedir".
   - **Tecnico**: muestra el listado actual de slots con
     status (test result, expiry) y permite `vault add`,
     `vault rotate`, `vault test`, `vault remove` desde
     chat o CLI.

7. **Gate de release** (consistente con sec 0.7):

   Forge **rechaza** ejecutar acciones que requieren un
   secret si el vault no lo tiene. Mensaje en didactico:
   "necesito una clave de X para esto. La cargas?". Mensaje
   en tecnico: "missing vault slot: X (required for
   operation Y)". **Nunca** se pide al usuario que pegue el
   secret en el chat plano sin enmascarar.

8. **Cero deuda con credenciales legacy**:

   Si un proyecto Yujin todavia tiene credenciales en
   archivos `.env` / `config.json` / hardcoded, el migrador
   las mueve al vault al primer touch de Forge + las elimina
   del archivo original + agrega entrada al `vault.audit.log`.

Esta seccion convive con sec 8 (activos estrategicos):
- Sec 8 protege el IP de Yujin (prompts, heuristicas) del
  desarrollador-cliente.
- Sec 0.11 protege las credenciales del cliente del desarrollo
  asistido por Forge.

Son dos vaults distintos conceptualmente: el primero vive
server-side en yujin.app (sec 8); el segundo vive local en
la maquina del desarrollador (sec 0.11), AES-GCM con
passphrase del usuario.

---

## 1. Antes de tocar codigo

### 1.1 Lectura obligatoria de documentacion del proyecto

ANTES de hacer cualquier modificacion en un proyecto Yujin,
es obligatorio leer **toda** la documentacion del proyecto.
No "leí lo que necesitaba". Lectura completa o no se toca
nada.

Set minimo:

1. `README.md` — overview, install, status.
2. `PROJECT.md` — gobernanza, topologia, ciclo de trabajo.
3. `SQ.md` (este archivo) — estandares de calidad.
4. `docs/ARCHITECTURE.md` o `docs/HITO_*_ARCHITECTURE.md`.
5. `docs/USER_MANUAL.md` (o equivalente del proyecto).
6. `docs/MAINTENANCE_MANUAL.md`.
7. `docs/INFRASTRUCTURE.md`.
8. `CHANGELOG.md` — historia reciente.
9. `docs/RFC/` o `rfcs/` — decisiones propuestas / aprobadas
   / implementadas.
10. `docs/decisions/` cuando exista — ADRs.

Si **cualquiera** de estos docs no existe en el proyecto:
- Levantar la falta antes de modificar codigo.
- Proponer creacion del doc faltante como primer slice.
- Si Pablo dice "skip", documentar el skip en commit
  message + memoria.

Esta regla previene tres clases de error:

- **Refactor contra el design explicito** (el README explicaba
  el porque, y rompi el invariante).
- **Tocar areas con invariantes que el codigo no se lee**
  (la regla esta en MAINTENANCE_MANUAL, no en el codigo).
- **Repetir bugs ya documentados** (el incident anterior tiene
  runbook + post-mortem, lo replicamos por no leerlo).

### 1.2 Volumetrias antes de arquitectura

ANTES de proponer arquitectura para una feature nueva o un
proyecto nuevo, **obligatorio** preguntar al stakeholder
estas volumetrias:

| Volumetria | Pregunta concreta al stakeholder |
|---|---|
| Usuarios concurrentes | "Cuantos usuarios estaran activos simultaneamente en pico?" |
| Requests / segundo | "Que tasa de requests/segundo esperas en pico?" |
| Volumen de datos | "Cuanto data se va a generar / almacenar diaria / mensualmente?" |
| Latencia aceptable | "Cual es la latencia p95 / p99 aceptable para esta feature?" |
| Disponibilidad esperada | "Cual es el SLA esperado? 99.9% / 99.99%?" |
| Geografia | "Usuarios en una region o multi-region?" |
| Picos esperados | "Hay eventos predecibles que multipliquen la carga? (lanzamientos, fin de mes, horarios)" |
| Crecimiento proyectado | "Que crecimiento esperas en 6 / 12 / 24 meses?" |
| Tolerancia a fallos | "Cuanto downtime es aceptable en una semana / mes?" |
| Tipo de carga | "Read-heavy / write-heavy / balanced?" |

**Sin volumetrias, la arquitectura es adivinacion y la
implementacion es deuda tecnica garantizada.**

Las respuestas determinan:

- Stack tecnologico viable (Postgres vs DynamoDB vs Cassandra,
  monolito vs microservicios).
- Necesidad de cache distribuido (Redis, Memcached), CDN, edge
  computing.
- Workers stateless escalables horizontal vs stateful con
  pinning.
- Read replicas, sharding, particionamiento.
- Queues asincronas (SQS, RabbitMQ, Kafka) vs RPC sincronico.
- Provisioning: serverless (Lambda) vs containers (ECS) vs
  bare metal.
- Geo-distribution + multi-region active-active vs DR
  passive.

### 1.3 Solicitudes simultaneas + soluciones escalables

Para cada flow del proyecto, ANTES de implementar:

1. **Inferir** `concurrency_p95` (pico de solicitudes
   simultaneas), `rps_avg` (tasa sostenida), patron
   read-heavy / write-heavy / balanced.
2. **Documentar** la inferencia en el RFC / HITO doc:
   "asumimos `concurrency_p95 = N` segun volumetria 1.2.X".
3. **Proponer** arquitectura que soporte esos numeros con
   margen de 3x para crecimiento.
4. **Enumerar las ventajas** del approach elegido (no asumir
   que Pablo "ya entiende"; escribirlo).

#### Preferencia obligatoria: stateless

#### Ventajas de soluciones stateless (las 10 que justifican la preferencia)

1. **Horizontal scaling sin estado compartido.** Se agregan
   instancias sin coordinacion previa. El load balancer
   distribuye, cualquier instancia sirve cualquier request.
2. **Recuperacion instantanea de fallas.** Una instancia
   muere, el LB rutea a otra, **sin perdida de sesion del
   usuario**.
3. **Deploy sin downtime.** Rolling deploys porque cualquier
   instancia sirve cualquier request. Blue/green es trivial.
4. **Predictibilidad de costos.** Escalar es lineal con load,
   sin overhead de coordinacion / sincronizacion / locks
   distribuidos.
5. **Testing mas simple.** Cada request es self-contained,
   no necesita setup de estado previo. Tests paralelos
   sin colision.
6. **Independencia de orden de procesamiento.** Los workers
   procesan en cualquier orden sin afectar correctness.
7. **Compatibilidad con caches.** Las respuestas son
   cacheables por (input, version). CDN edge cache es viable.
8. **Diagnostico mas simple.** Replay de un request da el
   mismo resultado. Bug bisection trivial.
9. **Migracion entre regiones / providers mas simple.** Sin
   state local que migrar.
10. **Capacidad de spot / preemptible instances.** Perdida de
    instancia = perdida de un request a lo sumo, que el
    retry resuelve.

#### Atomizacion obligatoria de acciones

- Cada operacion debe ser **atomica** (idempotente cuando es
  posible).
- Operaciones largas se rompen en steps que se pueden
  retry independiente.
- Estado intermedio en stores externos (DB, queue), **no** en
  memoria del proceso.
- Cualquier operacion que tarde > 100ms debe ser cola
  asincrona, **no** RPC sincronico.
- Las queues son la unidad de retry — si falla un step, el
  siguiente arranca la proxima vez.

#### Cuando se rompe el "stateless preferido"

Solo en estos casos:

- Conexiones WebSocket persistentes (chat real-time, voice
  full-duplex).
- Streams de media (TTS playback, video conferencing).
- Calculos pesados que ya cargaron data en memoria (Spark
  workers, ML inference con modelo de 10GB).
- Hardware especializado pegado a una instancia (GPU
  exclusiva).

En estos casos, el state debe estar:

- Documentado en `docs/STATEFUL_COMPONENTS.md` con la razon
  exacta.
- Aislado en un componente especifico (no contaminar el
  resto del sistema).
- Tener backup / failover / DR plan documentado.
- Tener metrica + alerta que dispare cuando el componente
  baja de capacidad.

---

## 2. Estandares de codigo

### 2.1 Tests

- **100% test pass.** `npm test` retorna exit 0 con cero
  FAIL en Linux + macOS + Windows. Pre-existing failures
  NO son aceptables — se arreglan o se borran. No existe
  "known-failing-but-not-our-fault".
- **TDD por slice.** Escribir tests RED antes de implementar.
  Implementar. Commit GREEN. Saltarse TDD solo en
  extractors / formatters triviales donde el test seria un
  1:1 mirror del impl.
- **Evidencia requerida.** Cada slice cita los tests que pasan
  en el commit message + CHANGELOG. Si un slice no apunta a
  un test verde, no es slice — es draft.
- **Seams mockeables.** Cada llamada a Claude, cada `fetch`,
  cada `fs` write, cada spawn, cada captura de audio es
  alcanzable via DI seam para que los unit tests corran
  offline sin keys.

### 2.2 Coverage 100% de interfaces visuales

**Regla incorporada 2026-05-25 despues del bug del
SyntaxError en el panel:** toda interfaz visual de Yujin
(panel de chat incluido, modales, dropdowns, drag-drop
overlays) se cubre al 100% con tests Playwright headless
que ejercen **dialogos de alta complejidad** y **todas las
funciones del producto**, no solo "carga sin errores".

Detalle completo en `PROJECT.md` sec 3.1.1. Resumen aplicable
a cualquier proyecto Yujin:

- Boot smoke: panel carga con cero `console.error` /
  `pageerror`.
- Functional smokes: cada funcion visible tiene al menos un
  scenario end-to-end.
- High-complexity dialogues: conversaciones multi-turn con
  Claude scripteado realista que encadenan tools.
- Cross-language: cada scenario corre en los 10 idiomas
  cuando aplica.
- Cross-browser: chromium + firefox + webkit.
- Visual regression: screenshots vs baselines.
- Audio + media: con stubs deterministicos.

**Vitest no es suficiente.** Vitest cubre endpoints + pure
functions. **No** ejecuta el JS inline del browser. Reportar
"X tests verde" sin haber corrido Playwright es claim falso.

### 2.3 Coverage 100% backend

- Cada funcion publica del runtime tiene test unitario.
- Cada endpoint HTTP tiene test de integracion (happy path
  + 1 error path minimo).
- Cada plugin / handler tiene test de su flow.

### 2.4 Codigo style

- **ASCII puro** en codigo fuente TS/JS (`src/**`,
  `scripts/**`). Sin unicode arrows, em-dashes, smart quotes.
  Catalogos i18n + manuales HTML son la excepcion — esos
  cargan unicode por diseno.
- **TypeScript** first. `tsx` para dev, `tsc` para build,
  `dist/` para npm.
- **camelCase** JS/TS variables.
- **PascalCase** clases + interfaces.
- **snake_case** JSON keys + on-the-wire fields.
- **kebab-case** CLI subcommands + filenames cuando aplica.
- **Function declarations** en module top-level. Arrow
  expressions OK para inline callbacks.
- **Comments explican el POR QUE**, no el QUE. Default a sin
  comment. Comment solo cuando el por que no es obvio
  (constraint oculto, invariante sutil, workaround
  sorprendente, referencia a spec).
- **TypeScript strict** activo: `noUncheckedIndexedAccess`,
  `strict: true`, `noImplicitOverride`. No relajar.

### 2.5 Build + deploy

- `npm run build` corre `tsc`. Output a `dist/`. Codigo
  fuente siempre en `src/`.
- `npm run prepublishOnly` corre build + typecheck +
  catalog:lint + test. **No bypassear.** Es el publish gate.
- `npm publish --tag alpha` desde un estado verificado.
  Promote a `latest` solo en GA cut.
- `npm publish --dry-run` despues de tocar `files` glob.

### 2.6 Multi-language: 10 idiomas canonicos NAC3

Forge y todo proyecto Yujin enforece la **regla 10 idiomas**:
`es, en, pt, fr, ja, zh, hi, ar, de, it`.

- Cada string user-facing pasa por `t('key')` /
  `tForLang(lang, 'key')`.
- Catalogos: `src/i18n/catalogs/<lang>.json` (10 archivos).
- Espanol es source of truth. Cada otro locale debe contener
  todas las keys de es.
- `catalog-lint` enforces parity. `prepublishOnly` corre
  catalog-lint como gate.
- HTML manuales: uno por idioma en `docs/manuals/manual.<lang>.html`.
- Voice intents extendidos a 10 idiomas con verbos por
  idioma.

Ver `docs/LANGUAGE_POLICY.md`.

### 2.7 Provenance

Cada accion que el sistema dispatcha emite un evento
estructurado: `{tool, input, display, is_error,
via_voice?, voice_pattern?, voice_utterance?, ...}`. Es lo
que da trazabilidad para auditoria + debugging.

- **No suprimir silenciosamente** trace entries, ni siquiera
  en failure paths.
- **VOZ badge** + utterance + pattern slug en dispatches
  voice-driven.
- **tool_rounds** en cada respuesta `/api/chat`.

### 2.8 Security boundaries

- **Vault** (`src/vault/` cuando aplica): AES-256-GCM,
  scrypt KDF, machine-fingerprint binding, atomic writes
  `0o600`, one-shot reveal, never re-displayable.
- **Direct-dispatch endpoint** (`/api/forge/tool` o
  equivalente) whitelist solo a tools read-only. Write-class
  pasa por `/api/chat` con approval flow.
- **Approval gates** en operaciones destructivas (file
  scaffolding, scaffolds, pushes, deletes): explicit
  `{approve: true}` requerido.
- **Path-escape validation** en cualquier handler que
  resuelve paths del usuario: rechazar absolute paths, `..`,
  drive letters; resolver contra `projectRoot` y verificar
  prefix.
- **Voiceprint liveness** mandatorio para irreversible ops.
- **Cost gates** dobles (env + impl installed) para
  operaciones que pueden charge tokens.

### 2.9 Single source of truth para modelos LLM

El identificador de modelo Claude / OpenAI / Gemini / etc.
vive en **una sola** ubicacion por proyecto (e.g.
`src/version.ts` para version, `core/AiModel.php` para
modelos en CRM, o equivalente). Rolling over a un modelo
nuevo es un cambio de 1 linea, no buscar y reemplazar 50
archivos.

---

## 3. Entregables por proyecto -- 4 manuales obligatorios

Cada proyecto Yujin debe emitir y **mantener** estos cuatro
manuales en formato Markdown legible:

### 3.1 `docs/INFRASTRUCTURE.md` — Manual de infraestructura

Contenido obligatorio:

- Diagrama de infraestructura (mermaid, ASCII art, o link
  a un PNG).
- Servicios externos: cuales son, para que se usan, donde
  estan los slots de credenciales (sin las credenciales
  mismas).
- Variables de entorno necesarias + valores ejemplo + valores
  prohibidos.
- Puertos, hostnames, DNS records configurados.
- Backups: que se respalda, donde, frecuencia, retention,
  cifrado.
- Restore procedure: tested + documented step-by-step.
- Monitoring: que metricas se emiten, donde se visualizan
  (CloudWatch / Grafana / etc).
- Alertas: cuales estan configuradas, threshold, a quien
  notifican.
- Capacity planning: limites actuales, headroom, trigger de
  scaling.

### 3.2 `docs/ARCHITECTURE.md` — Manual de arquitectura

Contenido obligatorio:

- **Decision arquitectonica principal** y por que (incluyendo
  alternativas descartadas).
- **Volumetrias acordadas** segun sec 1.2 de este SQ.
- **Stack tecnologico** + razon de cada eleccion.
- **Diagrama de modulos** (modulos internos + sus relaciones).
- **Diagramas de flow** de happy paths (top 5 minimo).
- **Diagramas de flow de failure paths** (top 5 minimo).
- **Boundaries** entre componentes: que componente conoce que.
- **Acoplamiento**: que requiere que (idealmente: tabla).
- **Data model**: schemas + relaciones + indices.
- **Concurrency model**: como se asegura correctness bajo
  carga concurrente (locks, optimistic, eventual
  consistency, etc).
- **Threat model**: que protege el sistema y contra que.

### 3.3 `docs/USER_MANUAL.md` — Manual de usuario (o variantes por idioma)

Contenido obligatorio:

- Guia paso a paso para el usuario final.
- En el idioma del usuario (los 10 NAC3 cuando aplica;
  multiples archivos `docs/manuals/manual.<lang>.html` o
  `docs/USER_MANUAL.<lang>.md`).
- Screenshots / GIFs cuando corresponda (en `docs/assets/`).
- Troubleshooting de los 10 problemas mas comunes.
- Contacto de soporte.

### 3.4 `docs/MAINTENANCE_MANUAL.md` — Manual de mantenimiento

Contenido obligatorio:

- **Procedure de deploy** step-by-step + rollback.
- **Procedure de rollback** independiente del deploy.
- **Runbook de los 10 incidents mas comunes** + diagnostico
  + remedio.
- **Como agregar capacidad** (vertical y horizontal).
- **Como investigar un incident** (logs, metricas,
  herramientas).
- **Logs**: donde estan, formato, rotation, search.
- **Metricas**: donde estan, umbrales normales / warning /
  critical.
- **Dependencias externas**: que pasa si X cae, RPO/RTO de
  cada una.
- **Procedure de DR** (disaster recovery).
- **Procedure de re-key** + rotacion de credenciales.

### Formato de los manuales

- **Markdown plano**, sin frameworks (no Docusaurus, no
  MkDocs custom). Renderable en GitHub web view sin
  extensiones.
- **Cada doc < 2000 lineas**; si supera, separar en
  subdocs linkeados.
- **Headings nivelados**: H1 titulo, H2 secciones, H3
  subsecciones.
- **Tablas** para data tabular.
- **Code blocks** con language tag.
- **Diagramas** preferentemente en mermaid (texto-as-data)
  o ASCII art. Si PNG, en `docs/assets/`.
- **Linkeable** desde el README del proyecto.

### Mantenimiento de los manuales

- **Cada slice** que afecta una seccion de un manual
  actualiza el manual en el **mismo commit** (regla
  doc-update invariant, PROJECT.md sec 2.4).
- **Manuales obsoletos son bug critico** — al detectarlo,
  levantar issue + parchear.
- **Pasada trimestral** de re-validacion: alguien (humano
  + Sumi) lee los manuales pretendiendo no saber nada del
  sistema, y reporta secciones que ya no representan la
  realidad.

---

## 4. Pre-development checklist

Antes de hacer cualquier slice de codigo, Sumi pasa por
este checklist. **Si cualquier item falla, el slice NO
arranca** — se hace el item primero, despues se arranca el
slice.

- [ ] Lei `README.md` del proyecto.
- [ ] Lei `PROJECT.md`.
- [ ] Lei este SQ.md.
- [ ] Lei `docs/ARCHITECTURE.md` o `docs/HITO_*_ARCHITECTURE.md`.
- [ ] Lei `docs/USER_MANUAL.md` (o equivalente).
- [ ] Lei `docs/MAINTENANCE_MANUAL.md`.
- [ ] Lei `docs/INFRASTRUCTURE.md`.
- [ ] Lei el `CHANGELOG.md` reciente.
- [ ] Para feature nueva: pedi las volumetrias (sec 1.2).
- [ ] Para feature nueva: defini el target de `concurrency_p95`
      (sec 1.3).
- [ ] Para feature nueva: propuse arquitectura stateless O
      justifique stateful en `STATEFUL_COMPONENTS.md`.
- [ ] Para feature nueva: enumere las 10 ventajas (o subset
      aplicable) del approach elegido (sec 1.3).
- [ ] El plan tiene tests Playwright para las visual
      interfaces que toca.
- [ ] El plan actualiza los 4 manuales en el mismo PR si
      la feature los toca.
- [ ] Hable con Pablo si encontre contradicciones entre
      docs o invariantes.

---

## 5. Reporte de "ready" — disciplina

Cuando Sumi reporta que un slice esta listo, la frase debe
contener **estos cuatro componentes**:

> X vitest cases + Y Playwright scenarios green. Console +
> page errors empty on all 3 browsers + all 10 languages
> exercised for affected surfaces. Screenshots diff: 0
> baseline changes. Evidence updated at
> `tests/evidence/<scenario>/`.

Si **alguno** de los cuatro componentes no aplica o no esta
verde, **no se dice "ready"**. Se dice "blocked on
[componente]" + ETA concreta.

Esto protege el tiempo de Pablo (sec 0.1).

---

## 6. Evidencia visual permanente

Cada Playwright run guarda screenshots de la **ultima
ejecucion exitosa** en `tests/evidence/<scenario>/<lang>/<browser>.png`.

- Failed runs **NO** sobreescriben la evidencia previa.
- Committed al repo como visual changelog.
- Actualizado en el mismo commit que el codigo cuando el
  scenario cambia intencionalmente.
- < 200 KB por PNG; 1280 wide max.

Detalle en `PROJECT.md` sec 3.1.1 subseccion "Evidence
folder".

---

## 7. Memoria de decisiones

Cada decision arquitectonica no-trivial se documenta en uno
de:

1. `docs/RFC/RFC-<HITO>-<NN>-<title>.md` para decisiones de
   HITO scope.
2. `docs/decisions/ADR-<NN>-<title>.md` para Architecture
   Decision Records puntuales.
3. Inline en el `PROJECT.md` cuando es una regla del
   proyecto entero.
4. Inline en el `CHANGELOG.md` cuando es un cambio
   especifico de version.

**No** se aceptan decisiones que viven solo en chats /
commits / commit messages sin un doc estable que las
referencie.

---

## 8. Activos estrategicos + proteccion de propiedad intelectual

> **Estado:** decision tomada **2026-05-25** por Pablo:
> **Opcion A -- Server-side prompt composition.** El
> inventario en 8.2 sigue siendo autoritativo. Las opciones
> B/C/D quedan documentadas como historico. La implementacion
> arranca en `docs/HITO_4_STRATEGIC_ASSETS.md` (HITO 4
> "Strategic asset isolation").

### 8.1 El problema

Forge se distribuye via `npm install -g @yujin/forge-cli`. Al
instalarse, el codigo entero (incluido el `dist/`) queda
legible en disco del adopter. **Cualquier developer con
acceso al binario puede leer el codigo fuente**, incluido:

- Los system prompts a Claude para extract / plan / decorate
  / recap summary.
- Los catalogos de tools + sus shapes + sus rules.
- Los templates de scaffolding por kind/language.
- Los heuristicos del trust model + del intent matcher.
- La metodologia completa del pipeline.

Es decir: **el "secret sauce" del producto esta hoy en
plaintext en la maquina de cada adopter pago.** Un competidor
puede `npm install -g @yujin/forge-cli`, abrir
`dist/chat/spec_extract.js`, copiar el prompt, y construir
un clon sin pagar.

Esto debe arreglarse antes del GA cut (HITO 3 territory),
con la decision tomada antes de la promocion alpha → latest.

### 8.2 Inventario de activos estrategicos

Lista exhaustiva de lo que da valor a Forge.
**Cada item esta clasificado por sensibilidad: CLOSED, MIXED,
OPEN.**

**Tier 1 -- CLOSED (secret sauce; competitividad directa):**

1. **System prompts de los flows Claude** -- la receta de
   como Forge extrae requirements de un spec, arma planes,
   redacta el recap summary. Hoy en plaintext en:
   - `src/chat/spec_extract.ts` (SYSTEM_PROMPT)
   - `src/chat/spec_plan.ts` (SYSTEM_PROMPT)
   - `src/chat/server.ts` (recap summariser system prompt)
   - `src/migrate/ai-decorate-*.ts` (decoration prompts)
   - `src/migrate/figma-*.ts` (Figma scaffolder prompts)

2. **Heuristicas de plan generation** -- las reglas de "que
   archivos crear para que entidad/endpoint/component",
   "orden de creacion", "naming conventions". Hoy en
   `src/chat/spec_plan.ts` + system prompt.

3. **Templates de scaffold por (kind, language)** -- los
   stub bodies de `model.ts`, `api.ts`, `Component.tsx`,
   `README.md`, etc. Hoy en `src/chat/spec_scaffold.ts`
   (`templateFor` function).

4. **Decoration heuristicas NAC-3** -- como elegimos
   `data-nac-role` por elemento, como derivamos
   `data-nac-action`, como agrupamos elementos en plugin
   slugs.

5. **NAC-3 disambiguation prompts** -- cuando esto se
   implemente (memoria `nac3-disambiguation-model-split`),
   el prompt que recibe Gemini Flash Lite para resolver
   ambiguity en runtime de Pilot.

6. **El benchmark interno + sus resultados** -- los runs de
   600 ejecuciones del NAC-3 benchmark (que modelo, que
   protocolo, que accuracy). Hoy en `yujin-nac-spec/benchmark/`,
   no en Forge, pero Forge consume los hallazgos para
   decidir defaults de model_preference.

7. **Modelo Koe (pricing + cost formula)** -- la formula
   provider_cost + 30% markup + 20% reinvestment +
   institutional plan. Documentada en CRM memory
   `yujin-koe-pricing-formula`.

**Tier 2 -- MIXED (parte open, parte closed):**

1. **Tool catalog `forge.*`** -- los NOMBRES + SCHEMAS
   pueden ser publicos (los adopters los invocan). Las
   IMPLEMENTACIONES de cada tool tienen detalles que valen
   ocultar (e.g. como `forge.git_commit` orquesta el splice
   del token de GitHub).

2. **Trust model voiceprint** -- la idea de 5 capas es
   publica. Los thresholds + ponderaciones precisas son
   ajustables y son el resultado de tuning empirico = valor.

3. **Recap summary cost gating** -- el doble lock
   (env var + summariser instalado) es publico. La logica
   exacta de cuando el summary vale los tokens es interna.

4. **Voice intent matcher catalog** -- los 8 intents son
   publicos (estan en el manual del usuario). Los regex
   exactos por idioma son el resultado de empirical tuning
   = valor. Hoy en `src/voice/intents.ts` en plaintext.

**Tier 3 -- OPEN (Apache-2.0; pueden ser publicos sin perdida):**

1. **CLI surface** (`yf` commands + flags) -- documentado en
   USAGE.md, expuesto al mundo.
2. **Reader pipeline + 10 parsers** -- standard tech; los
   parsers en si son ejercicios de ingenieria, no IP unica.
3. **Vault crypto** -- estandar AES-256-GCM + scrypt + machine
   fingerprint; el codigo es directo y publicable.
4. **i18n runtime + 10 catalogos** -- las traducciones son
   accesibles al usuario via el panel; el codigo es trivial.
5. **HTML manuals** -- distribuidos al usuario por diseno;
   publicos por definicion.
6. **Playwright test suite** -- estandar de QA, no IP.
7. **PROJECT.md + SQ.md + LANGUAGE_POLICY.md** -- son
   politicas del equipo, no codigo.
8. **NAC-3 spec adoption** -- la spec es Apache-2.0; nuestro
   uso de ella es subsidiario.

### 8.3 Threat model

**Actores con acceso al binario:**

| Actor | Acceso | Riesgo |
|---|---|---|
| Pablo + Sumi | Full repo + dist + secrets | Trust total |
| Adopter pago ($5/mo) | `npm install -g` -> dist en disco | Lee Tier 1 + Tier 2 |
| ADIP / institucional (gratis) | igual que adopter pago | Misma exposicion |
| Open-source contributor | Repo publico (cuando se abra) | Solo Tier 3 |
| Competidor que paga $5/mo | igual que adopter | **Caso de uso adversario principal** |
| Reverse engineer determinado | dist + debugger + DevTools | Lo logra eventualmente sin importar mitigacion |

**Lo que protege un mecanismo razonable:**
- Casual copy (alguien abre el archivo, copia el prompt, ya
  esta). Mitigacion barata previene el 90% de los casos.

**Lo que NO se puede proteger 100%:**
- Reverse engineering determinado de un binario distribuido.
  Cualquier mecanismo de cifrado + license-gating se crackea
  con tiempo + skill suficiente.

**Conclusion:** la proteccion eleva el costo del ataque
hasta que no vale la pena. No la lleva a infinito.

### 8.4 Opciones de proteccion -- decision tomada (Opcion A)

**Pablo eligio Opcion A el 2026-05-25.** Las otras tres
opciones quedan documentadas como historico para futuro
contexto. El diseno completo de la implementacion vive en
`docs/HITO_4_STRATEGIC_ASSETS.md`.

#### Opcion A -- Server-side prompt composition (ELEGIDA)

- Los Tier-1 prompts viven en un servidor central de Yujin
  (`prompts.yujin.app/api/v1/...`).
- Forge cliente NUNCA tiene los prompts. Cuando necesita
  extract / plan / recap-summary, llama a:
  `POST https://prompts.yujin.app/api/v1/spec-extract`
  con `{ flat_text, title, language, license_key }`.
- El server compone el prompt + llama a Claude + devuelve
  el resultado validado.
- **Pros:** prompt nunca sale del server; rotacion central
  (un cambio en el prompt se propaga sin re-publish a npm);
  rate-limiting + abuse-blocking centralizado; A/B testing
  trivial.
- **Cons:** requiere infra Yujin always-on; latencia extra
  (1 hop ida-vuelta); air-gapped deployments imposibles;
  privacy concern (el spec del cliente pasa por nuestro
  server).

#### Opcion B -- Bundle encryption + license-gated decryption

- Los Tier-1 prompts viven en `dist/` cifrados con AES-256-GCM.
- La key de decryption llega del license server al boot
  (`yf license activate` la cachea localmente).
- Sin licencia valida, prompts inutilizables.
- **Pros:** funciona offline despues del first activation;
  no requiere server runtime para cada extract; respeta
  privacy del spec del adopter.
- **Cons:** cualquier debugger atrapa el plaintext en
  memoria post-decrypt; obfuscacion del decryptor lo demora
  pero no lo previene; complica el build pipeline.

#### Opcion C -- Hybrid (publica surface + private kernel)

- El kernel critico (prompts + heuristicas tier-1) sirve
  via API como en A.
- El resto (CLI, reader, voice subsystem, vault) queda en
  npm publico.
- Marketing: "Forge open framework + Yujin Engine premium".
- **Pros:** combina lo mejor de A + adopcion open-source;
  permite ecosistema sin perder secret sauce.
- **Cons:** misma latency + always-on que A para los flows
  Claude-driven; complica el messaging comercial.

#### Opcion D -- Obfuscacion sola (NO recomendada, NO elegida)

- Code obfuscation del bundle, strings encoded en base64 +
  XOR-mask, runtime decode.
- **Pros:** trivial de implementar; sin infra.
- **Cons:** se crackea en una tarde con DevTools; no es
  proteccion, es teatro de seguridad. Solo aceptable como
  capa adicional encima de A o B.

#### Notas sobre la decision Opcion A

- **Infra requerida:** servidor central `prompts.yujin.app`
  o equivalente. Ya alineada con HITO 3 license server (que
  vive en el CRM Yujin segun decision 2026-05-23).
- **Latency budget:** un extra hop ida-vuelta. Para flows
  Claude (extract / plan / recap summary) que ya tardan
  varios segundos, +200ms es invisible. Para flows no-Claude
  (no aplica) no afecta.
- **Privacy del spec del adopter:** el `flat_text` del spec
  va a nuestro server. Documentar esto en
  `PRIVACY_POLICY.md` antes de GA. Adopters institucionales
  (ADIP) pueden tener clausula de no-retencion en su
  contrato.
- **Air-gapped deployment:** NO soportado en HITO 4 inicial.
  Si una institucion lo pide, evaluar Opcion B selectivamente
  para esos clientes (license-tier especifico).
- **Failover:** si `prompts.yujin.app` esta down, Forge
  cliente reporta error claro -- NO hace fallback a un prompt
  local (eso violaria toda la proteccion).

### 8.5 Reglas hasta que se implemente la opcion elegida

Mientras el mecanismo de 8.4 esta en desarrollo:

1. **No agregar nuevos Tier-1 assets en plaintext al
   `src/`.** Si un slice necesita un prompt nuevo, escribirlo
   en un archivo separado en `src/_secret_pending/` con
   header `*** TIER-1 STRATEGIC ASSET -- DO NOT PUBLISH ***`
   + un TODO de migracion a la opcion elegida.

2. **El npm publish gate (prepublishOnly) corre un linter
   que rechaza `src/_secret_pending/` en el dist.** Eso
   bloquea publish accidental hasta que el asset migre a la
   solucion definitiva.

3. **Documentar en cada commit que toca un Tier-1 asset:**
   "Tier-1 strategic asset modified. Threat exposure
   acknowledged per SQ sec 8.3."

4. **No agregar nuevos system prompts a archivos publicos.**
   Si un nuevo flow Claude-driven aparece, pedir a Pablo la
   decision: server-side ya, plaintext con warning, o
   diferir el slice.

### 8.6 Migracion futura (post-decision)

Cuando Pablo elija opcion A / B / C:

1. Listar todos los Tier-1 assets actualmente en `src/`.
2. Diseñar el mecanismo elegido (server endpoints o
   encryption layout).
3. Implementar el mecanismo en una HITO dedicada (HITO 4
   "Strategic asset isolation" propuesto).
4. Migrar uno a uno los assets, con tests E2E que verifican
   que el flow sigue funcionando.
5. Republicar a npm como version major (`v0.3.0-alpha.0`)
   con changelog explicito: "Forge ahora requiere licencia
   valida para los flows Claude-driven."
6. Adopters existentes mantienen acceso porque su license
   sigue valida; nuevos adopters obtienen el binario sin
   los assets sensitive incluidos.

---

## 9. Convivencia con el `PROJECT.md`

El `PROJECT.md` del proyecto es **topologico + procesal** (que
hay, donde, como se mueve). Este `SQ.md` es **normativo** (que
calidad debe tener todo lo que se hace).

Cuando hay conflicto:

- Si es sobre **topologia o proceso** → `PROJECT.md` gana.
- Si es sobre **calidad o normas de conducta** → `SQ.md`
  gana.
- Si es sobre **una preferencia personal** que un colaborador
  intenta imponer → ambos docs ganan, el colaborador se ajusta.

---

## 14. Producer/Consumer Symmetry (mandatory, auto-enforced)

Cualquier cambio que toque una **estructura compartida** EXIGE
que el commit asegure simetria producer/consumer. Estructuras
compartidas incluyen (no es lista cerrada):

- Vault slots (`google_voice`, `github_token`, etc)
- JSON keys en archivos de config persistidos
  (`provider_keys.json`, `yujin.forge.json`, `license.json`)
- Env vars (`ANTHROPIC_API_KEY`, `YF_MODE`, etc)
- Tool names del catalogo de chat (`forge_X`)
- Type identifiers exportados desde `src/types/`
- Endpoint contracts (`/api/voice/stt`, `/api/forge/tool`, etc)
- Manifest fields (`data-nac-id`, `data-nac-role`, etc)

### 14.1 Auto-enforcement (cero pregunta al usuario)

Forge es responsable de la simetria, NO el usuario. Pasos
obligatorios antes de cualquier commit que toque write paths
de estos conceptos:

1. **Audit:** Forge corre `forge_audit_consumers(<concepto>)`.
2. **Sync:** Si hay readers desincronizados, Forge los actualiza
   en el MISMO commit. No espera siguiente sesion.
3. **Test:** Forge garantiza la existencia de un test en
   `tests/fresh-user/<concepto>.test.ts` que (a) limpia el
   estado, (b) escribe el lado productor, (c) instancia el
   consumer, (d) afirma que funciona.
4. **Commit:** El mensaje del commit lista los consumers
   sincronizados.

El usuario nunca es consultado en este flujo. Si el audit
revela algo legitimamente ambiguo (ej. una migracion de
contrato con back-compat), Forge SI pregunta -- pero la
pregunta es FUNCIONAL ("mantenemos compatibilidad con
usuarios viejos?"), no tecnica ("cual reader actualizo?").

### 14.2 GOTCHAS log obligatorio

Cada regresion de tipo AP-1 que llega a una version publicada
se anota en `docs/GOTCHAS.md` con:

- Sintoma user-visible (texto literal del error / screenshot)
- Causa raiz estructural
- Patch (commit hash)
- Como Forge previene la recurrencia

Forge lee `GOTCHAS.md` al boot. Cuando un cambio diff matchea
un patron registrado, refuse el commit y enlaza a la entrada.

### 14.3 Que pasa si Forge ignora esta regla

- Bug AP-1 en alpha: commit que lo detecta tiene que rollback.
- Bug AP-1 en stable: ademas, anotacion en GOTCHAS con
  `published: true` flag, alarma en el panel para el proximo
  uso del producer.
- Tres bugs AP-1 en una semana: pause del autopilot, hand-off
  manual hasta que se audite la causa de no-deteccion.

### 14.4 Por que esta seccion (origen historico)

2026-05-29: el BYOK refactor (`yf keys setup` -> 
`provider_keys.json`) shippeo en alpha.4 con tres consumers
sin actualizar. Sumi parche alpha.5, alpha.7, alpha.8 cada
una al consumer siguiente que el usuario tropezo. Pablo
flageo el patron y pidio que Forge no lo cometa.

Esta seccion + el tool `forge_audit_consumers` + los tests
`tests/fresh-user/byok-*.test.ts` son la respuesta. Ver
`docs/GOTCHAS.md` entries G-2026-05-29 a/b/c.

---

## 15. Autonomia: Forge testea por si mismo

**Principio central (2026-05-31, Pablo lockeo):**

> "Menor friccion y ruido posible. El tiempo del user es para
> juicio y decisiones, no para reproducir bugs o ejecutar
> comandos."

Forge -- y el agente Sumi que opera Forge en sesion -- deben
testear autonomamente todo lo que puedan, antes de pedirle al
user que corra algo. Cada vez que el agente esta por preguntar
"podes correr X y pegarme el output?", parar y reescribir como
"voy a correr X yo, capturar output, diagnosticar".

### 15.1 Que puede testear Forge solo

**CLI smoke tests:** correr `yf <cualquier comando>` directamente
via shell. Capturar exit code + stdout + stderr.

**Browser-based UI (chat panel, voice loop, DevTools console):**
levantar el servidor con `yf chat --no-open` y testear:
- WebSocket: simular cliente con `ws` lib, mandar mensajes,
  inspeccionar respuestas.
- Voice loop: capturar logs del proceso, no del DevTools (la
  consola del browser duplica lo que ya escribimos a stdout).
- Playwright headless para clicks de UI cuando aplica.

**API endpoints:** curl / fetch directos contra:
- Worker `yujin-hito4` deployado.
- Chat server local.
- Polar webhook (con stub firmado).

**End-to-end commerciales:** stub fixtures + correr el flow
con HTTP fake. Sin esperar a que el user compre / pague /
reciba email.

**Builds:** disparar el comando (`npm publish --dry-run`,
`eas build`, `wrangler deploy`) y esperar el resultado.

**Logs runtime:** parsear `logs/forge.log` y `~/.yujin-forge/usage.jsonl`
directamente.

### 15.2 Cuando SI involucrar al user

Acciones que el agente fisicamente no puede hacer:

- **Touch hardware:** microfono real, camara real (la grabacion
  WebM sintetica se procesa distinto que un audio real con
  ruido ambiente, eco, codec).
- **Juicio subjetivo:** "este copy suena natural?", "este
  layout queda bien?", "este precio te parece razonable?".
- **Decisiones comerciales:** $$$, scope, lock-in con un
  proveedor, comprar credito de EAS / Anthropic / Polar.
- **Acceso a infra externa con creds que solo el user tiene:**
  Polar dashboard manual, panel admin de GoDaddy, AWS root.

### 15.3 Cuando NO involucrar al user

Anti-pattern: pedir al user que reproduzca un bug paso a paso.

- "Podes abrir el chat, hablar, y pegarme el log?" -> NO.
  Forge levanta el chat headless, simula audio, captura log.
- "Podes correr `yf license sync --verbose`?" -> NO. Forge
  corre el comando, lee stdout, diagnostica.
- "Podes verificar que aparecio `paid`?" -> NO. Forge lee
  `~/.yujin-forge/license.json` directo y verifica.

### 15.4 Cuando el test autonomo NO es suficiente

Si despues del test autonomo el bug sigue apareciendo solo en
la maquina del user (no en la del agente), entonces:

1. Capturar **diff de ambiente** primero: node version, OS,
   shell, vars de env relevantes, contenido de
   `~/.yujin-forge/*`. El agente puede pedir esto via un
   comando `yf doctor --detailed` que vuelque todo.
2. Solo entonces pedir al user un paso especifico, con un
   comando exacto que produce un artifact concreto que el
   agente despues lee + diagnostica.

### 15.5 Como Forge mismo aplica esta regla con sus users

Cuando un user instala Forge y le pide que diagnostique algo,
Forge corre los tests + reporta el diagnostico. No le pide al
user "podes correr X y pegarme el output".

Esto se manifiesta en:
- El system prompt del chat shell (`buildSystemPrompt`)
  incluye la regla "test things yourself" como principio
  numero 1.
- Los tools `forge_*` capturan logs autonomamente sin pedir
  al user.
- Los flows del worker `yujin-hito4` corren los tests +
  devuelven el reporte; el user solo ve la conclusion.

### 15.6 Origen historico

2026-05-31: Pablo flageo que Sumi le pedia tests reproducibles
(DevTools console, comandos CLI) que Sumi podia correr solo.
Pablo nota: "no estare todo el dia. Aprovecha esa facilidad
para optimizar mis tiempos."

Pablo despues extendio: "trasladalo a Forge, dado que es lo
que pretendemos, menor friccion y ruido posible." Esta seccion
+ la actualizacion del system prompt son la respuesta.

---

*Ultima revision: 2026-05-31 (adicion sec 15 -- autonomia).*

*Actualizar este archivo en el mismo commit que cualquier
cambio de norma de calidad o entregable. Cambios sustanciales
requieren acuerdo explicito de Pablo (mantenedor).*
