20 KiB
Auditoria Codex - ecosistema Active + Orca
Fecha: 2026-05-04
Workspace: G:\dev\svelte\active
Alcance
Se audito el estado actual del ecosistema con foco en el nuevo modulo
src/arts/orca y sus puntos de acoplamiento con:
src/arts/active-appsrc/arts/bussrc/arts/sessionsrc/arts/cachesrc/arts/permsrc/arts/connection- documentacion publica en
src/arts/*/README.mdy pagina activa generada.
No se modifico codigo existente. El arbol ya tenia cambios previos en:
src/arts/orca/consts.tssrc/arts/orca/result.tssrc/arts/orca/types.ts
Esos cambios parecen corregir parte de la deriva de comentarios v0.1+ respecto a
timeout/fatal/gates/compensation, pero no cierran todos los problemas.
Veredicto
orca esta bien orientado arquitectonicamente. La decision fuerte, y la que
realmente eleva el ecosistema, es mover las reacciones inter-modulo a una capa de
orquestacion declarativa situada en active-app, no dentro de cache, perm,
session o connection. Eso reduce acoplamiento y permite testear flujos
compuestos como objetos de ejecucion (OrcaRunResult).
El modulo, sin embargo, ya ha crecido mas rapido que su contrato. El motor actual
implementa gates, timeouts de accion, compensacion, transacciones, payloads en
tokens, fan-in y politicas de cola. La documentacion mezcla tres versiones a la
vez: boceto conceptual, v0 inicial y estado real. Antes de seguir expandiendo
orca, conviene congelar el contrato real y eliminar ambiguedades.
Estado de pruebas focalizadas:
npx vitest run src/arts/orca/test src/arts/active-app/test/presets.test.ts
Test Files 4 passed
Tests 169 passed
Hallazgos P1
1. Liberacion de trace no es segura con runs paralelos
Referencia:
src/arts/orca/engine-orca.ts:928src/arts/orca/engine-orca.ts:931src/arts/orca/engine-orca.ts:935
maybeReleaseTrace() borra traceStates si no quedan eventos en cola. El propio
comentario reconoce que no sabe si hay runs en vuelo del mismo trace. Eso era
defendible con ejecucion estrictamente secuencial, pero ya existe
ORCA_QUEUE_PARALLEL. Si dos eventos derivados del mismo trace corren en
paralelo, el primero que termine puede borrar el estado de trace mientras el otro
sigue vivo.
Impacto:
- Los contadores
maxDepth,maxEventsPerTrace,repeatedEventLimitydedupeKeypueden resetearse antes de tiempo. - Un loop por eventos derivados puede saltarse la proteccion si el trace se borra mientras quedan runs paralelos activos.
- La trazabilidad de un flujo enterprise deja de ser confiable justo en el modo mas peligroso: paralelo.
Recomendacion:
- Mantener
traceInFlightCountportraceId. - Incrementarlo en
spawnRun(). - Decrementarlo en el
finallydeexecuteRun(). - Liberar el trace solo cuando
queuedCount(traceId) === 0einFlightCount(traceId) === 0. - Anadir test: dos eventos derivados con
ORCA_QUEUE_PARALLELen el mismo trace; el primero termina, el segundo emite otro evento repetido y el guard sigue aplicando.
2. provides no limita emits, asi que la validacion puede mentir
Referencia:
src/arts/orca/types.ts:421src/arts/orca/types.ts:424src/arts/orca/types.ts:425src/arts/orca/engine-orca.ts:1117src/arts/orca/engine-orca.ts:1124
El contrato dice que provides es lo que una accion puede producir, y
validate() usa provides para detectar tokens imposibles. Pero el runtime
acepta cualquier token que venga en result.emits, aunque no este declarado en
provides.
Impacto:
validate()no es una garantia fuerte; es una estimacion basada en intencion.- Una accion puede desbloquear otra con un token que el grafo no declaraba.
- Un typo en
emitspuede cambiar el pipeline sin quevalidate()lo vea. - El futuro
setupOrca()tipado pierde parte de su sentido si el runtime permite emisiones fuera de esquema.
Recomendacion:
- En modo dev, lanzar o registrar
CONFIGURATION_INVALIDcuando una accion emite un token no declarado enprovides. - En modo prod, al menos registrar diagnostic
orca.configuration.invalido descartar el token no declarado segun opcion. - Documentar excepcion solo si se decide permitir tokens dinamicos, pero entonces
validate()debe llamarse "best effort", no "static graph validation".
3. ORCA_QUEUE_REPLACE no es replace-current, solo reemplaza queued
Referencia:
src/arts/orca/consts.ts:73src/arts/orca/engine-orca.ts:420src/arts/orca/engine-orca.ts:421src/arts/orca/engine-orca.ts:422src/arts/orca/README.md:439src/arts/orca/README.md:1444
Hay dos semanticas distintas usando el mismo nombre mental:
- Una seccion del README describe
replacecomo "aborta el run activo y empieza uno nuevo", estilotakeLatest. - El motor implementa "reemplaza solo entradas queued; no aborta in-flight".
- Otra seccion posterior del README ya reconoce esta realidad.
Impacto:
- Para formularios, busquedas, navegacion o cambio de identidad, un usuario puede esperar "ultima intencion gana", pero el run anterior seguira ejecutandose.
- Si la accion vieja muta cache/conexiones despues de la nueva, puede pisar estado.
- El nombre
replacees ambiguo para usuarios que vienen de saga/Rx/RTK.
Recomendacion:
- Renombrar la politica actual a algo explicito:
ORCA_QUEUE_REPLACE_QUEUEDoORCA_QUEUE_LATEST_QUEUED. - Reservar
ORCA_QUEUE_REPLACE_CURRENT/ORCA_QUEUE_TAKE_LATESTpara la variante fuerte que aborta in-flight. - Si se mantiene el nombre actual, borrar del README cualquier promesa de abortar el run activo.
4. IDs de run/event/trace usan Date.now() y Math.random() fuera de timr
Referencia:
src/arts/orca/engine-orca.ts:1513src/arts/orca/engine-orca.ts:1514src/arts/orca/engine-orca.ts:1517src/arts/orca/engine-orca.ts:1518src/arts/orca/engine-orca.ts:1521src/arts/orca/engine-orca.ts:1522src/arts/orca/README.md:841
El README establece que orca no debe usar Date.now() ni setTimeout()
directamente. Los timestamps del envelope ya pasan por timers.clock.now(), pero
los IDs de run/event/trace no.
Impacto:
- Tests y replay no son plenamente deterministas.
- En SSR/hydration o tests con clocks controlados, los IDs no siguen el tiempo simulado.
- La disciplina "todo tiempo via timr" queda rota justo en el modulo que quiere ser trazable.
Recomendacion:
- Anadir
idFactoryaEngineOrcaOptionso tres factories separadas:runIdFactory,eventIdFactory,traceIdFactory. - Default: contador monotono con prefijo, alimentado por
timers.clock.now()si se quiere incluir tiempo. - Tests: factory determinista para snapshots.
5. setupOrca() esta documentado como API recomendada pero no existe
Referencia:
src/arts/orca/README.md:235src/arts/orca/README.md:241src/arts/orca/README.md:271src/arts/orca/README.md:284src/arts/orca/README.md:1271src/arts/orca/index.ts
El README recomienda setupOrca() para apps grandes y muestra ejemplos, pero no
hay export ni implementacion en src/arts/orca.
Impacto:
- La documentacion invita a usar una API inexistente.
- El usuario no sabe si debe usar
App.Orca.onEvent()directo, presets o un setup tipado futuro. - La promesa de validacion fuerte de tokens/eventos queda sin soporte.
Recomendacion:
- O implementar un
setupOrca()minimo, aunque solo envuelvaonEventcon declaracion de eventos/tokens/actions. - O mover esa seccion a "Futuro / v0.1" y dejar claro que v0 real es
createEngineOrca()+App.Orca.onEvent().
6. La integracion con connection no esta cerrada y la documentacion promete mas de lo que existe
Referencia:
src/arts/active-app/presets/standard.ts:28src/arts/active-app/presets/index.ts:5src/arts/active-app/service-factories/connections.ts:9src/arts/connection/README.md:83src/arts/connection/README.md:93src/arts/connection/README.md:100src/arts/connection/session-wiring.ts:27
applyStandardOrca() solo registra presets de cache y perm. No hay preset para
connections.reauthenticateAll() ni para connections.closeAll() en cambios de
identidad/revoke/expire. A la vez, la documentacion de connection habla de
autoReauthOn: 'standard' y de escuchar SESSION_EVENT_IDENTITY_CHANGED.
Ademas, defineActiveConnections() ya no inyecta bus ni session; el comentario
dice que identidad debe venir por orca preset o por una session manual, pero ese
preset no existe.
Impacto:
- Una app que siga la documentacion puede creer que las conexiones se reautentican
al cambiar de usuario, pero con
applyStandardOrca(App)no ocurre. - El caso critico que motivo
orca("chat conectado con credenciales del usuario anterior") sigue sin preset estandar. connectionconserva un mecanismo interno desession-wiringque compite conceptualmente con la nueva regla: los artefactos publican/reciben eventos; la app orquesta reacciones.
Recomendacion:
- Crear preset en
active-app/presets:applyConnectionsReauthOnIdentityChange(App). - Definir si el estandar hace
reauthenticateAll()ocloseAll()cuando no hay credencial nueva. - Actualizar
applyStandardOrca()para incluir conexiones cuandoApp.connectionsexista. - Decidir si
connection.session-wiringqueda como modo local/manual o se depreca a favor del preset deorca.
Hallazgos P2
7. runActionWithTimeout() aborta de forma cooperativa, pero la accion puede seguir mutando estado
Referencia:
src/arts/orca/engine-orca.ts:1042src/arts/orca/engine-orca.ts:1052src/arts/orca/engine-orca.ts:1056src/arts/orca/engine-orca.ts:1058src/arts/orca/engine-orca.ts:1070
El timeout hace actionController.abort() y resuelve orcaTimeout(timeoutMs), pero
la promesa original de la accion sigue viva si la accion no respeta ctx.signal.
Esto es normal en JS, pero debe tratarse como contrato de seguridad.
Impacto:
- Una accion timeout puede mutar cache, conexiones o permisos despues de que el run ya haya tomado otra decision.
- Los tests pueden pasar porque el resultado es
timeout, pero el side-effect tardio queda fuera del trace.
Recomendacion:
- Documentar que toda accion async debe comprobar
ctx.signal.abortedantes y despues de awaits relevantes. - Anadir helper
ctx.throwIfAborted()oorcaAbortIfSignaled(ctx). - Anadir test: accion con timeout que intenta mutar despues; demostrar que el patron recomendado lo evita.
8. La cola es global para eventos no-parallel, aunque el contrato se lee como per-event
Referencia:
src/arts/orca/engine-orca.ts:526src/arts/orca/engine-orca.ts:527src/arts/orca/engine-orca.ts:529src/arts/orca/engine-orca.ts:531
canStartRun() serializa globalmente todos los eventos no-parallel:
nonParallelInFlight === 0. Eso significa que un evento lento de cache puede
bloquear un evento no relacionado de perm, connection o cualquier feature.
Impacto:
- Semantica mas conservadora y lenta de lo que sugiere "queue policy per event".
- Posible cuello de botella en apps grandes con flujos independientes.
- Si esta decision es intencional, falta nombrarla como "single lane".
Recomendacion:
- Decidir explicitamente:
- Modelo A: serializacion global por defecto, documentada como garantia simple.
- Modelo B: serializacion por evento, con concurrencia entre eventos distintos.
- Si se mantiene A, renombrar/comentar como
globalSerialLane. - Si se pasa a B, usar
inFlightByEventpara bloquear solo el mismo evento.
9. commit() congela el grafo; eso choca con features lazy si no se documenta como modo prod
Referencia:
src/arts/orca/types.ts:711src/arts/orca/types.ts:723src/arts/orca/engine-orca.ts:1275src/arts/orca/test/engine-orca.test.ts:4013
El comportamiento actual esta claro en codigo y tests: despues de commit(),
onEvent() y configureEvent() lanzan OrcaFrozenError. Esto no es un bug por
si mismo, pero tensiona el objetivo de registrar acciones desde features
lazy-loaded.
Impacto:
- Si una app llama
App.Orca.commit()durante bootstrap, una ruta lazy ya no puede registrar sus acciones al cargar. - HMR/devtools pueden quedar bloqueados si no se separa "validar" de "sellar".
Recomendacion:
- Documentar
commit()como opcion production/seal, no como paso obligatorio. - Considerar
validate()para dev ycommit()solo para builds donde el grafo es completo al arrancar. - Si se quiere lazy + freeze, introducir versionado por evento: cada run usa un snapshot, pero el registro global puede crecer entre runs.
10. ctx.emit() es correcto, pero la atribucion via bus.publish() depende de AsyncLocalStorage
Referencia:
src/arts/orca/engine-orca.ts:133src/arts/orca/engine-orca.ts:204src/arts/orca/engine-orca.ts:864src/arts/orca/als.tssrc/arts/orca/README.md:606src/arts/orca/README.md:621src/arts/orca/README.md:1470
El diseno correcto es claro: modulo -> bus.publish(), accion -> ctx.emit().
El motor intenta interceptar bus.publish() dentro de acciones mediante
AsyncLocalStorage cuando esta disponible. En navegador puede no estar disponible,
por lo que el mismo bus.publish() dentro de una accion puede ser hijo en Node y
root event en browser.
Impacto:
- Trazas distintas entre SSR/tests Node y browser.
- Reentry guards no aplican igual si un evento derivado sale como root.
Recomendacion:
- Mantener la regla dura: las acciones usan
ctx.emit()siempre. - Tratar la interceptacion ALS como bonus diagnostico, no como contrato.
- Anadir lint/documentacion: no usar
App.Bus.publish()dentro de una accion deorcasalvo que se quiera crear root event explicito.
11. engine-orca.ts ya es un monolito de responsabilidades
Referencia:
src/arts/orca/engine-orca.ts(~58 KB)
El engine concentra registro, cola, trace state, reentry, ejecucion de waves, timeouts, compensation, validation, ID generation, diagnostics y public API.
Impacto:
- Dificulta revisar invariantes delicadas como "trace cleanup + parallel".
- Hace mas probable que futuras features (
runTimeoutMs,setupOrca, inspector) entren sin frontera clara. - Ya contradice la direccion del ecosistema de reducir monolitos (
connection.tsse venia refactorizando por el mismo motivo).
Recomendacion de split:
queue.ts: enqueue, policies, drain, in-flight counters.trace.ts: envelope, trace state, reentry guards, release.runner.ts: stages, waves, action execution, status precedence.timeouts.ts: action timeout helpers y timer keys.compensation.ts: LIFO compensation / transaction compensation.validation.ts: validate/commit helpers.ids.ts: factories deterministas.engine-orca.ts: composicion publica.
12. Los presets usan action ids y tokens inline/locales
Referencia:
src/arts/active-app/presets/cache-clear-on-identity-change.ts:6src/arts/active-app/presets/cache-clear-on-identity-change.ts:7src/arts/active-app/presets/cache-clear-on-revoke.ts:6src/arts/active-app/presets/cache-clear-on-revoke.ts:7src/arts/active-app/presets/perm-invalidate-on-identity-change.ts:6src/arts/active-app/presets/perm-invalidate-on-identity-change.ts:7
Los eventos del ecosistema ya estan centralizados como constantes, pero los
ACTION_ID y TOKEN_* de presets quedan como strings locales no exportados.
Impacto:
- No se pueden reutilizar en tests de integracion, docs, inspector
/test/orcao setup tipado. - Rompe la regla emergente: "eventos, tokens y action ids como constantes".
- El inspector no puede mostrar nombres canonicos importables.
Recomendacion:
- Crear
src/arts/active-app/presets/consts.tso exportar desde cada preset:APP_ORCA_ACTION_CACHE_CLEAR_ON_IDENTITY_CHANGE,APP_ORCA_TOKEN_CACHE_CLEARED_ON_IDENTITY_CHANGE, etc. - Usar nombres de constantes en README y pagina docs.
Hallazgos P3
13. Header de engine-orca.ts esta obsoleto
Referencia:
src/arts/orca/engine-orca.ts:24src/arts/orca/engine-orca.ts:25src/arts/orca/engine-orca.ts:26
El comentario inicial dice que after, unless, abortOn,
actionTimeoutMs y compensate se aceptan pero se ignoran. El motor ya los
implementa.
Impacto:
- La siguiente persona que lea el archivo empieza con un mapa mental falso.
- Ya se corrigieron comentarios en
types.ts,consts.tsyresult.ts, pero el comentario mas importante del motor sigue atrasado.
Recomendacion:
- Actualizar el bloque de cabecera para describir el estado real.
- Evitar version tags contradictorios dentro del codigo; mover roadmap al README.
14. El README de orca mezcla contrato actual, boceto y roadmap en un solo flujo
Referencia:
src/arts/orca/README.md:511src/arts/orca/README.md:1411src/arts/orca/README.md:1506src/arts/orca/README.md:1522
Ejemplo claro: una seccion dice que en v0 los tokens son flags sin payload; otra seccion posterior dice que los tokens con payload ya estan implementados. Esto no es solo estetico: afecta al modo en que un desarrollador modela acciones.
Impacto:
- La documentacion no sirve como contrato normativo.
- Los lectores no saben si estan viendo la version deseada o la version real.
Recomendacion:
- Reestructurar README en tres bloques cerrados:
- "Contrato actual implementado"
- "Patrones recomendados"
- "Roadmap / no implementado"
- Eliminar del contrato actual cualquier API no exportada (
setupOrca) o moverla a roadmap. - Mantener una tabla "Feature -> estado -> archivo/test".
15. Falta una prueba compuesta del caso que motivo orca: cambio de usuario con cache/perm/connection
Referencias:
src/arts/active-app/test/presets.test.tssrc/arts/orca/test/engine-orca.test.ts
Hay buena cobertura unitaria de orca y presets basicos. Falta el escenario
ecosistema que debe probar el valor real:
- Usuario A abre sesion.
- Chat/conexion usa credencial A.
- Cache actor-scoped guarda datos de A.
- Perm calcula snapshot de A.
- Cambia a usuario B.
- Orca ejecuta clear cache, invalidate perm y reauth/close connection.
- Ningun dato/credencial de A queda observable.
Impacto:
- El sistema puede estar correcto por modulo pero fallar justo en composicion.
- El caso "chat con credenciales antiguas" sigue sin prueba de regresion.
Recomendacion:
- Crear test de integracion en
src/arts/active-app/test/ecosystem-orca.test.tso equivalente. - Usar fakes de cache/perm/connection con counters y credenciales capturadas.
- Verificar orden por
OrcaRunResult: cache -> perm -> connection si se decide dependencia via tokens.
Observaciones positivas
App.Bus,App.TimersyApp.Orcaya son core siempre presentes encreateActiveApp(), yOrcaes inerte hasta registrar acciones. Esa decision encaja con el diseno enterprise sin obligar a cada app a crear singletons manuales.- Los presets viven en
active-app/presets, no dentro de los artefactos. Esto es correcto:cacheno debe conocersession;permno debe conocerauth;orcano debe conocer modulos. ActiveOrcaes un wrapper fino y razonable: estado reactivo, sin meter logica del engine en Svelte.- La suite focalizada de
orcaya es grande: 169 tests entre engine/active/result y presets. Para un modulo recien nacido, eso es muy buena base. ctx.signalexiste enOrcaActionContext; eso habilita cancelacion cooperativa y es la direccion correcta.
Recomendacion de orden de trabajo
- Corregir P1.1: trace cleanup con runs paralelos.
- Cerrar P1.2:
providesdebe ser contrato real ovalidate()debe declararse best-effort. - Resolver P1.3: renombrar/split de
replacepara evitar semantica ambigua. - Sustituir
Date.now()/Math.random()por factories deterministas. - Decidir
setupOrca(): implementarlo minimo o moverlo fuera de v0. - Crear preset de
connectiony test compuesto usuario A -> usuario B. - Reordenar README para separar implementado/recomendado/roadmap.
- Refactorizar
engine-orca.tspor responsabilidades antes de anadir run/stage timeout, inspector visual o setup tipado.
Conclusion
orca merece seguir. No es "otro bus": es el sitio correcto para convertir
flujos inter-modulo en artefactos trazables y testeables. Pero precisamente por
eso no puede permitirse ambiguedad en nombres, timeouts, tokens y concurrencia.
El ecosistema esta cruzando una frontera importante: de librerias coherentes a
runtime de aplicacion. La prioridad ahora no es meter mas features, sino hacer
que el contrato de orca sea tan fiable como su idea.