ye-AST / docs

Verdad de código determinista

El IDE de tu agente.

ye-AST le da a tu agente lo que un IDE te da a ti: quién llama a un símbolo, qué depende de un cambio, dónde aparece esa dependencia y cuán completa es la respuesta. Deriva cada respuesta de código, git y contratos declarados, e indica lo que no pudo ver.

Ningún LLM corre dentro del motor. “Unknown” es una respuesta explícita, y un resultado vacío nunca significa “sin impacto”.

7comandos de lecturamap · impact · callers · importers · outline · workspace · decisions
2trust modesuntrusted por defecto; trusted se declara
9tipos de cutcada punto ciego tiene nombre
0llamadas a un LLMel motor decide, el agente lee
Una petición cruza una frontera y produce un fact adapter de entradaCLI · MCP composicióncablea ambos lados caso de usoImpactQueries puertolo que necesita adaptergit · codegraph Fact<ImpactValue> · complete | partial | unknown
El core decide; las capas que lo rodean solo transportan peticiones y resultados. El CLI, el servidor MCP y el protocolo de query alcanzan el mismo caso de uso porque composición lo inyecta.

El contrato de fact

Respuestas que dicen “no lo sé”

Cada query devuelve un Fact. Su estado decide si un resultado vacío significa “no hay” o “no se vio”.

complete

El recorrido terminó.

Nada que pudiera añadir un llamador quedó sin ver. El valor cubre todo lo que hay dentro del alcance declarado.

Léelo como: dentro de este alcance, esta es la respuesta completa.

partial

Algo detuvo el recorrido.

Cada causa es un cut, y cada cut nombra dónde se detuvo: un límite, un nombre sin resolver, un archivo sin extractor o una ruta fuera del export.

Léelo como: lo que está más allá de un cut no se conoce.

unknown

No hay respuesta posible.

La razón indica la causa: index-unavailable, source-unreadable, out-of-scope…

Nunca lo leas como “no hay impacto”.

Qué hace que un fact sea el mismo fact

schema + inputs + producer

La identidad es la única clave de invalidación. Cambia el alcance, el contenido, la config o la versión de un engine y es un fact distinto.

src/core/domain/shared/fact.ts:73-90, 193-194 · RFC-0002 regla 5

trust trusted | untrusted alcance lenguajes, frameworks, include, exclude content digest de los bytes exportados config límite, targets, files origin full | sync engines versiones exactas

Cómo leer un fact partial

Nueve tipos de cut

Todo fact partial lista sus cuts con estos nombres (src/core/domain/shared/fact.ts:114-128). Las instrucciones del servidor MCP indican a un agente que una respuesta partial conserva sus hallazgos conocidos y lista sus cuts, y que solo debe subir un límite cuando un cut lo nombra (src/mcp/server.ts:50-69). La tabla indica qué hacer con cada uno.

CorteQué significaQué hacer
depthEl recorrido se detuvo en el límite de profundidad.Sube budget.depth, o pregunta por el símbolo del cut con callers.
hubUn símbolo alcanzado tiene más llamadores de tipo llamada que el presupuesto hubFanIn, así que el recorrido no lo expandió. El símbolo sigue en la respuesta; lo que se detiene es el ascenso a través de él.Sube hubFanIn, o pregunta con callers solo por ese símbolo.
caller-budgetSe agotó expansions, o un presupuesto de export detuvo el snapshot.Sube el límite, o acota la petición con alcance.
unresolved-linkUn nombre que el índice no pudo resolver puede apuntar a un símbolo recorrido.Abre cada lugar y decide; tras una eliminación, cada lugar que aún lo nombra se rompe.
no-extractorUn archivo que ye-AST no puede leer: una plantilla, una hoja de estilos, un lenguaje sin extractor.Léelo tú cuando importe para la tarea.
not-exportedUna ruta que el snapshot dejó fuera (symlink, submódulo, ruta insegura).Léela tú; no se leyó nada debajo.
deadlineSe acabó el tiempo antes de que la respuesta estuviera completa.Pregunta otra vez; acota el alcance si se repite.
sectionUna sección de una respuesta compuesta no se pudo producir.El resto se mantiene; volver a preguntar puede completarla.
node-capUn recorrido se detuvo en un tope de nodos.Acota el alcance o pregunta por menos símbolos.

Superficies

Tres formas de entrar, un solo núcleo

