> ARCHIVED — historical brainstorming. orca v1 is shipped. Items
> listed below as "out of v0" (commit / replace / timeouts /
> transaction / compensate / parallel / abortOn unless / tokens con
> payload / fan-in) all live in the engine today. The current
> contract is `src/arts/orca/README.md`; this file is preserved as a
> record of the design conversation, not as guidance.

Clippy-pet verdict: `orca` es una ballena preciosa, pero si intentamos montarla entera en v0 nos hunde la barca.

Lo correcto:

```txt
v0 = kernel
v1 = enterprise orchestration
```

`orca` está bien pensado porque tiene tres aciertos enormes:

- Desacopla módulos: `orca` no sabe qué es `cach`, `perm`, `sess` o `connection`.
- Convierte flujos críticos en artefactos trazables: `OrcaRunResult`.
- Usa tokens como hechos semánticos per-run, que es la parte diferencial.

Pero ahora mismo el README mezcla kernel y futuro. Para que sea implementable, v0 debería recortarse así:

```txt
entra en v0:
  setupOrca
  createEngineOrca
  App.Orchestration inerte
  onEvent
  stages
  queue/drop
  tokens per-run flag
  after/provides
  OrcaResult success/skipped/error/fatal/interrupted
  OrcaRunResult
  validate()
  diagnostics

sale de v0:
  commit()
  replace
  timeouts
  transaction
  compensate
  parallel
  abortOn/unless avanzados si complican
  tokens con payload
  fan-in
```

La pregunta decisiva no es “¿está bien diseñado?”. Sí, lo está.

La pregunta correcta es: **¿cuál es el núcleo mínimo que demuestra que `orca` merece existir?**

Respuesta: `event -> staged actions -> tokens -> result trace`.

Si eso funciona, lo demás se puede crecer con calma.


como evitamos la reentrada en orca , si no establecemos en el payload del evento los eventos que le preceden en el stack ?  al disparar el componente verifica si esta gestionando ya un evento de ese stack y lo omitiria , como lo suelen hacer el evitar loops infinitos ? 


La forma sana no es meter “eventos precedentes” en el payload de negocio. Eso contaminaría todos los eventos con metadata de orquestación y acabaría mezclando dominio con runtime.

Lo correcto es que `orca` envuelva cada evento en un **OrcaEnvelope** interno:

```ts
interface OrcaEnvelope<TPayload = unknown> {
    readonly event: string;
    readonly payload: TPayload;
    readonly meta: {
        readonly eventId: string;
        readonly parentEventId?: string;
        readonly runId?: string;
        readonly traceId: string;
        readonly depth: number;
        readonly stack: readonly string[];
        readonly emittedBy?: OrcaActionId;
    };
}
```

El payload sigue limpio:

```ts
{ previousActorId, nextActorId }
```

Y `orca` conserva el contexto:

```ts
{
    event: APP_EVENT_CACHE_CLEARED,
    meta: {
        parentEventId: 'evt-1',
        traceId: 'trace-7',
        depth: 2,
        stack: [
            APP_EVENT_USER_IDENTITY_CHANGED,
            APP_EVENT_CACHE_CLEARED
        ],
        emittedBy: ORCA_ACTION_CLEAR_PRIVATE_CACHE
    }
}
```

Entonces la prevención de loops vive en `orca`, no en los módulos.

Reglas típicas para evitar loops infinitos:

```txt
1. No ejecutar inline eventos emitidos durante un run.
2. Encolarlos con traceId y parentEventId.
3. Mantener stack interno por trace.
4. Rechazar o saltar eventos si superan maxDepth.
5. Rechazar o saltar si el mismo evento aparece demasiado en el mismo trace.
6. Aplicar dedupeKey opcional.
7. Tener maxEventsPerTrace.
8. Tener diagnostics cuando se corta el loop.
```

Ejemplo:

```ts
const Orca = createEngineOrca({
    bus,
    timers,
    logger,
    reentry: {
        maxDepth: 16,
        maxEventsPerTrace: 128,
        repeatedEventPolicy: ORCA_REENTRY_SKIP,
        repeatedEventLimit: 2
    }
});
```

Si ocurre esto:

```txt
A -> action publica B
B -> action publica A
A -> action publica B
...
```

`orca` ve el trace:

```txt
A, B, A, B, A
```

Y puede cortar:

```ts
ORCA_RESULT_INTERRUPTED
ORCA_REENTRY_REASON_REPEATED_EVENT
```

o marcar el run como:

```ts
ORCA_RUN_ABORTED
```

Los patrones habituales en otros sistemas:

- Redux middleware suele evitar loops por convención y con guards manuales.
- Redux-Saga usa `takeLatest`, cancelación y control de tasks.
- EventEmitter no te protege: si emites recursivo, te comes el loop.
- State machines evitan loops por transición/estado: si ya estás en cierto estado, el evento no transiciona.
- Sistemas workflow usan `trace/correlationId`, depth limits, idempotency keys y dedupe.

Para `orca`, yo fijaría esto:

```txt
payload = dominio, limpio
envelope/meta = runtime, trace, stack, depth
tokens = coordinación intra-run
bus events = comunicación inter-run
```

Y añadiría al contrato v0:

```ts
interface OrcaReentryOptions {
    readonly maxDepth?: number;            // default 16
    readonly maxEventsPerTrace?: number;   // default 128
    readonly repeatedEventLimit?: number;  // default 1 o 2
    readonly repeatedEventPolicy?:
        | typeof ORCA_REENTRY_SKIP
        | typeof ORCA_REENTRY_ABORT_TRACE
        | typeof ORCA_REENTRY_ERROR;
}
```

Así evitas reentrada sin ensuciar los payloads y sin obligar a cada módulo/componente a recordar “quién vino antes”.


cual estrategia es mas arquitectonicamente mejor ? 


Arquitectónicamente, la mejor estrategia es:

```txt
payload limpio + envelope runtime interno + cola de orca + límites de reentrada
```

No metería el stack en el payload del evento.

Por qué:

- El payload pertenece al dominio: `userId`, `tenantId`, `orderId`, etc.
- El stack pertenece al runtime de orquestación.
- Si mezclas ambos, todos los módulos empiezan a conocer detalles de `orca`.
- Si mañana cambias cómo trazas reentrada, rompes contratos de eventos.
- Los eventos pueden venir de `connection`, `auth`, `sess`, `http`, etc.; no todos deberían cargar metadata de runtime.

La arquitectura correcta sería:

```txt
buss event:
  type + payload limpio

orca internal envelope:
  eventId
  traceId
  parentEventId
  runId
  depth
  stack
  emittedByAction
  dedupeKey
```

Flujo:

```txt
1. buss publica EVENT_A(payload)
2. orca crea envelope A con traceId
3. action de A publica EVENT_B
4. orca no ejecuta B inline
5. orca crea envelope B con parent=A, mismo traceId, depth+1
6. orca comprueba stack/repeated/depth
7. si es seguro, encola B
8. si detecta loop, corta con diagnostic
```

Esto es más limpio que “cada componente mira si ya está gestionando un evento de ese stack”, porque esa opción reparte lógica de orquestación por toda la app. Es justo lo que `orca` intenta evitar.

Estrategia recomendada para v0:

```ts
createEngineOrca({
    bus,
    logger,
    reentry: {
        maxDepth: 16,
        maxEventsPerTrace: 128,
        repeatedEventLimit: 2,
        repeatedEventPolicy: ORCA_REENTRY_SKIP
    }
});
```

Reglas:

- Eventos publicados durante un run se encolan, no se ejecutan inline.
- El stack es interno de `orca`.
- Si el mismo evento aparece demasiadas veces en el mismo trace, se salta o aborta.
- Si depth supera límite, aborta el trace.
- Si eventsPerTrace supera límite, aborta el trace.
- Se emite diagnostic estructurado.
- El `OrcaRunResult` registra `traceId`, `parentEventId`, `depth`, `interruptedReason`.

Mi voto: **envelope interno + queue + trace guards**. Es la opción más limpia, menos acoplada y más mantenible.



me refiero a los otros sistemas de referencia



En los sistemas de referencia, la estrategia arquitectónicamente mejor **no es meter el stack en el payload**. Casi todos los sistemas buenos separan:

```txt
payload = datos de negocio
runtime context = control, cancelación, stack, tracing, concurrencia
```

