Auditoría de un proyecto Angular con un agente de IA

Por: Artiko
angularbuenas-practicasauditoriaagente-iallmrendimientoseguridad

Auditoría de un proyecto Angular con un agente de IA

Los catorce capítulos anteriores explican qué es un Angular de calidad y cómo se ve cada práctica en el código. Este capítulo final cierra el círculo: convierte todo el curso en un procedimiento reproducible que un agente de IA con acceso a tu repositorio ejecuta para auditar un proyecto Angular real y emitir un informe con evidencia, severidad y plan de remediación.

La diferencia con una revisión a ojo es que el agente no dice “parece que le falta OnPush”: recorre el árbol con ripgrep, encuentra los componentes sin changeDetection, cita el archivo y la línea, y estima el impacto (“re-renderiza todo el subárbol en cada evento del navegador”). El catálogo de patrones y antipatrones es la lista que este protocolo recorre; acá la volvemos ejecutable.

Cómo usar este capítulo

  1. Abrí una sesión limpia de tu agente (Claude Code, Cursor, Copilot, etc.) en la raíz del proyecto Angular a auditar.
  2. Copiá el bloque “Briefing para el agente” completo y pegalo como primer mensaje.
  3. El agente ejecuta la Fase 0 (reconocimiento) y luego las siete dimensiones, y devuelve un informe estructurado.
  4. Regla de oro: el agente audita y reporta; no modifica nada hasta que apruebes el plan de remediación.
flowchart LR
    A[Fase 0<br/>Reconocimiento] --> B[7 dimensiones<br/>de calidad]
    B --> C[Hallazgos con<br/>evidencia archivo:línea]
    C --> D[Informe priorizado<br/>por severidad]
    D -.aprobación.-> E[Remediación]

El protocolo asume que el agente tiene un intérprete de shell con ripgrep (rg). Si sólo hay grep, los patrones son equivalentes con grep -rn. Los comandos de este capítulo están pensados para pegarse tal cual.

Escala de severidad

Cada hallazgo lleva un veredicto y una severidad. Usá siempre matices, nunca binario:

SeveridadSignificado
CRÍTICOVulnerabilidad explotable o defecto que rompe producción ya (XSS con datos de usuario, secreto en el bundle, race condition que corrompe estado).
ALTODegradación seria de rendimiento o mantenibilidad que se nota en producción (todo el árbol sin OnPush, @for sin track sobre listas grandes, memory leaks).
MEDIODeuda técnica que escala mal (lógica en templates, BehaviorSubject donde va computed, componentes-dios).
BAJORoce estilístico o riesgo latente (barrel files, tests frágiles, nombres inconsistentes).

Y un estado por control: CUMPLE / PARCIAL / NO CUMPLE / N/A (justificado).

Fase 0 — Reconocimiento

Antes de auditar nada, el agente construye el mapa del proyecto. Sin esto, confundiría un proyecto zoneless con uno que olvidó provideZoneChangeDetection, o marcaría como antipatrón un NgModule que en realidad es una librería de terceros.

Versión de Angular y toolchain:

# Versión declarada y resuelta
rg '"@angular/core"' package.json
npx ng version 2>/dev/null || cat package.json | rg '"@angular|"typescript"|"rxjs"|"zone.js"'

# ¿Nx, workspaces, monorepo?
ls nx.json angular.json project.json 2>/dev/null
rg -l '"@nx/' package.json

# ¿ESLint moderno (angular-eslint) o TSLint legacy?
ls eslint.config.js .eslintrc.json tslint.json 2>/dev/null

Standalone vs NgModules, zoneless vs zone.js:

# ¿Sigue habiendo NgModules de aplicación? (excluí node_modules)
rg -c 'NgModule' src --glob '!**/node_modules/**'

# ¿Bootstrap standalone?
rg 'bootstrapApplication|provideZonelessChangeDetection|provideZoneChangeDetection' src

# ¿zone.js todavía en polyfills / angular.json?
rg 'zone.js' angular.json package.json src 2>/dev/null

Comandos disponibles y presupuestos:

rg '"scripts"' -A 20 package.json
rg 'budgets' -A 8 angular.json   # presupuestos de bundle configurados

Con esto el agente resume en 5-8 líneas: versión de Angular, si es standalone/zoneless, si usa Nx, qué linter, qué scripts hay (build, test, lint, e2e) y cuántos NgModule de aplicación quedan. Ese resumen calibra el resto de la auditoría.