Un adaptador de entrada convierte una petición externa en una llamada y da forma a la respuesta. Nunca llama directamente a un adaptador ni a un caso de uso; composición inyecta las query families.

comandos Puntos de entrada cada comando y dónde vive
Puntos de entrada
SuperficieQué exponeDónde
ye-ast mapLos puntos de entrada de una revisión; --live para un working tree trusted.src/cli/main.ts:296-299
ye-ast impactEl cambio desde el merge base hasta head, con opciones de límite y alcance.src/cli/main.ts:300-303
ye-ast callersQué depende de símbolos o rangos de líneas.src/cli/main.ts:304-307
ye-ast importersImporters, users y namers sin resolver por archivo.src/cli/main.ts:308-311
ye-ast outlineSpans de declaraciones e imports de los archivos pedidos; los archivos sin nodo en el índice se listan como unheld.src/cli/main.ts:312-315
ye-ast workspaceLos nombres externos que usa un repositorio, los repositorios candidatos de cada uno y los nombres que ningún repositorio sirve; --offline no refresca ningún remoto.src/cli/main.ts:316-319
ye-ast decisionsLos huecos de configuración que el código no puede cubrir, cada uno con opciones respaldadas por evidencia; no escribe nada.src/cli/main.ts:320-323
ye-ast initEscribe la declaración de trust, el exclude local y la fixed layer; imprime el registro MCP.src/cli/main.ts:104 · src/core/application/install/install.ts:26
ye-ast mcpServidor MCP sobre stdio con tools de solo lectura; sirve los repositorios declarados, y cada llamada elige uno con repo.src/composition/mcp.ts:9-23
ye-ast serveEl protocolo de query sobre stdio; stdout solo lleva líneas de protocolo.src/protocol/query-server.ts

Solo lectura por tipo. El servidor MCP recibe solo query families de lectura: EntrypointQueries, ImpactQueries, OutlineQueries, WorkspaceQueries, WorkspaceImpactQueries, DecisionQueries y ContractConsequencesQueries. No existe ningún método de escritura, y las diez tools están anotadas como de solo lectura.

El servidor también incluye instrucciones: cuándo llamar a cada tool y cómo leer una respuesta. Complete es relativo al alcance declarado, partial conserva los hallazgos conocidos y lista sus cuts, unknown nunca significa sin impacto, y un límite se sube solo cuando un cut lo nombra.

Un servidor sirve varios repositorios declarados: ye-ast mcp [<launch-root>] [--repo <id> <root>]... los declara y cada llamada elige uno con repo (por defecto, el repositorio de arranque). Registrar un repositorio no le concede trust.

src/mcp/query-runner.ts:27-37 · src/mcp/server.ts:50-69 · src/composition/mcp.ts:9-23

Las otras tools y controles

  • ye_ast_outline devuelve el tipo, el nombre y el rango de líneas de cada declaración y los archivos que importa un archivo, nunca texto fuente. Los archivos pedidos de los que el índice no tiene nodo vuelven como unheld, que no significa “nada”.
  • ye_ast_workspace devuelve los nombres externos que usa un repositorio (HTTP, mensajería, dependencias), los repositorios candidatos de cada uno y los nombres que ningún repositorio sirve. Los clones locales que aportes se usan tal cual, nunca se descargan.
  • ye_ast_decisions devuelve los huecos que el código no puede cubrir (membership, repository, library, gateway, revision, remote, trust), cada uno con opciones respaldadas por evidencia. No escribe nada.
  • ye_ast_contract_consequences devuelve qué rompe un cambio de contrato de request o response, a partir de hipótesis escritas o de un diff del contrato: cada uso de un consumidor o productor de la request con su veredicto y la cadena que lo prueba, y cada punto donde se pierde el flujo como unknown. Una respuesta sin hallazgos nunca significa que el cambio sea seguro.
  • mode cambia solo la presentación, nunca la cobertura: summary da los hallazgos, details la evidencia y las ubicaciones, full el JSON completo del resultado con texto de navegación.
  • Entrypoints, callers e impact paginan la evidencia que omite el texto: select y page van juntos, y page.limit es obligatorio. expect verifica la identidad de un resultado; replay vuelve a ejecutar la query y falla si el resultado cambió, porque ye-AST no guarda ninguna captura anterior.

