ozali 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,301 @@
1
+ # Plantillas de documentación
2
+
3
+ Hay **dos** conjuntos de documentación, con propósito y ruta distintos:
4
+
5
+ | Conjunto | Quién lo genera | Cuándo | Ruta |
6
+ |----------|-----------------|--------|------|
7
+ | **Corrida de ozali** | `ozali` | cada corrida de diagnóstico | `.ai/ozali/logs/ozali.log_{{yy-mm-dd}}/` |
8
+ | **Hito de cdk** | `cdk` (`project-documenter`) | cada solicitud/hito del usuario | `.ozali/docs/cdk/<hito>/` |
9
+
10
+ Ambos comparten el mismo **encabezado de identidad**.
11
+
12
+ ---
13
+
14
+ ## A) Documentación de corrida (ozali)
15
+
16
+ Cada corrida de `ozali` produce **3 documentos** en:
17
+
18
+ ```
19
+ .ai/ozali/logs/ozali.log_{{yy-mm-dd}}/
20
+ 01-analisis.md
21
+ 02-plan.md
22
+ 03-mejoras.md
23
+ ```
24
+
25
+ - `{{yy-mm-dd}}` = fecha local de la corrida (ej. `26-06-10`).
26
+ - Si ya existe una carpeta del mismo día, agrega sufijo: `ozali.log_26-06-10-2/`.
27
+ - La **fecha** va en el nombre de la carpeta; la **fecha + hora** va dentro de cada documento.
28
+
29
+ ---
30
+
31
+ ## Encabezado obligatorio (todos los documentos)
32
+
33
+ Va al inicio de cada `.md`. Toma los datos de la **Fase 0** de `ozali` (identidad/git/sesión).
34
+
35
+ ```
36
+ ---
37
+ ozali.log: {{yy-mm-dd}}
38
+ documento: 01-analisis | 02-plan | 03-mejoras
39
+ Autor: <git user.name> <<git user.email>>
40
+ Sesión: <correo de sesión si está disponible>
41
+ Rama: <branch actual>
42
+ Creado: <yyyy-mm-dd HH:MM:SS> (local)
43
+ ---
44
+ ```
45
+
46
+ ---
47
+
48
+ ## 01-analisis.md — Análisis e hitos de importancia
49
+
50
+ ```markdown
51
+ # Análisis — <título corto de la solicitud>
52
+
53
+ ## Contexto
54
+ <qué se pidió y por qué>
55
+
56
+ ## Fuente de verdad usada
57
+ - Variante: AI.md/.ai | IA.md/.ia
58
+ - Discrepancias detectadas vs. estructura real:
59
+ - <lista>
60
+
61
+ ## Hitos de importancia
62
+ 1. <hito> — <por qué importa> — Riesgo: Alto/Medio/Bajo
63
+ 2. ...
64
+
65
+ ## Superficie de impacto
66
+ - Archivos/módulos afectados: <lista>
67
+ - Dependencias: <lista>
68
+ ```
69
+
70
+ ---
71
+
72
+ ## 02-plan.md — Plan ejecutado
73
+
74
+ ```markdown
75
+ # Plan ejecutado — <título corto>
76
+
77
+ ## Decisión
78
+ <enfoque elegido y alternativas descartadas>
79
+
80
+ ## Tareas (con estado final)
81
+ - [x] <tarea 1>
82
+ - [x] <tarea 2>
83
+ - [ ] <pendiente, si aplica>
84
+
85
+ ## Cambios realizados
86
+ - <archivo>: <qué cambió>
87
+
88
+ ## Validación
89
+ - Pruebas ejecutadas: <comando / resultado>
90
+ - Criterios de aceptación: cumplidos/parciales
91
+ ```
92
+
93
+ ---
94
+
95
+ ## 03-mejoras.md — Mejoras posibles (explicativo, breve)
96
+
97
+ ```markdown
98
+ # Mejoras posibles — <título corto>
99
+
100
+ > Solo propuestas explicativas, sin profundizar. Cada una con su grado de relevancia.
101
+
102
+ ## A la skill (ozali/cdk)
103
+ - **[Alta]** <mejora> — <por qué>
104
+ - **[Media]** <mejora> — <por qué>
105
+
106
+ ## Al proyecto
107
+ - **[Alta]** <mejora> — <por qué>
108
+ - **[Baja]** <mejora> — <por qué>
109
+ ```
110
+
111
+ Grados de relevancia: **Alta** (impacto/urgencia clara), **Media** (conviene pronto),
112
+ **Baja** (nice-to-have).
113
+
114
+ ---
115
+
116
+ ## B) Documentación por hito (cdk)
117
+
118
+ La genera `cdk` (subagente `project-documenter`) **una vez por cada solicitud/hito** del
119
+ usuario, en:
120
+
121
+ ```
122
+ .ozali/docs/cdk/<hito>/
123
+ 01-prompt-entrada.md ← al inicio del hito
124
+ 02-plan-aprobado.md ← se congela al aprobar el GATE (inmutable)
125
+ 03-resumen-tecnico.md ← al cierre
126
+ 04-resumen-usuario.md ← al cierre
127
+ 05-bitacora-ejecucion.md ← append-only, DURANTE el ciclo
128
+ 06-uso-tokens.md ← al cierre
129
+ ```
130
+
131
+ - `<hito>` = slug corto y descriptivo de la solicitud (ej. `alta-componente-cobranza`,
132
+ `fix-calculo-prima-poliza`). Si ya existe, agrega sufijo `-2`, `-3`, …
133
+ - Cada documento usa el **mismo encabezado de identidad** de arriba (con `hito:` en lugar de
134
+ `ozali.log:`).
135
+
136
+ ### 01-prompt-entrada.md — Prompt de entrada
137
+
138
+ ```markdown
139
+ # Prompt de entrada — <hito>
140
+
141
+ > Captura textual de la solicitud del usuario, para evaluar el progreso de las solicitudes.
142
+
143
+ ## Prompt (textual)
144
+ <pega aquí, sin editar, el prompt/solicitud exacta del usuario>
145
+
146
+ ## Contexto de la sesión
147
+ - Fecha/Hora de la solicitud: <yyyy-mm-dd HH:MM:SS>
148
+ - Hito asignado: <slug>
149
+ - Modo de ejecución: normal | --auto
150
+ - Solicitudes previas relacionadas: <links a otros hitos, si aplica>
151
+ ```
152
+
153
+ ### 02-plan-aprobado.md — Plan aprobado (snapshot congelado en el GATE)
154
+
155
+ > Se escribe **al aprobarse el GATE, antes de tocar código**, y es **inmutable**: deja
156
+ > constancia de qué se acordó y quién lo aprobó. Cualquier desvío posterior se registra en
157
+ > `05-bitacora-ejecucion.md`, nunca editando este documento. Es el mismo Plan de Acción que
158
+ > vio el usuario, ya con su decisión.
159
+
160
+ ```markdown
161
+ # Plan aprobado — <hito>
162
+
163
+ **Tipo:** feature | bugfix | hotfix | refactor **Tamaño:** S | M | L
164
+ **Workflow:** .ai/workflows/<archivo>.md
165
+ **Modo:** normal | --auto
166
+ **Aprobado por:** <usuario> — <yyyy-mm-dd HH:MM:SS>
167
+
168
+ ## Solicitud del usuario
169
+ <qué pidió, en sus palabras>
170
+
171
+ ## Alcance aprobado
172
+ <lo que SÍ se hará>
173
+
174
+ ## Hallazgos del análisis
175
+ - Reutilización detectada: <clases/archivos existentes que se aprovechan>
176
+ - Riesgos: ⚠ <riesgo> → <mitigación> / 🔴 <bloqueante resuelto y cómo>
177
+
178
+ ## Cambios aprobados (archivo por archivo)
179
+ | Acción | Archivo / Clase | Capa | Detalle |
180
+ | :-- | :-- | :-- | :-- |
181
+ | crear | <X> | <capa> | <detalle> |
182
+ | modificar | <Y> | <capa> | <detalle> |
183
+
184
+ ## Tareas
185
+ - [ ] <tarea 1>
186
+ - [ ] <tarea 2>
187
+
188
+ ## Plan de pruebas
189
+ - Caso feliz: <...>
190
+ - Casos negativos: <...>
191
+
192
+ ## Criterios de aceptación (definition of done)
193
+ - <p. ej. mvn test verde + criterios del owner>
194
+
195
+ ## Fuera de alcance (explícito)
196
+ - <lo que NO se hará en este hito>
197
+ ```
198
+
199
+ ### 03-resumen-tecnico.md — Resumen técnico
200
+
201
+ ```markdown
202
+ # Resumen técnico — <hito>
203
+
204
+ ## Decisiones de implementación
205
+ <enfoque, patrones, por qué>
206
+
207
+ ## Archivos tocados
208
+ - <archivo>: <qué cambió>
209
+
210
+ ## Impacto y riesgos
211
+ - Módulos afectados: <lista>
212
+ - Riesgo en módulos sensibles (core/guard/services/poliza/siniestros/cobranza/models/...): <sí/no, detalle>
213
+
214
+ ## Validación
215
+ - Pruebas: <comando / resultado>
216
+ - walkthrough.md: <ruta / evidencia>
217
+ ```
218
+
219
+ ### 04-resumen-usuario.md — Resumen para el usuario
220
+
221
+ ```markdown
222
+ # Resumen para usuario — <hito>
223
+
224
+ > Lenguaje claro, sin jerga técnica.
225
+
226
+ ## ¿Qué se hizo y para qué sirve?
227
+ <explicación sencilla en 2-3 frases>
228
+
229
+ ## ¿Cómo se usa? (casos de uso)
230
+ 1. **<caso de uso 1>** — <pasos sencillos explicados>
231
+ 2. **<caso de uso 2>** — <pasos sencillos explicados>
232
+
233
+ ## Qué cambia para ti
234
+ <beneficio concreto / qué notará el usuario>
235
+ ```
236
+
237
+ ### 05-bitacora-ejecucion.md — Bitácora de ejecución (append-only)
238
+
239
+ > Registro **cronológico y append-only** de lo que ocurre DESPUÉS de aprobar el plan y
240
+ > DURANTE el ciclo de ejecución: dudas, decisiones, actualizaciones y desvíos respecto al
241
+ > `02-plan-aprobado.md` (que permanece inmutable), preguntas al usuario y sus respuestas.
242
+ > **No se reescribe**: solo se agregan entradas, en orden cronológico. Aquí vive toda la
243
+ > diferencia entre lo planeado y lo realmente ejecutado.
244
+
245
+ ```markdown
246
+ # Bitácora de ejecución — <hito>
247
+
248
+ **Modo de ejecución:** normal | --auto
249
+ **Inicio del ciclo:** <yyyy-mm-dd HH:MM:SS>
250
+
251
+ ## Entradas
252
+
253
+ ### <yyyy-mm-dd HH:MM:SS> — [duda | decisión | actualización | desvío | pregunta]
254
+ - **Qué surgió:** <descripción concreta>
255
+ - **Contexto:** <archivo / tarea / iteración donde apareció>
256
+ - **Resolución:** <qué se decidió y por qué; si fue pregunta al usuario, pega su respuesta textual>
257
+ - **Impacto en el plan:** ninguno | ajuste dentro de alcance | requirió ampliar alcance (se detuvo y preguntó)
258
+
259
+ ### <yyyy-mm-dd HH:MM:SS> — [tipo]
260
+ - ...
261
+
262
+ ## Cierre del ciclo
263
+ - **Fin:** <yyyy-mm-dd HH:MM:SS>
264
+ - **Iteraciones executioner⇄tester:** <n>
265
+ - **Desvíos relevantes vs. plan aprobado:** <resumen / "ninguno">
266
+ ```
267
+
268
+ ### 06-uso-tokens.md — Uso de tokens (al cierre)
269
+
270
+ > Se captura **al terminar el plan**. Las métricas se rellenan en caso de que el proveedor sea
271
+ > **Claude/Anthropic** (fuente: comando `/cost` de Claude Code). Con cualquier otro
272
+ > proveedor verifica si puedes obtener la información y si no puedes, deja la estructura con el **nombre del proveedor** y las métricas en `N/A`
273
+ > (data presente, sin inventar cifras).
274
+
275
+ ```markdown
276
+ # Uso de tokens — <hito>
277
+
278
+ **Proveedor:** Claude (Anthropic) | <otro proveedor>
279
+ **Modelo:** <p. ej. claude-opus-4-8 / N/A>
280
+ **Fuente de la medición:** /cost (Claude Code) | N/A
281
+ **Capturado:** <yyyy-mm-dd HH:MM:SS>
282
+
283
+ ## Métricas de la sesión
284
+ | Métrica | Valor |
285
+ | :-- | :-- |
286
+ | Tokens de entrada (input) | <n / N/A> |
287
+ | Tokens de salida (output) | <n / N/A> |
288
+ | Tokens de caché (lectura) | <n / N/A> |
289
+ | Tokens de caché (escritura) | <n / N/A> |
290
+ | Total de tokens | <n / N/A> |
291
+ | Total de tiempo de sesión | <n / N/A> |
292
+ | Costo estimado | <$ / N/A> |
293
+
294
+ ## Notas
295
+ - <observaciones sobre el consumo del hito; deja vacío o "N/A" si no puedes encontrar información del proveedor>
296
+ ```
297
+
298
+ > **Regla del proveedor:** si el proveedor **no** cuenta con estos datos, **no** intentes
299
+ > derivar ni inventar cifras de otro sistema: solo registra el nombre del proveedor y deja
300
+ > el resto en `N/A`. El objetivo es **mantener la estructura presente** para no perder la
301
+ > trazabilidad del hito.
@@ -0,0 +1,186 @@
1
+ # Convención de memoria híbrida (docs + Engram)
2
+
3
+ Contrato de persistencia que `ozali` cablea dentro del `SKILL.md` de `cdk` (Fase 6). Define
4
+ **qué se guarda, dónde, cuándo y con qué nombre** para que la herramienta **aprenda de lo que el
5
+ equipo va haciendo** sin sobrecargar el repo principal.
6
+
7
+ > **Principio híbrido:** cada artefacto clave vive en **dos** lugares — un **documento legible**
8
+ > (para humanos, auditable, versionable en el repo de conocimiento) **y** un **espejo en Engram**
9
+ > (buscable, recuperable tras compactación, base de la memoria acumulativa del equipo).
10
+
11
+ ---
12
+
13
+ ## 1. Modo de persistencia y degradación
14
+
15
+ `cdk` resuelve el modo **al iniciar cada hito**:
16
+
17
+ | Modo | Lee de | Escribe en | Cuándo |
18
+ |---|---|---|---|
19
+ | **`hybrid`** (default) | Engram primero, docs como fallback | docs **y** Engram | Engram disponible |
20
+ | **`docs`** | docs | docs | Engram **no** instalado/alcanzable |
21
+ | **`none`** | contexto del prompt | nada | el usuario lo pide explícito (efímero) |
22
+
23
+ **Detección de Engram:** el MCP de Engram expone `mem_*`. Si las herramientas no están disponibles
24
+ (o `mem_context` falla), `cdk` **degrada a `docs`** sin romper: escribe los 6 documentos por hito
25
+ igual y anota en la bitácora que el espejo Engram quedó pendiente. `ozali init` (CLI) **verifica/
26
+ guía la instalación de Engram**; mientras no esté, todo funciona en modo `docs`.
27
+
28
+ > Regla: la **ausencia de Engram nunca bloquea** un hito. Solo se pierde la capa buscable, que se
29
+ > rellena al sincronizar cuando Engram esté disponible.
30
+
31
+ **Nombre de proyecto:** usa el que Engram autodetecta del remoto git (normalizado a minúsculas).
32
+ Sin remoto, el nombre de carpeta. Mantén UN nombre por proyecto (evita drift `my-app` vs `My-App`).
33
+
34
+ ---
35
+
36
+ ## 2. Naming determinista
37
+
38
+ Todos los artefactos de `cdk` en Engram siguen:
39
+
40
+ ```
41
+ title: cdk/{hito}/{artifact-type}
42
+ topic_key: cdk/{hito}/{artifact-type}
43
+ type: architecture
44
+ project: {nombre del proyecto detectado}
45
+ scope: project
46
+ capture_prompt: false # artefactos automáticos: NO capturan el prompt del usuario
47
+ ```
48
+
49
+ Para artefactos a nivel de proyecto (no de hito): `cdk/_project/{artifact-type}`.
50
+
51
+ > `capture_prompt: false` es **explícito y obligatorio** para artefactos automáticos cuando el
52
+ > esquema lo soporta (Engram v1.15.3+ lo pone `true` por defecto en saves humanos). Si un esquema
53
+ > viejo no expone el campo, **omítelo** en lugar de fallar. El **prompt del usuario** se captura
54
+ > aparte, una sola vez, con `mem_save_prompt` al inicio del hito (artefacto `01`).
55
+
56
+ ### Mapa doc ↔ Engram
57
+
58
+ | Doc por hito (archivo) | artifact-type (Engram) | Momento | Operación |
59
+ |---|---|---|---|
60
+ | `01-prompt-entrada.md` | — (usa `mem_save_prompt`) | inicio del hito | `mem_save_prompt` |
61
+ | (análisis del analyzer) | `analisis` | tras el análisis | `mem_save` |
62
+ | `02-plan-aprobado.md` | `plan-aprobado` | al aprobar el GATE | `mem_save` **una vez** (inmutable) |
63
+ | `05-bitacora-ejecucion.md` | `bitacora` | checkpoints del ciclo | `mem_update` (upsert) |
64
+ | `03-resumen-tecnico.md` | `resumen-tecnico` | al cierre | `mem_save` |
65
+ | (estado del orchestrator) | `state` | tras cada transición de fase | `mem_update` (upsert) |
66
+ | calibración (Fase 3.5 de ozali) | `_project/testing-capabilities` | en el bootstrap | `mem_save` |
67
+
68
+ > `04-resumen-usuario.md` y `06-uso-tokens.md` se quedan como **docs legibles** (no necesitan
69
+ > espejo buscable); opcional mirror si el equipo lo quiere.
70
+
71
+ ---
72
+
73
+ ## 3. Llamadas inline (lo que cdk debe ejecutar)
74
+
75
+ ### Al INICIAR un hito (contrato de arranque — así aprende del equipo)
76
+
77
+ ```
78
+ # 1) Capturar el prompt real, una vez:
79
+ mem_save_prompt(prompt: "{prompt textual del usuario}", project: "{project}")
80
+
81
+ # 2) Traer contexto previo (búsquedas primero, luego recuperar full):
82
+ mem_search(query: "cdk/{hito}/state", project: "{project}") → ¿hito en curso? (reanudar)
83
+ mem_search(query: "cdk/_project/testing-capabilities", project: "{project}") → strict_tdd + comando verde
84
+ mem_search(query: "cdk/{hito}", project: "{project}") → artefactos relacionados
85
+ mem_context(project: "{project}") → historia reciente de sesión
86
+
87
+ # 3) Recuperar contenido completo de lo relevante (search devuelve preview truncado):
88
+ mem_get_observation(id: {state_id}) → restaurar fase + tareas done/pending
89
+ mem_get_observation(id: {testing_capabilities_id}) → resolver modo TDD
90
+ ```
91
+
92
+ Si `state` existe con tareas pendientes → **reanuda** desde la primera pendiente (no rehagas lo
93
+ hecho). Si `testing-capabilities` da `strict_tdd: true` → ciclo **test-first** (RED→GREEN→REFACTOR).
94
+
95
+ ### Al CONGELAR el plan (GATE aprobado)
96
+
97
+ ```
98
+ mem_save(
99
+ title: "cdk/{hito}/plan-aprobado", topic_key: "cdk/{hito}/plan-aprobado",
100
+ type: "architecture", project: "{project}", capture_prompt: false,
101
+ content: "{markdown completo del plan aprobado}"
102
+ )
103
+ ```
104
+ Inmutable: **no** se vuelve a guardar este topic_key. Los desvíos van a `bitacora`.
105
+
106
+ ### DURANTE el ciclo (bitácora + estado, append-only en archivo, upsert en Engram)
107
+
108
+ ```
109
+ # bitácora: el archivo 05 es append-only (fuente de verdad); el espejo se upserta con el full actual
110
+ mem_update(id: {bitacora_id}, content: "{contenido completo y actualizado de la bitácora}")
111
+ # (si aún no existe: mem_save con topic_key cdk/{hito}/bitacora)
112
+
113
+ # estado recuperable: upsert tras CADA transición de fase
114
+ mem_update(id: {state_id}, content: "{ver §4}")
115
+ # (si aún no existe: mem_save con topic_key cdk/{hito}/state)
116
+ ```
117
+
118
+ ### Al CERRAR el hito
119
+
120
+ ```
121
+ mem_save(title: "cdk/{hito}/resumen-tecnico", topic_key: "cdk/{hito}/resumen-tecnico",
122
+ type: "architecture", project: "{project}", capture_prompt: false,
123
+ content: "{resumen técnico}")
124
+ # y un cierre de sesión (solo el agente top-level, NUNCA un subagente):
125
+ mem_session_summary(project: "{project}", content: "{qué se logró en el hito}")
126
+ ```
127
+
128
+ ---
129
+
130
+ ## 4. Artefacto `state` (recuperable tras compactación)
131
+
132
+ Lo mantiene el `project-orchestrator`. Permite que un hito sobreviva a una compactación de
133
+ contexto o a cerrar/abrir la sesión.
134
+
135
+ ```
136
+ title: cdk/{hito}/state
137
+ topic_key: cdk/{hito}/state
138
+ content: |
139
+ hito: {hito}
140
+ fase: {analisis | plan-aprobado | ejecucion | cierre}
141
+ strict_tdd: {true|false}
142
+ modo: {normal | --auto}
143
+ tareas:
144
+ completadas: [t1, t2]
145
+ pendientes: [t3, t4]
146
+ ultimo_commit: {short SHA}
147
+ last_updated: {ISO-8601}
148
+ ```
149
+
150
+ **Recuperación (2 pasos):** `mem_search("cdk/{hito}/state")` → `mem_get_observation(id)` → parsear
151
+ YAML → restaurar. Si no hay `state`, es un hito nuevo.
152
+
153
+ ---
154
+
155
+ ## 5. Reglas duras
156
+
157
+ - **Persistir ANTES de responder:** cuando un subagente guarda en Engram o escribe docs, la llamada
158
+ va **antes** de su texto final. La última salida del subagente debe ser **texto**, nunca un
159
+ tool-call (si no, el orquestador solo recibe `"Observation saved"` y se pierde el análisis).
160
+ - **Subagentes NO llaman `mem_session_summary`** — reservado para el agente top-level.
161
+ - **Modo `hybrid`: ambas escrituras deben tener éxito.** Si Engram falla a media operación, el doc
162
+ ya quedó (fuente de verdad) y se anota el espejo pendiente en la bitácora; no se aborta el hito.
163
+ - **Lectura `hybrid`: Engram primero, docs como fallback.** Si `mem_search` no devuelve, lee el
164
+ archivo correspondiente en `.ozali/docs/cdk/{hito}/`.
165
+ - **Nunca inventes el prompt:** si no hay contexto de prompt, `mem_save` no fabrica texto.
166
+
167
+ ---
168
+
169
+ ## 6. Sincronización al repo de conocimiento (`ozali sync`)
170
+
171
+ Engram guarda en su **store local**; el histórico (docs + export Engram) se aísla en el repo de
172
+ conocimiento de equipo (ver [team-history](../../docs/team-history.md)). El CLI lo orquesta:
173
+
174
+ ```
175
+ ozali sync # export del proyecto → repo de conocimiento, commit + push
176
+ ozali sync --import # pull del repo de conocimiento → import a Engram local (onboarding)
177
+ ```
178
+
179
+ Internamente (Fase C lo implementa):
180
+ 1. `engram sync` exporta las memorias del proyecto a `.engram/` (chunks + manifest).
181
+ 2. Copia `.engram/` y `.ozali/docs/cdk/` a `ozali-knowledge/{engram,projects/<project>/...}`.
182
+ 3. Commit + push del repo de conocimiento (no del repo principal, que los tiene gitignored).
183
+ 4. `--import` hace lo inverso: clona/pull del repo de conocimiento y `engram sync --import`.
184
+
185
+ > Trazabilidad: cada doc lleva `ultimo_commit`/`Commit:` del repo principal en su encabezado, así
186
+ > el histórico aislado siempre apunta al código exacto que documenta.
@@ -0,0 +1,214 @@
1
+ # Plantilla del harness `verify-structure.mjs`
2
+
3
+ Esqueleto parametrizado del **harness del analista** que `ozali` genera en la Fase 6
4
+ (punto 3) como `.claude/skills/cdk/verify-structure.mjs`. El script es el paso 1
5
+ obligatorio del `project-analyzer`: verifica la estructura REAL del repo contra la
6
+ arquitectura documentada — no confía en la doc.
7
+
8
+ > **Regla:** los valores de los parámetros salen de la **fuente de verdad validada en la
9
+ > Fase 3** (`.ai/context/architecture.md`) y de la inspección real del repo — nunca de
10
+ > supuestos. Cero dependencias, Node 16+.
11
+
12
+ ---
13
+
14
+ ## 1. Parámetros a sustituir
15
+
16
+ | Parámetro | Qué es | Ejemplo backend (Java) | Ejemplo frontend (Angular) |
17
+ |---|---|---|---|
18
+ | `{{PROJECT_NAME}}` | Nombre real del repo | `quattro-auto-mtto` | `biibiic` |
19
+ | `{{ROOT_MARKER}}` | Archivo que identifica la raíz (para subir buscándolo) | `pom.xml` | `angular.json` (o `package.json`) |
20
+ | `{{BASE_PATH}}` | Carpeta base del código, como array de segmentos | `["src","main","java","com","acme"]` | `["src","app"]` |
21
+ | `{{EXT}}` | Extensión de archivos a contar | `.java` | `.ts` |
22
+ | `{{EXPECTED}}` | Capas/carpetas esperadas + rol de una línea (de `architecture.md`) | `controllers`, `services/strategies/impl`, … | `components`, `services`, `guards`, `pages`, … |
23
+ | `{{KEY_CLASSES}}` | Clases/archivos clave que los agentes referencian (sin extensión) | `ApiResponse`, `ErrorCode` | `auth.guard`, `api.service` |
24
+ | `{{CONSISTENCY_CHECKS}}` | Gotchas verificados del repo (ver §3) | context-path, typos de nombres | rutas lazy, config de entornos |
25
+ | `{{TEST_DIR}}` | Carpeta(s) de pruebas a contar | `src/test` | `src` con sufijo `.spec.ts` |
26
+
27
+ ---
28
+
29
+ ## 2. Esqueleto del script
30
+
31
+ ```javascript
32
+ #!/usr/bin/env node
33
+ // CDK — {{PROJECT_NAME}}
34
+ // Harness del analista: verifica la estructura real del proyecto contra la
35
+ // arquitectura documentada (.ai/context/architecture.md), localiza archivos clave
36
+ // y reporta discrepancias + candidatos a reutilizacion.
37
+ //
38
+ // Uso (desde cualquier carpeta dentro del repo):
39
+ // node .claude/skills/cdk/verify-structure.mjs # reporte completo
40
+ // node .claude/skills/cdk/verify-structure.mjs --grep <palabra>
41
+ //
42
+ // Cero dependencias. Node 16+.
43
+
44
+ import fs from "node:fs";
45
+ import path from "node:path";
46
+
47
+ // ---- localizar la raiz del proyecto (sube buscando {{ROOT_MARKER}}) ---------
48
+ function findRoot(start) {
49
+ let dir = start;
50
+ for (let i = 0; i < 30; i++) {
51
+ if (fs.existsSync(path.join(dir, "{{ROOT_MARKER}}"))) return dir;
52
+ const parent = path.dirname(dir);
53
+ if (parent === dir) break;
54
+ dir = parent;
55
+ }
56
+ return start;
57
+ }
58
+
59
+ const ROOT = findRoot(process.cwd());
60
+ const BASE = path.join(ROOT, ...{{BASE_PATH}});
61
+ const EXT = "{{EXT}}";
62
+
63
+ // ---- capas esperadas (lo que promete .ai/context/architecture.md) -----------
64
+ const EXPECTED = [
65
+ // { pkg: "<carpeta relativa a BASE>", role: "<rol de una linea>" },
66
+ {{EXPECTED}}
67
+ ];
68
+
69
+ // ---- archivos clave que referencian los agentes -----------------------------
70
+ const KEY_CLASSES = [
71
+ {{KEY_CLASSES}}
72
+ ];
73
+
74
+ function countFiles(dir) {
75
+ let n = 0;
76
+ if (!fs.existsSync(dir)) return -1;
77
+ for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
78
+ if (e.isDirectory()) {
79
+ const c = countFiles(path.join(dir, e.name));
80
+ if (c > 0) n += c;
81
+ } else if (e.name.endsWith(EXT)) {
82
+ n++;
83
+ }
84
+ }
85
+ return n;
86
+ }
87
+
88
+ function findFile(dir, name) {
89
+ if (!fs.existsSync(dir)) return null;
90
+ for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
91
+ const full = path.join(dir, e.name);
92
+ if (e.isDirectory()) {
93
+ const hit = findFile(full, name);
94
+ if (hit) return hit;
95
+ } else if (e.name === name + EXT) {
96
+ return path.relative(ROOT, full);
97
+ }
98
+ }
99
+ return null;
100
+ }
101
+
102
+ function grepFiles(dir, term, out, limit = 40) {
103
+ if (out.length >= limit || !fs.existsSync(dir)) return;
104
+ for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
105
+ if (out.length >= limit) return;
106
+ const full = path.join(dir, e.name);
107
+ if (e.isDirectory()) {
108
+ grepFiles(full, term, out, limit);
109
+ } else if (e.name.endsWith(EXT) && e.name.toLowerCase().includes(term.toLowerCase())) {
110
+ out.push(path.relative(ROOT, full));
111
+ }
112
+ }
113
+ }
114
+
115
+ // ---------------------------------------------------------------------------
116
+ console.log("============================================================");
117
+ console.log(" CDK · {{PROJECT_NAME}} — Verificacion de estructura");
118
+ console.log("============================================================");
119
+ console.log("Root:", ROOT);
120
+ console.log("Base:", fs.existsSync(BASE) ? path.relative(ROOT, BASE) : "(!) NO ENCONTRADO");
121
+ console.log("");
122
+
123
+ const risks = [];
124
+
125
+ console.log("-- Capas / carpetas ---------------------------------------");
126
+ for (const { pkg, role } of EXPECTED) {
127
+ const dir = path.join(BASE, ...pkg.split("/"));
128
+ const c = countFiles(dir);
129
+ const status = c < 0 ? "FALTA " : String(c).padStart(4) + " ";
130
+ console.log(` [${c < 0 ? "X" : "ok"}] ${pkg.padEnd(26)} ${status}files — ${role}`);
131
+ if (c < 0) risks.push(`Carpeta esperada ausente: ${pkg}`);
132
+ }
133
+ console.log("");
134
+
135
+ console.log("-- Archivos clave -----------------------------------------");
136
+ for (const cls of KEY_CLASSES) {
137
+ const loc = findFile(BASE, cls);
138
+ console.log(` [${loc ? "ok" : "X"}] ${cls.padEnd(28)} ${loc || "(!) NO ENCONTRADO"}`);
139
+ if (!loc) risks.push(`Archivo clave no encontrado: ${cls}`);
140
+ }
141
+ console.log("");
142
+
143
+ console.log("-- Chequeos de consistencia doc<->codigo -----------------");
144
+ // {{CONSISTENCY_CHECKS}}: gotchas VERIFICADOS del repo. Cada uno imprime [i] con el
145
+ // hallazgo y la regla practica. Si dejan de aparecer, actualizar tambien la seccion
146
+ // Gotchas del SKILL.md de cdk y .ai/knowledge/learning-notes.md. Ejemplos:
147
+ // - typos en nombres reales de clases (no "corregirlos" sin refactor aprobado)
148
+ // - prefijos globales (context-path / baseHref) que no van en el codigo
149
+ // - donde vive cada propiedad de configuracion por entorno
150
+ // - conteo de pruebas reales ({{TEST_DIR}}) → advertir si la cobertura es minima
151
+ {{CONSISTENCY_CHECKS}}
152
+ console.log("");
153
+
154
+ // ---- busqueda opcional de reutilizacion (busca antes de crear) --------------
155
+ const gi = process.argv.indexOf("--grep");
156
+ if (gi !== -1 && process.argv[gi + 1]) {
157
+ const term = process.argv[gi + 1];
158
+ console.log(`-- Reutilizacion: archivos que ya mencionan "${term}" ----`);
159
+ const hits = [];
160
+ grepFiles(BASE, term, hits);
161
+ if (hits.length === 0) console.log(" (sin coincidencias por nombre de archivo)");
162
+ for (const h of hits) console.log(" •", h);
163
+ console.log("");
164
+ console.log(` >> Antes de crear codigo nuevo, revisa estos ${hits.length} archivo(s).`);
165
+ console.log("");
166
+ }
167
+
168
+ console.log("============================================================");
169
+ if (risks.length) {
170
+ console.log(` RIESGOS / HALLAZGOS (${risks.length}):`);
171
+ for (const r of risks) console.log(" ⚠ " + r);
172
+ } else {
173
+ console.log(" Estructura coherente con la arquitectura documentada.");
174
+ }
175
+ console.log("============================================================");
176
+ ```
177
+
178
+ ---
179
+
180
+ ## 3. Secciones específicas por tipo de proyecto
181
+
182
+ Además del esqueleto, agrega los chequeos que apliquen:
183
+
184
+ **Backend (Java/Spring)**
185
+ - Sección extra de **dominio** si hay un patrón central (p. ej. en quattro-auto-mtto:
186
+ listar carpetas bajo `services/strategies/impl/` y verificar que cada aseguradora tenga
187
+ su `*Strategy`). Replica la idea para el patrón central del proyecto.
188
+ - Leer `context-path` de `application.properties`/`application.yml` y advertir que no se
189
+ incluye en `@RequestMapping`.
190
+ - Contar `.java` en `src/test`.
191
+
192
+ **Frontend (Angular/React/Vue)**
193
+ - Verificar módulos/rutas declarados vs carpetas reales (lazy loading roto = riesgo).
194
+ - Leer `baseHref`/`deploy` de `angular.json` o equivalente.
195
+ - Contar `*.spec.ts` (o `*.test.tsx`) para reportar cobertura real.
196
+
197
+ **Ambos**
198
+ - El bloque de consistencia **siembra** `learning-notes.md`: todo gotcha que el harness
199
+ detecte en su primera corrida debe quedar registrado ahí y en el SKILL.md de `cdk`.
200
+
201
+ ---
202
+
203
+ ## 4. Validación obligatoria al generarlo
204
+
205
+ Tras escribir el script, `ozali` **debe ejecutarlo** y verificar:
206
+ 1. Corre sin errores con Node 16+ (`node .claude/skills/cdk/verify-structure.mjs`).
207
+ 2. Todas las capas de `EXPECTED` reportan `[ok]` (si algo reporta `FALTA`, o la doc está
208
+ mal o el parámetro está mal — corrígelo antes de cerrar la Fase 6).
209
+ 3. Todos los `KEY_CLASSES` se localizan.
210
+ 4. `--grep <término-conocido>` devuelve hits razonables.
211
+
212
+ La salida real de esta corrida se cita en el `02-plan.md` de la corrida de ozali como
213
+ evidencia. Ejemplo de referencia ya funcionando: el `verify-structure.mjs` de este repo
214
+ (`.claude/skills/cdk/verify-structure.mjs`).