# before_0_1 > Lo que hay que **cerrar, incluir o verificar** antes de etiquetar > `0.1.0`. Construido sobre las evidencias del repo a fecha de hoy y los > hallazgos del audit. Un par de bloqueantes son políticas / hygiene que > pesan más que cualquier hallazgo técnico individual. --- ## 1. Qué significa `0.1` aquí (definición operativa) `0.1` no es _production-ready_. Es la versión que **un equipo externo puede probar sin sorpresas grandes**, sabiendo que la API pública no romperá silenciosamente durante la línea `0.1.x`. Esto fija el listón: - API pública de los 9 roots always-present **congelada** durante `0.1.x`. - Las 5 factorías scoped (`Sium`, `Session`, `Connections`, `Auth`, `Permissions`) pueden iterar pero deben respetar deprecation policy. - Sin bugs de seguridad conocidos en flujos hot. - Repo aceptable para un PR externo: licencia, README, contributing, CI. - Docs suficientes para enviar una feature sin leer el código fuente. - Build estático funciona end-to-end (no solo el typecheck). Lo que **no** entra en `0.1`: MFA en producción, OAuth con todos los proveedores, todos los módulos con docs profundas, métricas / telemetría, ejemplos reales más allá de las páginas `/test`. --- ## 2. Estado real verificado hoy Antes de listar gaps, lo que ya está cerrado (corroborado leyendo el repo, los tests y los gates locales): - **Tests reales**: 108 archivos / 1208 tests verdes. - **Typecheck**: `npm run check` 0/0/0. - **Build estático**: `npm run build` verde. - **Gate completo**: `npm run test:all` verde (`check` + `test` + `build` + `test:static` + `test:bundle`). - **Bundle smoke**: `createActiveApp({})` está medido con Vite/OXC en `scripts/bundle-smoke.mjs`; baseline actual ~65 KB gzip, presupuesto `0.1` en 70 KB gzip configurable con `ACTIVE_BUNDLE_GZIP_LIMIT_KB`. - **Refactor wave** documentada en `NEXT_STEPS.md` ha resuelto parcialmente varios de mis hallazgos del audit: - **C2/C3** (Auth → Permissions/Cache invalidation) — cableado a través de `arts/aapp/integrations/auth-cache.ts`. _A verificar_ con tests de race cross-actor que el flujo real cierra el gap. - **C1** (perm race cross-actor) — el cliente perm se ha partido en `client-cache.ts` / `client-keys.ts` / `client-snapshot.ts`. _A verificar_ que `pending` se invalida en `hydrate` / cambio de scope. - Cobertura: `auth + sess + perm + cach` ya tienen test de integración cruzada. - **Brand brief** (`BRAND.md`) escrito y assets estáticos añadidos. - **Documentación interna** (`/active`): shell + landing + Get Started, páginas para todos los módulos bajo `docs/`, sección de capa servidor (`$svrs`), seguridad, versionado y guía para AI agents. La profundidad por módulo sigue siendo desigual y es trabajo pendiente. Lo que **sigue abierto** sale en §3. --- ## 3. Bloqueantes duros para `0.1` Cada bloqueante lleva una _Acceptance criteria_ verificable. ### 3.1 Repo hygiene (sin esto el repo no está listo para PR externos) | Falta | Acceptance | | ------------------ | ----------------------------------------------------------------------------------------- | | `LICENSE` | Archivo en raíz; campo `license` en `package.json` coincide. | | `README.md` (raíz) | Tagline, install, quick start, link a `/active`, link a `BRAND.md`, badges típicos. | | `SECURITY.md` | Política de reporte (correo / GitHub Security Advisories), modelo de amenazas resumido. | | `CONTRIBUTING.md` | Cómo correr tests, layout `libs/svrs/arts`, regla "docs y comentarios en inglés". | | `CHANGELOG.md` | Iniciado con `0.1.0` siguiendo Keep a Changelog + SemVer. | | `.github/` | Issue templates (bug, feature), PR template, workflow CI mínimo (lint+check+test+build). | | `.gitignore` | Añadir `tmp-active-docs-*.log`, `AUDIT_*.md` no, `BRAND.md` no — solo logs/temporales. | | `package.json` | Campos `license`, `engines.node` (`>=22`), `repository`, `bugs`, `homepage`. | > **Nota**: hay 4 ficheros `tmp-active-docs-*.log` en la raíz hoy. O se > commitean (no recomendado) o se ignoran. Decidir antes del tag. ### 3.2 Seguridad | ID | Bloqueante | Acceptance | | --- | --------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | | S1 | `AuthRateLimitPort` definido pero no cableado en flows críticos (audit C7). | `signInPassword`, `signUpPassword`, `requestPasswordReset`, `requestEmailVerification`, `startOAuth` consultan el puerto antes de procesar. Test que verifica que un puerto que devuelve `denied` corta el flujo. | | S2 | PKCE no validado server-side en `completeOAuth` (audit C6). | `provider.mapProfile` recibe `verifier` y un test cubre intento de callback con `code_verifier` distinto al `code_challenge` original; debe fallar. | | S3 | `verifyMfaChallenge` lanza `AuthConfigError` (audit C5, sigue stub). | O bien implementación funcional, o bien **excluido del barrel y de `handlers`** + nota en `SECURITY.md`. Coherente con la promesa: lo que se exporta funciona. | | S4 | Memory adapters (`svrs/auth`, `svrs/perm`, `svrs/cach`) no marcados como dev-only. | Bandera `process.env.NODE_ENV === 'production'` que loguea warning explícito al instanciar; nota en README de cada adapter; test que verifica el warning. | | S5 | CSRF cookie default `SameSite=Lax` (audit M2). | Default `Strict` en `AUTH_COOKIE_POLICY.SAME_SITE`. Tests de regresión. | | S6 | _Verificar_ que C1/C2/C3 están realmente cerrados tras el refactor (NEXT_STEPS). | Test de integración: actor A en vuelo → `hydrate(B)` antes de la respuesta → la decisión cacheada NO queda bajo scope B. Hoy el test no existe. | | S7 | `SECURITY.md` con threat model. | Documenta: cookie scopes, CSRF flow, refresh rotation, OAuth state binding, MFA estado actual, modelos de actor en perm. | ### 3.3 Correctitud / API | ID | Bloqueante | Acceptance | | --- | ----------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | | A1 | `ensureLive` con nombre de método incorrecto (audit C4). | Constantes `AUTH_METHOD_ON_CHANGE`, `PERMISSION_METHOD_CLEAR_ERROR`, etc.; test que valida el message del error contiene el método real. | | A2 | API pública de los 9 roots **comprometida** durante `0.1.x`. | Snapshot tests del shape de cada `Engine*`/`Active*` always-present; cualquier cambio en `0.1.x` debe ser aditivo o pasar por `__EXPERIMENTAL_*`. | | A3 | Política de deprecación documentada. | `CONTRIBUTING.md` describe: `@deprecated` JSDoc + warning runtime + `__EXPERIMENTAL_*` namespace + minimum una minor antes de remove. | | A4 | `AuthRateLimitPort` exportado **solo si** se cablea (S1). Si no, sacar del barrel. | Si no se implementa para `0.1`, no aparece en `index.ts` y no aparece en docs; añadir TODO de `0.2`. | | A5 | `mono-lang` cast `as unknown as ActiveLang` (audit M8). | Decidir: o se restringe el tipo de `App.Lang` cuando no hay schema, o se documenta explícitamente la ruptura de tipos. README de `lang` lo refleja. | ### 3.4 Documentación mínima `/active` ya tiene rutas para todos los módulos, pero la profundidad sigue siendo desigual. Para `0.1`: | Bloqueante | Acceptance | | ----------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | | Los **9 roots always-present** con docs reales (no stub). | `App, Lang, Logger, Formats, Frontend, Dom, Storage, Http, Timers, Cache` tienen sección Overview / Quick start / API / Limits / Testing. | | Las 5 factorías scoped pueden ser stub si llevan una nota "shape final en `0.2`". | El stub indica explícitamente qué partes de su API no están comprometidas. | | `SECURITY.md` (cubre S7) **enlazado** desde sidebar de `/active`. | Item en la sección `Get Started` con ruta `/active/security`. | | Migration / versioning policy publicada. | Página `/active/get-started/versioning` o sección dentro de Composition. | ### 3.5 Build y tooling | Bloqueante | Acceptance | | ----------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | | Build estático real verificado. | `npm run build` produce `build/` sin errores; `npm run preview` sirve `/active` y al menos `/test/ecosystem`.| | CI en GitHub Actions. | Workflow corre `test:typecheck`, `test`, `build`, `test:static` y `test:bundle` en push y PR. Branch protection en `master`/`main`. | | Scripts npm completos. | `test:typecheck`, `test:static`, `test:bundle` y `test:all` existen. `test:all` ejecuta `check` + `test` + `build` + `test:static` + `test:bundle`. | | Reproducibilidad. | `package-lock.json` commiteado (ya está). Node version pinneada en `engines` y `.nvmrc`. | | Bundle size sanity. | Smoke test que importa `createActiveApp({})` y verifica gzip bajo `ACTIVE_BUNDLE_GZIP_LIMIT_KB` (default 70 KB). | > `npm run lint` existe, pero sigue siendo deuda global pre-`0.1`; CI no > lo ejecuta hasta que el árbol completo quede limpio. La regla mientras > tanto es no añadir deuda nueva en archivos tocados. ### 3.6 Marca y assets `BRAND.md` describe lo que debe hacerse; `static/` solo tiene `robots.txt`. | Bloqueante | Acceptance | | -------------------------------- | ------------------------------------------------------------------------------------------------ | | `static/favicon.svg` | Concept A o B del brief, monocromo, vector limpio. | | `static/favicon-16/32/48.png` | Pixel-snapped (no scaling automático), sRGB. | | `static/apple-touch-icon.png` | 180×180 con padding 10%. | | `static/icon-192/512.png` + `icon-maskable-512.png` | PWA-ready aunque la PWA no esté declarada todavía. | | `static/og-image.png` | 1200×630 según prompt §10 de `BRAND.md`. | | `app.html` | ``, ``, ``, OG tags por defecto. | | `manifest.webmanifest` | Opcional para `0.1` pero recomendado, listado de iconos PWA. | --- ## 4. Bloqueantes blandos (pueden caer en `0.1.1`–`0.1.x`) Son hallazgos del audit con impacto real pero acotables a un parche: - M4 (refactor `validateOptionalField` en sess) — limpieza; no rompe nada. - M5 (acoplamiento `aapp` ↔ `stor` en mensajes de log) — se puede pulir más tarde sin tocar la superficie pública. - M9 (body-scroll-lock con scheduling propio en vez de delegar a `timr`) — optimización; no afecta la API. - M10 (HTTP recompone headers en cada retry) — perf, no semántica. - M14 (sess `BroadcastChannel` ignora el `event` recibido y vuelve a leer storage) — documentar como diseño y seguir. - m1–m15 (menores: docs faltantes, magic strings residuales, refactors cosméticos). Estos pueden entrar como issues etiquetados `0.1.x` y resolverse de manera incremental. --- ## 5. Fuera de alcance para `0.1` (explícito) Para evitar que el sprint se infle, dejar fuera y comunicarlo: - MFA real (TOTP, WebAuthn, recovery codes). - OAuth provider catalog (GitHub, Google, etc.) — solo el motor + un proveedor de ejemplo. - Métricas / telemetría / OpenTelemetry export. - Server-side rendering completo del docs site (es estático). - Componentes UI prefabricados (eso vive _encima_ de los artefactos). - Internacionalización del propio docs site (English-only en `0.1`). - Distribución por `npm publish` — `0.1` puede vivir solo como repo template / submódulo / vendoring. Decidir si publicar es objetivo. --- ## 6. Verificación pre-tag (un solo comando) Antes de etiquetar `0.1.0`, todo esto debe pasar en CI y local: ```sh # 1. Gate completo automatizado npm run test:all # → check + tests + build + static smoke + bundle smoke # 2. Tipos, si se quiere aislar el paso npm run check # → 0 errors / 0 warnings # 3. Suite, si se quiere aislar el paso npm test # → 0 failed; assert >= 1208 tests # 4. Build estático, si se quiere aislar el paso npm run build # → produce build/ sin errores # 5. Bundle smoke, si se quiere aislar el paso npm run test:bundle # → createActiveApp({}) <= 70 KB gzip por defecto # 6. Static smoke, si se quiere aislar el paso tras build npm run test:static # → rutas/docs/assets críticos existen en build/ ``` Y, cuando se quiera verificar el sitio servido: ```sh npm run preview curl -fsS http://localhost:4173/active | grep -q "active" curl -fsS http://localhost:4173/test/ecosystem | grep -q "ecosystem" ``` `npm run lint` debe ejecutarse antes del tag, pero hoy todavía representa una limpieza global separada. No debe bloquear el gate automático hasta que esa deuda esté cerrada. Y manual: - [ ] Abrir `/active` y `/test/ecosystem` en Chromium, Firefox, Safari desktop. **No console errors. No layout shifts grandes.** - [ ] `App.dispose()` se llama dos veces seguidas → no throw, no warn. - [ ] Cambio de locale a `ar` aplica `dir="rtl"` y propaga a Formats. - [ ] Sign-in → sign-out limpia perm cache y session bridge. - [ ] Refresh durante revoke → no resucita la sesión. - [ ] 404 en una ruta `/active/docs/` → muestra fallback. - [ ] Tema oscuro: contraste suficiente en sidebar activo, code blocks, callouts. --- ## 7. Orden sugerido Dos sprints serios bastan si nadie se desvía. **Sprint A — Seguridad y correctitud (1 semana)** 1. S1 — cablear rate-limit (engine + handlers + tests). 2. S2 — pasar verifier a OAuth provider y validar. 3. S3 — decisión MFA: implementar mínimo o sacar de barrel. 4. S5 — flip default CSRF a Strict. 5. S6 — test de integración perm race cross-actor. 6. A1 — corregir constants en `ensureLive`. 7. S4 — warning runtime en memory adapters. **Sprint B — Hygiene, docs y release (1 semana)** 1. Repo hygiene: LICENSE, README, CONTRIBUTING, SECURITY, CHANGELOG, `.github/` con CI básica. 2. A2/A3 — snapshot tests de superficie + política de deprecación escrita. **Cerrado para la superficie actual**; mantenerlo actualizado con cada miembro público nuevo. 3. Completar los 9 roots always-present en `/active/docs`. 4. Marca: ejecutar al menos `favicon.svg` + `favicon-32/16` + `og-image.png` + meta tags en `app.html`. 5. Build estático, static smoke y bundle smoke verificados en CI. 6. Tag `0.1.0` con changelog real. --- ## 8. Decisiones abiertas (necesitan criterio humano antes de avanzar) 1. **¿Se publica en npm o se distribuye como repo / template?** Cambia la forma de empaquetar (`exports`, `files`, `sideEffects` granular). 2. **¿`AuthRateLimitPort` se cablea ahora o se posterga?** Si se posterga, sacarlo del barrel hasta `0.2`. 3. **¿MFA en `0.1` o explicitamente en `0.2`?** Hoy está stubbed; un stub que lanza no debe estar en la superficie pública. 4. **¿`mono-lang` es público o interno?** Si público, se documenta y se asume el cast laxo; si interno, se quita del barrel. 5. **¿La doc de los 5 factorías scoped (`Sess`, `Auth`, `Perm`, `Conn`, `Sium`) llega a `0.1` profunda o stub?** Mi recomendación: `Auth`, `Sess` y `Perm` profundas (son las que un consumidor pisa en onboarding); `Conn` y `Sium` pueden quedar como stubs marcados. 6. **¿Adapter Static es el target final?** Si hay plan de SSR (auth server-side real), conviene cambiar a `adapter-node` antes de `0.1` para no romper consumidores en `0.1.x`. 7. **¿La API de `App.Cache.invalidate({tags})` queda como contrato estable?** Se merece ser parte del primer snapshot test de superficie porque cae en el camino crítico de `Auth`. --- ## 9. Métricas de "listo" Cuando todo lo anterior pase, el repo debería poder responder _sí_ a: - "¿Un dev externo clona, sigue el README y arranca `/active` en < 5 min?" - "¿Existe un punto de contacto claro para reportar un fallo de seguridad?" - "¿Hay manera de saber qué cambia entre `0.1.0` y `0.1.1` sin leer commits?" - "¿La superficie de los 9 roots always-present está documentada con una garantía explícita de no-break en la línea `0.1.x`?" - "¿Si elimino los assets de marca, queda algo identificable en el navegador?" (Hoy: no, `static/` solo tiene `robots.txt`). Si las cinco respuestas son sí, etiqueta `0.1.0`.