src/mcp/server.ts:50-69 · src/mcp/query-schema.ts:158-205 · src/mcp/presentation.ts:5-8 · src/core/domain/outline/outline-fact.ts · src/core/domain/decisions/decision.ts:4

Solo MCP · ye_ast_compose

Combina respuestas en una sola llamada

Envía de 1 a 16 queries tipadas de las siete familias (entrypoints, impact, callers, importers, outline, workspace, decisions) y recibe una respuesta fusionada. Agrupa queries relacionadas que comparten entidades; si una query posterior depende de una coordenada, obtén primero esa coordenada.

  1. 1–16 queriestipadas; las idénticas se fusionan
  2. en ordenuna a una, con un único plazo compartido
  3. tablas fusionadasuna entrada por archivo, declaración, evidencia o relación; se conservan todas las fuentes
  4. conexiones + coberturaderivadas solo entre lecturas que coinciden

Prueba una combinación

Elige las queries, lee la respuesta fusionada.

Queries combinadas
Modo de respuesta

tamaño de la respuesta

Respuestas reales capturadas sobre un fixture de dos repositorios (shop y web). Compose añade sobrecarga: una query sola, queries que no comparten nada o el modo full pueden costar más que las llamadas separadas. A cambio obtienes una respuesta fusionada con sus conexiones y su cobertura.

respuestacomplete


          
No es una transacción
Las queries pasan por el mismo runner que las tools individuales. La llamada no es atómica y no guarda nada; el primer fallo de una fuente la termina con composition-source-fault.
Fusionadas, no mezcladas
Los facts se normalizan en tablas compartidas. Los archivos, declaraciones, evidencias y relaciones idénticos se fusionan y conservan todas sus fuentes, así que cada fuente mantiene su propia cobertura.
Las conexiones exigen lecturas que coincidan
handler-declaration, reached-handler, linked-entrypoint, change-dependent, shared-file-import, used-import y shared-support enlazan hallazgos solo entre lecturas con el mismo schema, producer, trust, engines, workspace y snapshot. shared-file-import y shared-support solo repiten una observación exacta, así que también aceptan otra versión del mismo producer. Si no, se informa un issue context-mismatch o snapshot-difference. shares-evidence significa la misma ubicación, no causalidad.
Un recibo que puedes repetir
Los modos summary y details devuelven texto más un recibo: una identidad de verificación (mcp-c1) y las peticiones para repetirlas. Envíalas de vuelta con expect y el mismo conjunto debe seguir dando el mismo resultado.

src/mcp/composition-input.ts:13-19 · src/mcp/compose-request.ts · src/core/application/composition/compose-evidence.ts:207-237, 600-682 · src/mcp/render-composition.ts:93

Trust y snapshots

Dos modos de confianza, una regla

Un repositorio nunca eleva su propio trust. El trust describe el contenido del repositorio, nunca la máquina, y se declara fuera de él: un host lo hace a través de la librería o del protocolo, y un usuario con ye-ast init o con un flag. Sin declaración, el CLI y el servidor MCP corren untrusted.

default

untrusted

Lee solo un snapshot exportado desde git en un sha, nunca el repositorio en sí.

  1. 01 Resuelve la revisión a un sha completo.
  2. 02 ls-tree lista el árbol; solo se seleccionan los archivos dentro del scope.
  3. 03 cat-file --batch escribe cada blob en un directorio scratch.
  4. 04 Los extractores y codegraph leen el export, no el checkout.
  5. 05 El fact registra el sha y el digest de contenido.
  • No se ejecuta código del repositorio.
  • No se respeta ningún manifiesto, .gitignore, config de engine ni índice preconstruido del repositorio.
  • Sin symlinks, sin red.
declarado

trusted

Añade el working tree y el refresh de remotes, siempre hacia el store propio de ye-AST.

  1. 01 El mismo camino de export en un sha.
  2. 02 --live sustituye head/revision por el working tree.
  3. 03 git lista las rutas rastreadas con ls-files -z -s --cached y las no rastreadas con ls-files -z --others --exclude-standard.
  4. 04 ye-AST las copia y calcula su hash en su espejo; codegraph lee el espejo.
  5. 05 Un lock, un state file y sync({ paths }) mantienen el grafo de esos bytes.
  • --live se rechaza bajo untrusted con live-requires-trusted.
  • Las ediciones se copian, nunca se enlazan con hard links.
  • Una respuesta desactualizada lo indica por stderr; el fact no cambia.