Las siete dimensiones

Cada dimensión trae qué buscar, comandos concretos y el capítulo de referencia para la recomendación. El agente recorre las siete en orden.

Dimensión 1 — Arquitectura y organización

Referencia: Organización del proyecto · Inyección de dependencias

Qué buscar: barrel files (index.ts que reexportan todo un feature y rompen el tree-shaking y el lazy loading), NgModule de aplicación que ya no hacen falta, ausencia de límites entre features (imports cruzados feature-a-feature), servicios en providers de componente cuando deberían ser providedIn: 'root' o al revés.

# Barrel files sospechosos (index.ts con muchos re-exports)
rg -l "export \* from" src --glob '**/index.ts'

# NgModules de aplicación que sobreviven
rg -n '@NgModule' src --glob '!**/*.spec.ts'

# Imports que cruzan features (heurística: un feature importando otro)
rg -n "from '.*features/(?!\1)" src   # ajustar al layout real

# Constructor injection legacy vs inject()
rg -n 'constructor\(.*(private|public|readonly).*:' src --glob '**/*.ts'

Un barrel index.ts que reexporta 30 símbolos hace que importar uno arrastre los 30 al grafo del bundle; sobre una ruta lazy, anula el corte que buscaba el loadComponent.

Dimensión 2 — Componentes y diseño

Referencia: Componentes con SOLID

Qué buscar: componentes sin ChangeDetectionStrategy.OnPush, componentes-dios (cientos de líneas, muchas responsabilidades), lógica de negocio dentro del template, decorador @Input()/@Output() legacy en vez de input()/output(), sintaxis vieja *ngIf/*ngFor en vez del control flow @if/@for.

# Componentes SIN OnPush: cuenta @Component y compará con OnPush
rg -c '@Component' src --glob '**/*.ts'
rg -c 'ChangeDetectionStrategy.OnPush' src --glob '**/*.ts'
# Listado de componentes que NO mencionan OnPush
rg -L 'ChangeDetectionStrategy.OnPush' -l '@Component' src --glob '**/*.ts'

# API legacy de inputs/outputs
rg -n '@Input\(|@Output\(' src --glob '**/*.ts'

# Control flow viejo
rg -n '\*ngIf|\*ngFor|\*ngSwitch' src --glob '**/*.html' --glob '**/*.ts'

# Componentes-dios: archivos .ts de componente por tamaño
rg -l '@Component' src --glob '**/*.ts' | xargs wc -l | sort -rn | head -15

Un componente sin OnPush se revisa en cada ciclo de detección disparado por cualquier evento de la app, aunque sus datos no cambiaron. En un árbol de 200 componentes, es la diferencia entre chequear 200 nodos o los 3 que realmente cambiaron.

Para lógica en template, buscá llamadas a funciones dentro de las interpolaciones (ver Dimensión 4) y ngClass/ngStyle con expresiones complejas.

Dimensión 3 — Reactividad (signals y RxJS)

Referencia: Signals y estado reactivo · RxJS con criterio

Qué buscar: effect() usado para derivar estado (debería ser computed()), .subscribe() sin desuscripción (takeUntilDestroyed ni async pipe), BehaviorSubject manual para estado que un signal/computed modelaría mejor, .set()/.update() de una signal dentro de un effect (loop de escritura), suscripciones anidadas (subscribe dentro de subscribe).

# subscribe() sin takeUntilDestroyed cerca
rg -n '\.subscribe\(' src --glob '**/*.ts'
rg -c 'takeUntilDestroyed' src --glob '**/*.ts'

# effect() candidatos a ser computed (leen signals y setean otra)
rg -n 'effect\(\(\)\s*=>' -A 5 src --glob '**/*.ts'

# BehaviorSubject donde probablemente va signal/computed
rg -n 'new BehaviorSubject' src --glob '**/*.ts'

# subscribe anidado (leak + callback hell)
rg -n '\.subscribe\(' -A 8 src --glob '**/*.ts' | rg -n '\.subscribe\('

# .set()/.update() dentro de effect (posible loop)
rg -n 'effect\(' -A 6 src --glob '**/*.ts' | rg '\.set\(|\.update\('

Un effect que hace this.total.set(this.a() + this.b()) es un computed(() => this.a() + this.b()) mal escrito: introduce un tick extra, es más difícil de testear y puede caer en loops. Un .subscribe() sin takeUntilDestroyed() en un componente que se crea y destruye en cada navegación es un memory leak lineal: cada visita deja una suscripción viva.