**Comparativa**
| Sistema | Cómo evita loops/reentrada | Lectura para `orca` |
|---|---|---|
| RTK Listener Middleware | Usa runtime API: `signal`, `cancelActiveListeners()`, `cancel()`, `take`, `condition`, `delay`, `pause`, `fork`. No mete stack en la action. | Muy buen referente. `orca` debería pasar `signal`, `traceId`, `runId` y control de cancelación en `OrcaActionContext`. Fuente: [RTK listener middleware](https://redux-toolkit.js.org/api/createListenerMiddleware). |
| Redux-Saga | Usa tareas y cancelación: `takeLatest` cancela la tarea anterior; `takeEvery` permite concurrencia; `race`, `cancel`, `fork`, `join`. | Bueno para políticas `queue/drop/replace/parallel`, pero no copiaría generators. Fuente: [Redux-Saga concurrency](https://redux-saga.js.org/docs/advanced/Concurrency/). |
| XState | Evita loops mediante estado, guards y transiciones. Si ya estás en un estado, un evento puede no transicionar. El control vive en la máquina, no en el payload. | Útil para flows cerrados; para `orca`, copiaría `setup()` tipado y la idea de runtime/state como dueño del control. Fuente: [XState setup](https://stately.ai/docs/setup). |
| Effect Workflow | Distingue error/cause/interruption y tiene compensación estructurada. El runtime sabe qué falló y cómo compensar; no lo mete en payload. | Muy buen referente para `OrcaInterrupted`, compensaciones futuras y `Cause`. Fuente: [Effect Workflow compensation](https://effect-ts.github.io/effect/workflow/Workflow.ts.html). |
| EventEmitter simple | No evita loops. Si un listener emite el mismo evento recursivamente, problema del usuario. | Esto es justo lo que `orca` no debe ser. |

**Veredicto**
La mejor estrategia para `orca` es una mezcla de RTK Listener + Saga + XState:

```txt
payload limpio
OrcaEnvelope interno
cola propia de orca
traceId / parentEventId / runId
AbortSignal en OrcaActionContext
política de concurrencia por evento
límites maxDepth / maxEventsPerTrace
diagnostics cuando corta loops
```

No pondría el stack en el payload. Eso es arquitectura más débil porque obliga a todos los módulos a conocer el runtime de `orca`.

La estrategia superior es:

```ts
interface OrcaActionContext {
    readonly runId: OrcaRunId;
    readonly eventId: OrcaEventId;
    readonly traceId: OrcaTraceId;
    readonly parentEventId?: OrcaEventId;
    readonly depth: number;
    readonly signal: AbortSignal;
}
```

Y el envelope interno:

```ts
interface OrcaEnvelope<TPayload> {
    readonly event: string;
    readonly payload: TPayload;
    readonly meta: OrcaEventMeta;
}
```

Así `orca` se parece a los sistemas buenos: el **runtime** controla reentrada, cancelación y concurrencia; el **payload** sigue siendo dominio limpio.


ahora mismo no se parece a eso en nada ?




Correcto: **el diseño actual apunta en esa dirección, pero todavía no se parece lo suficiente en contrato concreto**.

Ahora mismo el README ya dice cosas buenas:

```txt
payload limpio
no ejecutar inline
queue/drop/replace
tokens per-run
RunResult
App.Orchestration inerte
```

Pero faltan las piezas que lo harían parecerse de verdad a RTK/Saga/XState/Effect en lo importante:

```txt
OrcaEnvelope interno
OrcaActionContext con traceId/runId/eventId/depth
AbortSignal en acciones
cola interna explícita de orca
políticas de reentrada: maxDepth, maxEventsPerTrace
reason/result para reentry-skip / interrupted
relación formal buss -> orca listener -> queue
```

Así que mi diagnóstico es:

```txt
Conceptualmente: sí está en el camino correcto.
Contractualmente: todavía no está cerrado.
Implementablemente: aún tendría ambigüedad peligrosa.
```

La sección que habría que añadir al README antes de implementar es algo como:

```ts
interface OrcaEnvelope<TPayload = unknown> {
    readonly event: string;
    readonly payload: TPayload;
    readonly meta: OrcaEventMeta;
}

interface OrcaEventMeta {
    readonly eventId: OrcaEventId;
    readonly traceId: OrcaTraceId;
    readonly parentEventId?: OrcaEventId;
    readonly parentRunId?: OrcaRunId;
    readonly emittedByAction?: OrcaActionId;
    readonly depth: number;
    readonly stack: readonly string[];
}

interface OrcaActionContext {
    readonly runId: OrcaRunId;
    readonly event: string;
    readonly eventId: OrcaEventId;
    readonly traceId: OrcaTraceId;
    readonly depth: number;
    readonly signal: AbortSignal;
    readonly emit: <TPayload>(event: string, payload: TPayload) => void;
}
```

Y reglas:

```txt
1. Las acciones no llaman bus.publish directamente si quieren preservar trace.
2. Usan ctx.emit() para eventos derivados.
3. ctx.emit() crea envelope hijo.
4. Eventos derivados se encolan, no inline.
5. Orca corta loops con maxDepth/maxEventsPerTrace/repeatedEventLimit.
6. Si una acción llama App.Bus directamente, orca lo trata como evento raíz nuevo.
```

Esto último es importante: **si queremos trazabilidad real, las acciones deben emitir eventos derivados vía `ctx.emit()`**, no vía `App.Bus.publish()` directamente. Ahí está la diferencia entre “tenemos bus” y “tenemos runtime de orquestación”.

Así que sí: ahora mismo aún no está del todo. Tiene el esqueleto filosófico, pero le falta el contrato de runtime/envelope/context para ser una pieza robusta.





ctx deberiamos definirlo, seria otra capa mas ?




Sí, `ctx` hay que definirlo. Pero no lo vería como “otra capa” al nivel de `buss`/`orca`/`timr`; lo vería como **el runtime context de una ejecución de `orca`**.

No es un artefacto nuevo. Es parte del contrato de `orca`.

```txt
orca = engine
run = ejecución de un evento
ctx = contexto que orca entrega a cada action dentro de ese run
```

El `ctx` es donde ponemos todo lo que no debe ir en el payload:

```ts
interface OrcaActionContext {
    readonly runId: OrcaRunId;
    readonly eventId: OrcaEventId;
    readonly traceId: OrcaTraceId;
    readonly parentEventId?: OrcaEventId;
    readonly depth: number;

    readonly signal: AbortSignal;

    emit<TPayload>(
        event: string,
        payload: TPayload,
        options?: OrcaEmitOptions
    ): void;

    token(token: OrcaToken): void;

    hasToken(token: OrcaToken): boolean;
}
```

La separación queda:

```txt
payload
  Datos del evento.
  Pertenece al dominio.

ctx
  Datos/control de ejecución.
  Pertenece a orca.

App modules
  Servicios reales.
  La action los cierra por closure.
```

Ejemplo:

```ts
App.Orchestration.onEvent(APP_EVENT_USER_IDENTITY_CHANGED, {
    id: ORCA_ACTION_CLEAR_PRIVATE_CACHE,
    stage: ORCA_STAGE_MAIN,
    provides: [ORCA_TOKEN_CACHE_OK, ORCA_TOKEN_CACHE_ERROR],

    action: async (payload, ctx) => {
        if (ctx.signal.aborted) {
            return orcaInterrupted('run aborted');
        }

        const result = await App.Cache.clearActorScope(payload.previousActorId);

        if (!result.ok) {
            return orcaError(result.error, {
                emits: [ORCA_TOKEN_CACHE_ERROR]
            });
        }

        ctx.emit(APP_EVENT_PRIVATE_CACHE_CLEARED, {
            actorId: payload.previousActorId
        });

        return orcaSuccess({
            emits: [ORCA_TOKEN_CACHE_OK]
        });
    }
});
```

`ctx.emit()` es importante porque preserva traza:

```txt
run A
  action clear-cache
    ctx.emit(B)

orca crea envelope B:
  traceId = A.traceId
  parentEventId = A.eventId
  emittedByAction = clear-cache
  depth = A.depth + 1
```

Si la action llama directamente:

```ts
App.Bus.publish(B, payload)
```

entonces `orca` no sabe que B viene de A salvo que intercepte todo, lo cual es más frágil. Por eso yo pondría esta regla:

```txt
Dentro de acciones orca, usa ctx.emit() para eventos derivados.
Usa App.Bus.publish() solo para eventos raíz externos al run.
```

Entonces no es una capa adicional. Es el equivalente a:

- `listenerApi` en RTK listener middleware.
- `saga effects` en redux-saga.
- `context/event` en XState.
- `workflow context/cause` en Effect/Temporal.

Mi recomendación: sí, definir `OrcaActionContext` como contrato central de v0. Sin `ctx`, `orca` será solo un callback runner. Con `ctx`, empieza a ser runtime de orquestación.



y como sabe una accion de un modulo a la hora de emitir un evento donde lo debe hacer, por ejemplo 

auth.onChangeUser (newUser) {
    bus.publish(AUTH_CHANGE_EVENT,newUser)
    o
   ctx.publish(AUTH_CHANGE_EVENT,newUser)
}



La regla tiene que ser muy clara:

```txt
Un módulo nunca usa ctx.
Una acción de orca sí puede usar ctx.
```

Tu ejemplo:

```ts
auth.onChangeUser((newUser) => {
    bus.publish(AUTH_CHANGE_EVENT, newUser);
});
```

Eso está bien si ocurre **dentro del módulo auth**. `auth` no debe saber que existe `orca`, por tanto no puede recibir ni usar `ctx`.

En cambio esto:

```ts
auth.onChangeUser((newUser) => {
    ctx.publish(AUTH_CHANGE_EVENT, newUser);
});
```

Eso estaría mal si `auth.onChangeUser` es código del módulo. Meterías `orca` dentro de `auth`.

La separación correcta:

```txt
Módulo -> Bus
Orca action -> Ctx
```

Ejemplo completo:

```ts
// Dentro de auth
function setUser(nextUser: User) {
    currentUser = nextUser;

    bus.publish(AUTH_EVENT_USER_CHANGED, {
        userId: nextUser.id
    });
}
```

`auth` publica en `bus`. Punto. No conoce `orca`.

Ahora una acción de `orca`:

```ts
App.Orchestration.onEvent(AUTH_EVENT_USER_CHANGED, {
    id: ORCA_ACTION_CLEAR_PRIVATE_STATE,
    stage: ORCA_STAGE_MAIN,

    action: async (payload, ctx) => {
        await App.Cache.clearActorScope(payload.userId);

        ctx.emit(APP_EVENT_PRIVATE_STATE_CLEARED, {
            userId: payload.userId
        });

        return orcaSuccess({
            emits: [ORCA_TOKEN_CACHE_OK]
        });
    }
});
```

Aquí sí usamos `ctx.emit()` porque estamos dentro de una action y queremos preservar trace.

Entonces hay dos tipos de emisión:

```txt
bus.publish()
  Para módulos, componentes, servidor, código externo a orca.
  Crea evento raíz desde la perspectiva de orca.

ctx.emit()
  Solo dentro de una OrcaAction.
  Crea evento hijo dentro del trace actual.
```

Si un módulo emite durante una acción, por ejemplo:

```ts
action: async () => {
    await App.Auth.changeUser(nextUser); // Auth internamente hace bus.publish
}
```

`orca` lo verá como evento publicado durante un run, pero no sabrá con tanta precisión qué acción lo emitió salvo que tenga un contexto activo global interno. Hay dos opciones:

**Opción A, simple y limpia v0:**

```txt
Módulo publica por bus.
Orca detecta que hay run activo y lo encola como child event genérico.
parentRunId sí, emittedByAction quizá no.
```

**Opción B, más precisa:**

`orca` ejecuta cada action dentro de un “current action scope” interno. Si durante esa ejecución algún módulo hace `bus.publish`, `orca` intercepta el publish y lo marca como:

```ts
emittedByAction: ORCA_ACTION_CLEAR_PRIVATE_STATE
```

Eso requiere integración fuerte entre `buss` y `orca`.

Mi recomendación:

```txt
v0:
  módulos siempre bus.publish
  actions pueden ctx.emit
  si un módulo publica durante un run, orca lo trata como evento derivado del run si puede detectarlo, pero no exigimos emittedByAction perfecto

v1:
  integración bus/orca con current action scope para trazabilidad completa
```

Regla para desarrolladores:

```txt
Si estás escribiendo código de módulo: usa bus.publish.
Si estás escribiendo una OrcaAction: usa ctx.emit para eventos derivados del flujo.
```

Así evitamos acoplar módulos a `orca`, pero damos a las acciones una vía correcta para preservar trazabilidad.