La regla de live: un fact live describe bytes que ye-AST copió y les calculó el hash, y el grafo que lee es el grafo de esos mismos bytes. El motor nunca recorre el repositorio.

docs/architecture/rfc/0010-impact-queries.md “Live head” · src/core/application/live/live-tree.ts

Invariantes

Lo que nunca se mueve

  • Solo lectura para los agentes. El servidor MCP recibe solo query families de lectura, así que una escritura es imposible por tipo (src/mcp/query-runner.ts:27-37).
  • Determinismo. Salida ordenada, rutas relativas al repositorio, sin ids internos del índice, el snapshot en cada fact.
  • Redacción antes de la salida. Los patrones siempre; los secretos por valor solo en el proceso que ya los tiene.
  • Falla de forma visible y degrada de forma explícita. Un fallo tipado o un unknown/partial explícito, nunca un resultado vacío.
  • codegraph solo a través de su adaptador. El SQL crudo vive solo ahí, con versión comprobada; la telemetría siempre está apagada y su shim de CLI nunca se llama.

Arquitectura

Sigue una petición por las capas

Elige un flujo y recórrelo paso a paso: cada paso resalta los módulos y las aristas que cruza y explica por qué. Selecciona un módulo para ver qué puede importar y qué nunca alcanza. Mantén Ctrl (⌘ en Mac) y haz scroll para ampliar el grafo.

Flujo

impact

100%
1 / 8

El recorrido

Qué sigue el recorrido y dónde termina

Estas reglas deciden qué aristas sigue un recorrido y qué puede ver la respuesta. El simulador las aplica a un repositorio de ejemplo, y dos ejecuciones reales muestran el resultado.

Los cuatro límites

profundidad
Cuántos saltos desde la semilla puede subir el recorrido. La semilla está en profundidad 0; sus llamadores directos en profundidad 1.
hub fan-in
El fan-in es el número de llamadores de tipo llamada que tiene un símbolo: cada arista de llamada que apunta a él, la haya seguido el recorrido o no. El hub fan-in es un presupuesto opcional sobre esa cuenta. Cuando un símbolo alcanzado lo supera, el recorrido deja de expandirlo y emite un cut hub en ese símbolo. El símbolo sigue en la respuesta; el presupuesto solo evita que el recorrido suba a través de una utilidad compartida que, de otro modo, arrastraría todo el repositorio. No cuenta las llamadas que hace el símbolo.
expansiones
Cuántos símbolos alcanzados puede expandir el recorrido. Cuenta símbolos expandidos, no nodos alcanzados.
deadline
Un límite de tiempo de reloj. Un fact cortado por ese límite queda fuera de la promesa de determinismo y nunca se almacena.

Cuatro mecánicas que deciden la respuesta

01 El tipo declarante a la misma profundidad, y luego se detiene ADR-0017

Una ruta nombra una clase, no un método. Cuando el recorrido alcanza un método, también alcanza el tipo que lo declara, a la misma profundidad y con confianza 1 (walk.ts:82-87). Ese tipo se expande solo por aristas de tipo completo: extends, implements y uses-component / uses-directive / uses-pipe de Angular. No se expande hacia quien lo inyecta o importa; de lo contrario, un solo miembro alcanzado arrastraría todo.

src/core/domain/impact/edge-policy.ts:33-39 · src/core/application/impact/inbound-edges.ts:92-102

02 Dispatch de interfaz, en ambos sentidos derivado por ye-AST

Los puentes interface-impl de codegraph se detienen en silencio después de 40 por par clase-supertipo, así que ye-AST deriva los suyos: un método y el método del mismo nombre de un tipo por encima, para cada nodo alcanzado; hacia abajo solo cuando la declaración alcanzada es el contrato que cambió, porque una declaración cambiada cambia lo que sus implementaciones deben cumplir. Un camino que subió nunca vuelve a bajar a un hermano.

src/core/application/impact/inbound-edges.ts:123-169 · src/core/domain/impact/edge-policy.ts:50-55

03 El problema de this.field.member origen de campo

this.auth.login() es una referencia sin resolver, no una arista de llamada. Si la clase declara auth con un origen fijo, ye-AST resuelve el uso: un campo que contiene el tipo del miembro convierte el código en llamador; un campo que contiene un tipo no relacionado lo descarta como uso; un campo que contiene un subtipo lo deja sin resolver. Por eso el recorrido puede seguir dispatch real sin convertir cada método del mismo nombre en llamador.