Dimensión 4 — Rendimiento

Referencia: Change Detection y rendimiento de runtime · Carga inicial y Core Web Vitals

Qué buscar: funciones llamadas en bindings (se ejecutan en cada detección de cambios), @for sin track (recrea el DOM completo en cada cambio), ausencia de @defer y lazy loading en rutas, imágenes sin NgOptimizedImage, presupuestos de bundle no configurados.

# Funciones en interpolaciones/bindings del template (se re-ejecutan por CD)
rg -n '\{\{\s*\w+\(' src --glob '**/*.html'
rg -n '\[\w+\]="\w+\(' src --glob '**/*.html'

# @for sin track
rg -n '@for' -A 1 src --glob '**/*.html' | rg -v 'track'

# ¿Se usa @defer? ¿Rutas lazy con loadComponent/loadChildren?
rg -c '@defer' src --glob '**/*.html'
rg -n 'loadComponent|loadChildren' src --glob '**/*.ts'

# Imágenes sin NgOptimizedImage (usan src= en vez de ngSrc=)
rg -n '<img[^>]*\ssrc=' src --glob '**/*.html'
rg -c 'ngSrc' src --glob '**/*.html'

# Presupuestos de bundle
rg -n 'budgets' -A 8 angular.json

{{ formatearNombre(user) }} en el template se ejecuta en cada ciclo de detección de cambios, aunque user no haya cambiado; sobre una lista de 500 filas con detección disparada por un mousemove, son 500 llamadas por evento. @for (x of items) sin track obliga a Angular a destruir y recrear cada nodo del DOM cuando la referencia del array cambia, en vez de reconciliar por identidad: O(n) de churn de DOM evitable. Una imagen con <img src> en vez de ngSrc pierde el lazy automático, el dimensionado que previene CLS y la priorización de LCP.

Dimensión 5 — Datos y HTTP

Referencia: HTTP, datos y complejidad

Qué buscar: HttpClient llamado directamente desde componentes (en vez de un servicio de datos), race conditions (varias peticiones concurrentes cuyo orden de llegada importa, sin switchMap), complejidad algorítmica en el cliente (bucles anidados sobre respuestas → O(n²)), N+1 de peticiones (un subscribe que dispara una petición por ítem de una lista).

# HttpClient dentro de componentes (deberían ir en servicios)
rg -ln 'HttpClient' src --glob '**/*.component.ts'

# Peticiones que se pisan: subscribe sobre http sin switchMap
rg -n 'http\.(get|post|put|delete)\(' -B 3 src --glob '**/*.ts'
rg -c 'switchMap|exhaustMap|concatMap' src --glob '**/*.ts'

# Bucles anidados (heurística de O(n^2))
rg -n 'for\s*\(|\.forEach\(|\.map\(|\.filter\(' -A 3 src --glob '**/*.ts' \
  | rg 'for\s*\(|\.forEach\(|\.map\(|\.filter\('

# N+1: petición dentro de un map/forEach
rg -n '\.(map|forEach)\(' -A 5 src --glob '**/*.ts' | rg 'http\.'

Dos http.get de búsqueda disparados por teclado sin switchMap producen una race condition: si la respuesta de “ang” llega después de la de “angular”, el usuario ve resultados viejos. Un users.map(u => this.getOrders(u.id)) que dispara una petición por usuario es un N+1: 1 lista + N detalles, cuando el backend podría resolverlo en 1 llamada. Un .filter() dentro de un .map() sobre la misma colección es O(n²) en el cliente.

Dimensión 6 — Seguridad

Referencia: Seguridad

Qué buscar: uso de bypassSecurityTrust* (desactiva la sanitización de Angular), [innerHTML] con datos de usuario, secretos en el bundle (API keys, tokens en el código del cliente), autorización sólo en el cliente (rutas protegidas por un guard sin verificación en el backend).

# bypassSecurityTrust: cada uso es un punto de XSS potencial
rg -n 'bypassSecurityTrust(Html|Style|Script|Url|ResourceUrl)' src

# innerHTML (revisar de dónde viene el dato)
rg -n '\[innerHTML\]' src --glob '**/*.html'
rg -n 'innerHTML' src --glob '**/*.ts'

# Secretos en el bundle del cliente
rg -in 'api[_-]?key|secret|token|password|Authorization.*Bearer\s+[A-Za-z0-9]' src \
  --glob '**/*.ts' --glob '**/environments/**'