src/core/application/impact/inbound-edges.ts:265-302 · src/core/domain/impact/edge-policy.ts:40-45

04 La confianza es la del mejor camino, no un conteo max-min

Un camino es tan seguro como su arista menos segura, y el recorrido informa del mejor de esos caminos desde cualquier semilla. Una arista heurística sin puntuación cuenta 0.3. En la ejecución real: 1 en la semilla, 0.9 en login, 0.85 en onSubmit. El fan-in es otra cosa: cuenta los llamadores de tipo llamada, se hayan seguido o no, para que un renderizador pueda clasificar o colapsar hubs sin que el fact los corte.

src/core/application/impact/walk.ts:172-188 · src/core/domain/impact/edge-policy.ts:77-101

05 La política de aristas completa, fila por fila la tabla que lee el recorrido
Arista hacia un nodo alcanzadoSeguidaPor qué
calls, instantiates desde una función, método, clase, componente, constante, variable o inicializador de camposíEl comportamiento depende del destino.
Un this.<member> o this.<member>.<rest> sin resolver dentro de la clase que lo declarasíEl propio código de la clase usa el miembro.
references hacia una función, método, valor o clasesíLa fuente lo usa.
references hacia una interfaz o type alias (un DTO)síUn cambio de tipo rompe a sus usuarios; qayaba no sigue estas.
extends, implements hacia una clase o interfazsíUn subtipo depende de su supertipo.
Método de interfaz → método de implementación del mismo nombre, derivado por ye-ASTsí, ambos sentidosDispatch en tiempo de ejecución; los puentes interface-impl de codegraph se detienen en silencio después de 40 por par.
Un método alcanzado → su tipo, a la misma profundidad; desde ese tipo solo extends/implements y uses-*síLas rutas y componentes nombran la clase, no el método; ADR-0017 conserva la clase y evita que se expanda hacia los injectors.
imports hacia un nodo de archivonoUn nodo de archivo no lleva a ningún lado.
imports hacia un símbolosí cuando se usaSolo cuando el código top-level del archivo que importa lo usa.
Una clase inyectable sin llamador → el código top-level de sus importerssíInyección sin una llamada estática.
injects, uses-component, uses-directive, uses-pipesí, confianza 1Se leen de las fuentes Angular, no se adivinan.
navigatesnoUn enlace del router es navegación, no dependencia.
Las aristas angular-template y angular-event de codegraphnoADR-0014; las relaciones A2/A4 propias de ye-AST traen las suyas.
Cualquier arista desde un archivo de testnoLos tests no son llamadores; el alcance declarado lo dice.
ContenciónnoEstructura, no dependencia.

Todas las familias de consulta usan la misma versión del producer (ADR-0024). src/core/domain/impact/edge-policy.ts:14-58 · docs/architecture/rfc/0010-impact-queries.md:88-109

Simulador del recorrido

La política, en un repositorio de ejemplo.

El motor no se ejecuta en esta página. Es un modelo fiel del recorrido sobre un grafo pequeño, con la misma política de aristas, expansión de tipos declarantes, confianza y cuts. Cada regla que aplica está citada abajo.

hub fan-in es un presupuesto sobre el fan-in: el número de llamadores de tipo llamada que puede tener un símbolo antes de que el recorrido deje de expandirlo y emita un cut hub. Déjalo vacío para no aplicar límite. La profundidad cuenta saltos desde la semilla; las expansiones cuentan símbolos expandidos.

semilla alcanzado no alcanzado seguida archivo de test (rechazada) navegación / importación de archivo (ignorada) punto de entrada Las flechas apuntan en el sentido de la llamada. El recorrido va en sentido inverso, contra ellas.
Recorrido de impact sobre el repositorio de juguete Un grafo de símbolos. El recorrido empieza en la semilla y sube hacia sus llamadores, nivel por nivel.
traza de políticaaristas que el recorrido no siguió
Símbolos alcanzados, en el orden en que el fact real los escribe
prof.símboloarchivoconfianzafan-invía