rg -n 'AKIA[0-9A-Z]{16}|sk_live_|ghp_[A-Za-z0-9]{36}' src

# Guards de ruta (¿única capa de autorización?)
rg -n 'canActivate|CanActivateFn|canMatch' src --glob '**/*.ts'

Todo lo que esté en src/environments/ o en el código del cliente viaja al navegador: una API key ahí es pública. bypassSecurityTrustHtml(comentarioDelUsuario) reintroduce exactamente el XSS que el sanitizador de Angular previene por defecto. Un canActivate que oculta una ruta es UX, no seguridad: si el endpoint del backend no valida el permiso, cualquiera con la URL de la API accede igual. El agente debe marcar como CRÍTICO cualquier bypassSecurityTrust* o secreto que combine con datos de usuario o entorno de producción.

Dimensión 7 — Testing

Referencia: Testing

Qué buscar: cobertura baja o inexistente, tests frágiles (acoplados a la implementación: buscan por selectores CSS internos, esperan tiempos fijos con tick(500), mockean todo hasta que el test no prueba nada), ausencia de tests sobre signals y estado derivado.

# Relación código vs tests
rg -c '' -g '**/*.ts' --glob '!**/*.spec.ts' src | wc -l
rg -l '' src --glob '**/*.spec.ts' | wc -l

# Tests frágiles: waits fijos, selectores de implementación
rg -n 'tick\([0-9]{2,}\)|setTimeout\(|fixture.detectChanges\(\)\s*$' src --glob '**/*.spec.ts'
rg -n "By.css\('\.[a-z]" src --glob '**/*.spec.ts'   # selección por clase interna

# ¿Hay tests de signals/computed?
rg -n 'computed\(|signal\(' src --glob '**/*.spec.ts'

Un test que hace tick(500) para esperar un debounce es frágil: si el debounce cambia a 600 ms, el test rompe sin que la funcionalidad esté rota. Un test que selecciona .btn-primary se rompe con un cambio de CSS irrelevante. La señal de salud es cobertura sobre comportamiento (usando harnesses del CDK y getByRole), no sobre estructura.

Diagrama del flujo de auditoría

flowchart TD
    R[Fase 0 · Reconocimiento<br/>versión, standalone, zoneless, Nx, scripts]
    R --> D1[1 · Arquitectura<br/>caps 2, 9]
    R --> D2[2 · Componentes<br/>cap 3]
    R --> D3[3 · Reactividad<br/>caps 4, 5]
    R --> D4[4 · Rendimiento<br/>caps 6, 7]
    R --> D5[5 · Datos/HTTP<br/>cap 10]
    R --> D6[6 · Seguridad<br/>cap 11]
    R --> D7[7 · Testing<br/>cap 12]
    D1 --> H[Hallazgos con<br/>archivo:línea + impacto]
    D2 --> H
    D3 --> H
    D4 --> H
    D5 --> H
    D6 --> H
    D7 --> H
    H --> P[Informe priorizado<br/>CRÍTICO → BAJO]
    P -.aprobación.-> Rem[Remediación]

Heurísticas de detección (tabla rápida)

Esta tabla resume los smells y su detección. Sirve también para revisar críticamente el informe del agente:

DimensiónSmellDetecciónRef.
ArquitecturaBarrel filerg "export \* from" --glob '**/index.ts'2
ArquitecturaNgModule de apprg '@NgModule' src2, 9
ComponentesFalta OnPush@Component count vs OnPush count3
ComponentesAPI legacy`rg ‘@Input(@Output(‘`
ComponentesControl flow viejo`rg ‘*ngIf*ngFor’`
ReactividadLeak de subscriberg '\.subscribe\(' sin takeUntilDestroyed5
Reactividadeffect como computedeffect(() => …set())4
ReactividadBehaviorSubject de másrg 'new BehaviorSubject'4
RendimientoFunción en bindingrg '\{\{\s*\w+\(' en .html6
Rendimiento@for sin trackrg '@for' -A1 sin track6
RendimientoSin @defer/lazyrg '@defer' / loadComponent ausentes7
Rendimiento<img> sin ngSrcrg '<img[^>]*\ssrc='7
Datos/HTTPHTTP en componenterg 'HttpClient' '**/*.component.ts'10
Datos/HTTPRace conditionhttp.get sin switchMap10
Datos/HTTPN+1 / O(n²)petición o filtro dentro de map/forEach10
SeguridadbypassSecurityTrust*rg 'bypassSecurityTrust'11
SeguridadinnerHTML con user datarg '\[innerHTML\]'11
SeguridadSecreto en bundle`rg -i ‘api[_-]?keysecret
TestingTest frágilrg 'tick\([0-9]{2,}\)', By.css('.…')12

Los smells son señales, no veredictos. Un bypassSecurityTrustResourceUrl sobre una URL constante confiable puede ser legítimo; un .subscribe() con async pipe cercano puede estar bien gestionado. El agente debe leer el contexto de cada match antes de emitir severidad, no reportar el grep en crudo.

Briefing para el agente

Copiá todo lo que sigue en este bloque y pegalo a tu agente en la raíz del proyecto.

# MISIÓN: Auditoría de calidad de un proyecto Angular

Eres un auditor senior de Angular (versión 22). Tu misión es determinar la
calidad de ESTA aplicación en siete dimensiones: arquitectura, diseño de
componentes, reactividad, rendimiento, datos/HTTP, seguridad y testing. La
referencia es Angular moderno: standalone, signals, zoneless, nuevo control
flow (@if/@for/@defer), input()/output()/model(), inject(), OnPush.

REGLA DE ORO: NO modifiques ningún archivo. Solo lees, diagnosticas y reportas.
Toda remediación se propone como plan y espera mi aprobación explícita.
Cada hallazgo DEBE citar `archivo:línea` y el fragmento relevante. Sin evidencia,
no es un hallazgo.

## FASE 0 — Reconocimiento
Determina y resume en 5-8 líneas:
- Versión de @angular/core (package.json / ng version), TypeScript, RxJS.
- ¿Standalone o quedan NgModules de app? (rg '@NgModule' src)
- ¿Zoneless (provideZonelessChangeDetection) o zone.js?
- ¿Nx / monorepo? ¿angular-eslint o TSLint?
- Scripts disponibles (build, test, lint, e2e) y si hay budgets de bundle.

## FASE 1..7 — Diagnóstico por dimensión
Para CADA hallazgo usa este formato:
  - **[Dimensión] Hallazgo**: severidad CRÍTICO|ALTO|MEDIO|BAJO
    - Evidencia: `ruta/archivo.ext:línea` (cita el fragmento)
    - Impacto: consecuencia concreta (rendimiento/seguridad/mantenibilidad)
    - Recomendación: qué hacer

1. ARQUITECTURA (caps 2, 9): barrel files (export * from), NgModules de app,
   límites entre features cruzados, constructor injection legacy vs inject().
2. COMPONENTES (cap 3): componentes sin ChangeDetectionStrategy.OnPush,
   componentes-dios (por tamaño), lógica en template, @Input()/@Output()
   legacy, *ngIf/*ngFor en vez de @if/@for.
3. REACTIVIDAD (caps 4, 5): .subscribe() sin takeUntilDestroyed ni async pipe,
   effect() que deriva estado (debería ser computed), BehaviorSubject donde va
   signal/computed, .set()/.update() dentro de effect, subscribe anidado.
4. RENDIMIENTO (caps 6, 7): funciones en bindings del template, @for sin track,
   ausencia de @defer y rutas lazy (loadComponent/loadChildren), <img> sin
   NgOptimizedImage (ngSrc), budgets de bundle no configurados.
5. DATOS/HTTP (cap 10): HttpClient en componentes, race conditions (http sin
   switchMap), N+1 (petición dentro de map/forEach), O(n^2) (bucles/filtros
   anidados sobre la misma colección).
6. SEGURIDAD (cap 11): bypassSecurityTrust*, [innerHTML] con datos de usuario,
   secretos en el bundle (api key/token/secret en src o environments),
   autorización solo en cliente (guards sin validación en backend).
7. TESTING (cap 12): cobertura, tests frágiles (tick con ms fijos, selección
   por clase CSS interna, sobre-mockeo), falta de tests de signals/computed.

Usa ripgrep para localizar candidatos y LEE el contexto antes de dar severidad;
un match no es un hallazgo hasta confirmarlo. Marca N/A lo que no aplique y
justifícalo.

## FASE 8 — Informe
Entrega, en este orden:
1. Tabla resumen: dimensión | hallazgo | severidad | archivo:línea.
2. Score por dimensión (CUMPLE/PARCIAL/NO CUMPLE) y global.
3. Los 3 hallazgos más costosos con su evidencia e impacto.
4. Plan priorizado: CRÍTICO -> ALTO -> MEDIO -> BAJO, cada ítem con checkbox,
   archivo y recomendación en una línea con link al capítulo de referencia.

Espera mi aprobación antes de tocar cualquier archivo.

Formato del informe de auditoría

El resultado del agente debería verse así (ejemplo abreviado). Usá esta plantilla como referencia de lo que tenés que exigir:

## Auditoría Angular — mi-app

**Angular 22 · standalone · zoneless · Nx · angular-eslint**
**Score global: 4 / 7 dimensiones en verde**

| Dimensión | Estado | Peor severidad |
|-----------|--------|----------------|
| Arquitectura | PARCIAL | MEDIO |
| Componentes | NO CUMPLE | ALTO |
| Reactividad | PARCIAL | ALTO |
| Rendimiento | NO CUMPLE | ALTO |
| Datos/HTTP | PARCIAL | ALTO |
| Seguridad | NO CUMPLE | CRÍTICO |
| Testing | PARCIAL | MEDIO |

### Hallazgos más costosos
1. **[Seguridad] CRÍTICO**`src/app/perfil/perfil.component.ts:47`
   `this.sanitizer.bypassSecurityTrustHtml(this.bioDelUsuario)` sobre texto que
   viene del usuario. Impacto: XSS almacenado explotable.
   Recomendación: renderizar como texto o sanitizar sin bypass →
   [cap 11](/tecnologias/angular-buenas-practicas/11-seguridad/).
2. **[Rendimiento] ALTO**`src/app/lista/lista.component.html:12`
   `@for (item of items())` sin `track`. Impacto: recrea 800 nodos del DOM en
   cada cambio de referencia. Recomendación: `track item.id`
   [cap 6](/tecnologias/angular-buenas-practicas/06-change-detection/).
3. **[Componentes] ALTO** — 34 de 41 componentes sin `OnPush`. Impacto: cada
   evento del navegador dispara detección sobre todo el árbol.
   Recomendación: `changeDetection: ChangeDetectionStrategy.OnPush`
   [cap 3](/tecnologias/angular-buenas-practicas/03-componentes-solid/).

### Plan priorizado
#### CRÍTICO
- [ ] Seguridad — `perfil.component.ts:47` — quitar bypass, renderizar como texto (cap 11)
- [ ] Seguridad — `environments/environment.prod.ts:6` — mover API key al backend (cap 11)
#### ALTO
- [ ] Rendimiento — `lista.component.html:12` — agregar `track item.id` (cap 6)
- [ ] Componentes — 34 componentes — activar `OnPush` (cap 3)
- [ ] Reactividad — `busqueda.service.ts:22``switchMap` para evitar race (caps 5, 10)
#### MEDIO
- [ ] Arquitectura — `features/pedidos/index.ts` — eliminar barrel file (cap 2)
- [ ] Reactividad — `carrito.service.ts:9``BehaviorSubject``signal` (cap 4)
#### BAJO
- [ ] Testing — `lista.component.spec.ts:30``tick(500)` frágil → fake async por evento (cap 12)

Automatizar parte de la auditoría en CI

El agente da profundidad y contexto, pero varias de estas dimensiones se prestan a gates automáticos que corren en cada Pull Request, sin esperar una auditoría manual:

La combinación ideal: el CI atrapa las regresiones conocidas commit a commit, y la auditoría con agente descubre lo que ningún linter modela (un effect que debería ser computed, un N+1 escondido, un componente-dios que creció de a poco).

Checklist


Con este protocolo, todo el curso deja de ser teoría y se vuelve un diagnóstico repetible sobre tu código real: cualquier integrante del equipo pega el briefing en su agente y obtiene, en minutos, un informe evidenciado y priorizado del estado del proyecto. El criterio final —qué duele más en tu contexto de negocio— sigue siendo humano; el trabajo pesado de rastrear la evidencia lo hace el agente.

Y con esto llegás al final. Completaste el curso “Angular: Buenas Prácticas”. Recorriste diseño con SOLID, signals y RxJS con criterio, change detection y zoneless, Core Web Vitals, seguridad, testing, el catálogo de patrones y este protocolo de auditoría. Ahora tenés no sólo el cómo, sino el criterio para decidir cuál de las formas de hacer las cosas escala. Felicitaciones.

Volvé cuando quieras al índice del curso para repasar cualquier dimensión.