El grafo de ejemplo es ilustrativo; las reglas no. Solo se dibujan los símbolos alcanzados: la tira de abajo lista el resto, y la traza de política nombra cada arista que el recorrido rechazó y por qué. El recorrido expande cada símbolo una vez, entra al tipo declarante de un método alcanzado a la misma profundidad y sigue solo las filas de la política de aristas: un archivo de test nunca es llamador, la navegación no es dependencia y una importación de archivo no lleva a ningún lado.

Ejecución de referencia

Dos ejecuciones reales, capturadas de este checkout.

Los dos fixtures se crearon fuera del worktree, se leyeron como untrusted y se consultaron con este build. Los valores de abajo se copian del JSON.

TypeScript plano

complete

complete
ye-ast impact <repo> --base HEAD~1

La semilla es validateToken. El recorrido sube hasta AuthService.login y AuthController.loginHandler; las clases se unen a la misma profundidad que sus métodos. Este fixture no tiene puntos de entrada, y eso no es un fallo.

0 validateTokentoken.tsfan-in 1 1
1 AuthServiceauth.service.tsfan-in 0 0.9
1 loginauth.service.tsfan-in 1 0.9
2 AuthControllerauth.controller.tsfan-in 0 0.85
2 loginHandlerauth.controller.tsfan-in 0 0.85

snapshot 4e00fd9b293a · merge base 8dba227feee2 · trust untrusted

Rutas Angular

partial, y útil

partial
ye-ast impact <repo> --base HEAD~1

El mismo cambio, ahora con una tabla de rutas. El recorrido alcanza LoginComponent a través de onSubmit, y el join hace aparecer /login. El cut viene del snapshot, no del cambio: un archivo .rb no tiene extractor.

0 validateTokentoken.tsfan-in 1 1
1 AuthServiceauth.service.tsfan-in 0 0.9
1 loginauth.service.tsfan-in 1 0.9
2 LoginComponentlogin.component.tsfan-in 0 0.85
2 onSubmitlogin.component.tsfan-in 0 0.85
2 /loginlogin.component.ts 0.85

snapshot 2dff4ecee21a · merge base d2a9f2b9368b · cut no-extractor en src/legacy/report.rb

el fixtureel código detrás de la ejecución

src/auth/token.ts

export function validateToken(token: string): boolean {
  return token.length > 40; // cambiado: era > 20
}

src/auth/auth.service.ts

export class AuthService {
  login(token: string): boolean {
    return validateToken(token);
  }
}

src/ui/login.component.ts

@Component({ selector: "app-login", … })
export class LoginComponent {
  constructor(private readonly auth: AuthService) {}

  onSubmit(token: string): boolean {
    return this.auth.login(token);
  }
}

src/app.routes.ts

export const routes = [
  { path: "login", component: LoginComponent },
  { path: "dashboard", component: DashboardComponent,
    canActivate: [AuthGuard] },
];

Este es el fixture de Angular detrás de la ejecución partial; la ejecución plana solo cambia el caller, un AuthController en vez del componente. El cambio toca una línea de token.ts. El recorrido sube tres saltos, y el join convierte el componente en /login. El archivo de test que también llama a login está en el repositorio, pero nunca es llamador, por política.

Límites

Límites y cómo reproducirlo

Lo que esta página deja fuera y los comandos que reproducen sus ejecuciones. Los términos del glosario aparecen resaltados en el texto: selecciona uno para leer su definición.

Límites de esta página

Lo que no muestra

  • El simulador modela el algoritmo; no es el motor. Usa las mismas filas de política sobre un grafo más pequeño, pero codegraph, el compilador de TypeScript y git no se ejecutan.
  • Las ejecuciones reales vienen de dos repositorios fixture creados para esta página. No forman parte de la suite de tests y no están en el repositorio.
  • La página cubre las superficies del MVP (librería, CLI, MCP, protocolo). Hooks y el daemon son posteriores; el grafo los marca “después” a propósito.
  • Los números de línea son de este checkout (2026-11-06, paquete 0.4.0, schema 0.21.0). Un refactor los mueve.

Reproducir la evidencia

# los dos fixtures son repositorios git normales
node --import tsx src/composition/main.ts map      <fixture>
node --import tsx src/composition/main.ts impact   <fixture> --base HEAD~1
node --import tsx src/composition/main.ts callers  <fixture> src/auth/token.ts:validateToken
node --import tsx src/composition/main.ts importers <fixture> src/auth/token.ts

# la puerta de arquitectura
npm run check