pumuki 6.3.26 → 6.3.28
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.
- package/README.md +3 -1
- package/bin/pumuki-mcp-enterprise-stdio.js +5 -0
- package/bin/pumuki-mcp-evidence-stdio.js +5 -0
- package/core/gate/conditionMatches.ts +1 -21
- package/core/gate/evaluateGate.js +5 -0
- package/core/gate/evaluateRules.js +5 -0
- package/core/gate/evaluateRules.ts +1 -24
- package/core/gate/scopeMatcher.ts +84 -0
- package/docs/EXECUTION_BOARD.md +749 -376
- package/docs/MCP_SERVERS.md +41 -2
- package/docs/README.md +6 -2
- package/docs/REFRACTOR_PROGRESS.md +374 -6
- package/docs/validation/README.md +11 -1
- package/docs/validation/p9-ruralgo-bug-registry.md +607 -0
- package/docs/validation/p9-ruralgo-fork-validation-tracking.md +904 -0
- package/docs/validation/real-repo-manual-e2e-ruralgo-fork.md +372 -0
- package/integrations/config/skillsCompliance.ts +212 -0
- package/integrations/evidence/integrity.ts +352 -0
- package/integrations/evidence/rulesCoverage.ts +94 -0
- package/integrations/evidence/schema.test.ts +16 -0
- package/integrations/evidence/schema.ts +41 -0
- package/integrations/evidence/writeEvidence.test.ts +68 -0
- package/integrations/evidence/writeEvidence.ts +23 -2
- package/integrations/gate/evaluateAiGate.ts +382 -15
- package/integrations/gate/stagePolicies.ts +70 -15
- package/integrations/gate/waivers.ts +209 -0
- package/integrations/git/findingTraceability.ts +3 -23
- package/integrations/git/index.js +5 -0
- package/integrations/git/runCliCommand.ts +16 -0
- package/integrations/git/runPlatformGate.ts +53 -1
- package/integrations/git/runPlatformGateEvaluation.ts +13 -0
- package/integrations/git/stageRunners.ts +168 -5
- package/integrations/lifecycle/adapter.templates.json +72 -5
- package/integrations/lifecycle/adapter.ts +78 -4
- package/integrations/lifecycle/cli.ts +384 -14
- package/integrations/lifecycle/doctor.ts +534 -0
- package/integrations/lifecycle/hookBlock.ts +2 -1
- package/integrations/lifecycle/index.js +5 -0
- package/integrations/lifecycle/install.ts +115 -3
- package/integrations/lifecycle/openSpecBootstrap.ts +68 -8
- package/integrations/lifecycle/preWriteAutomation.ts +142 -0
- package/integrations/mcp/aiGateCheck.ts +6 -0
- package/integrations/mcp/aiGateReceipt.ts +188 -0
- package/integrations/mcp/enterpriseServer.ts +14 -1
- package/integrations/mcp/enterpriseStdioServer.cli.ts +315 -0
- package/integrations/mcp/evidenceStdioServer.cli.ts +342 -0
- package/integrations/mcp/index.js +5 -0
- package/integrations/sdd/index.js +5 -0
- package/integrations/sdd/index.ts +2 -0
- package/integrations/sdd/policy.ts +191 -2
- package/integrations/sdd/sessionStore.ts +139 -19
- package/integrations/sdd/syncDocs.ts +180 -0
- package/integrations/sdd/types.ts +4 -1
- package/integrations/telemetry/structuredTelemetry.ts +197 -0
- package/package.json +27 -8
- package/scripts/build-p9-validation-manifests.ts +53 -0
- package/scripts/check-p9-ruralgo-baseline-clean.ts +200 -0
- package/scripts/check-p9-ruralgo-baseline-versioned.ts +198 -0
- package/scripts/check-p9-ruralgo-branch-ready.ts +215 -0
- package/scripts/check-p9-ruralgo-install-health.ts +288 -0
- package/scripts/check-p9-ruralgo-runtime-ready.ts +188 -0
- package/scripts/check-package-manifest.ts +49 -0
- package/scripts/check-tracking-single-active.sh +40 -0
- package/scripts/framework-menu-consumer-preflight-lib.ts +31 -0
- package/scripts/framework-menu-consumer-runtime-lib.ts +3 -3
- package/scripts/framework-menu-legacy-audit-lib.ts +35 -7
- package/scripts/framework-menu-matrix-evidence-lib.ts +6 -2
- package/scripts/manage-library.sh +1 -1
- package/scripts/p9-ruralgo-baseline-clean-lib.ts +117 -0
- package/scripts/p9-ruralgo-baseline-versioned-lib.ts +119 -0
- package/scripts/p9-ruralgo-branch-ready-lib.ts +128 -0
- package/scripts/p9-ruralgo-install-health-lib.ts +121 -0
- package/scripts/p9-ruralgo-runtime-ready-lib.ts +149 -0
- package/scripts/p9-validation-manifests-lib.ts +366 -0
- package/scripts/package-manifest-lib.ts +9 -0
- package/skills.lock.json +1 -1
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
# Runbook Manual E2E en Repo Real (ruralgo-fork)
|
|
2
|
+
|
|
3
|
+
Runbook manual para validar Pumuki end-to-end en un repositorio real (no mock), usando un fork/copia controlada de RuralGO dentro de `~/Developer/Projects`.
|
|
4
|
+
|
|
5
|
+
## Objetivo
|
|
6
|
+
|
|
7
|
+
Verificar instalación, gates, lifecycle, comandos loop, servidores MCP y desinstalación limpia en un clon real que ejecutas tú manualmente.
|
|
8
|
+
|
|
9
|
+
## Rutas
|
|
10
|
+
|
|
11
|
+
- Repo real de origen (RuralGO): `/Users/juancarlosmerlosalbarracin/Developer/Projects/R_GO`
|
|
12
|
+
- Fork/copia de validación: `/Users/juancarlosmerlosalbarracin/Developer/Projects/ruralgo-fork`
|
|
13
|
+
|
|
14
|
+
## Espejo mínimo de tracking en el fork (manual)
|
|
15
|
+
|
|
16
|
+
Antes de empezar las pruebas reales, crea/actualiza este archivo en el fork:
|
|
17
|
+
|
|
18
|
+
- `ruralgo-fork/docs/strategy/ruralgo-tracking-hub.md`
|
|
19
|
+
|
|
20
|
+
Plantilla mínima recomendada:
|
|
21
|
+
|
|
22
|
+
```md
|
|
23
|
+
# RuralGO Tracking Hub (P9)
|
|
24
|
+
|
|
25
|
+
- Fuente maestra: `ast-intelligence-hooks/docs/validation/p9-ruralgo-fork-validation-tracking.md`
|
|
26
|
+
- Tarea activa: `P9.F0.T3`
|
|
27
|
+
- Última sincronización: <YYYY-MM-DD HH:mm TZ>
|
|
28
|
+
- Estado:
|
|
29
|
+
- F0: en curso
|
|
30
|
+
- F1..F6: pendientes
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## 0) Preparar fork/copia real en Projects
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
rm -rf /Users/juancarlosmerlosalbarracin/Developer/Projects/ruralgo-fork
|
|
37
|
+
git clone /Users/juancarlosmerlosalbarracin/Developer/Projects/R_GO /Users/juancarlosmerlosalbarracin/Developer/Projects/ruralgo-fork
|
|
38
|
+
cd /Users/juancarlosmerlosalbarracin/Developer/Projects/ruralgo-fork
|
|
39
|
+
git switch develop
|
|
40
|
+
git pull --ff-only origin develop
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## 0.1) P9.F0.T3.ST2 — Preparar rama real #1 (API contacto)
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
cd /Users/juancarlosmerlosalbarracin/Developer/Projects/ruralgo-fork
|
|
47
|
+
git switch develop
|
|
48
|
+
git pull --ff-only origin develop
|
|
49
|
+
git switch -c feature/p9-api-contact-contract
|
|
50
|
+
git status --short --branch
|
|
51
|
+
git rev-parse --abbrev-ref HEAD
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Esperado:
|
|
55
|
+
- rama activa: `feature/p9-api-contact-contract`
|
|
56
|
+
- base: `develop`
|
|
57
|
+
- upstream todavía no configurado (se configura al abrir PR #1)
|
|
58
|
+
|
|
59
|
+
Validación automática de precondiciones (desde este repo Pumuki):
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
cd /Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks
|
|
63
|
+
npm run -s validation:p9:ruralgo-branch-ready -- \
|
|
64
|
+
--repo=/Users/juancarlosmerlosalbarracin/Developer/Projects/ruralgo-fork \
|
|
65
|
+
--expected-branch=feature/p9-api-contact-contract \
|
|
66
|
+
--base-ref=origin/develop \
|
|
67
|
+
--json
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Esperado:
|
|
71
|
+
- `"ready": true`
|
|
72
|
+
- `"issues": []`
|
|
73
|
+
|
|
74
|
+
## 0.2) P9.F0.T3.ST3 — Preparación pendiente rama real #2 (UX contacto)
|
|
75
|
+
|
|
76
|
+
No crearla todavía para evitar mezclar trabajo de PRs. Se preparará al terminar PR #1:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
cd /Users/juancarlosmerlosalbarracin/Developer/Projects/ruralgo-fork
|
|
80
|
+
git switch develop
|
|
81
|
+
git pull --ff-only origin develop
|
|
82
|
+
git switch -c feature/p9-ux-contact-states
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Esperado:
|
|
86
|
+
- rama activa: `feature/p9-ux-contact-states`
|
|
87
|
+
- base: `develop`
|
|
88
|
+
- solo después de cerrar/encaminar PR #1
|
|
89
|
+
|
|
90
|
+
Validación automática de precondiciones (cuando toque abrir PR #2):
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
cd /Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks
|
|
94
|
+
npm run -s validation:p9:ruralgo-branch-ready:ux -- \
|
|
95
|
+
--repo=/Users/juancarlosmerlosalbarracin/Developer/Projects/ruralgo-fork \
|
|
96
|
+
--json
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Esperado:
|
|
100
|
+
- `"ready": true`
|
|
101
|
+
- `"issues": []`
|
|
102
|
+
|
|
103
|
+
## 0.3) P9.F1.T1 — Verificar runtime exigido por RuralGO
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
cd /Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks
|
|
107
|
+
npm run -s validation:p9:ruralgo-runtime-ready -- \
|
|
108
|
+
--repo=/Users/juancarlosmerlosalbarracin/Developer/Projects/ruralgo-fork \
|
|
109
|
+
--json
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Si tu shell no respeta `nvm use` (sigue mostrando `node v25`), ejecuta los comandos con:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
PATH="$HOME/.nvm/versions/node/v20.20.0/bin:$PATH" <comando>
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Esperado:
|
|
119
|
+
- `"required.node": "20.20.0"`
|
|
120
|
+
- `"required.npm": "10.8.2"`
|
|
121
|
+
- `"ready": true`
|
|
122
|
+
- `"issues": []`
|
|
123
|
+
|
|
124
|
+
## 1) Línea base limpia (sin restos de Pumuki)
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
npx --yes --package pumuki@latest pumuki uninstall --purge-artifacts || true
|
|
128
|
+
npm uninstall pumuki --save-exact || true
|
|
129
|
+
rm -rf node_modules package-lock.json .ai_evidence.json artifacts
|
|
130
|
+
git status --short --branch
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Esperado:
|
|
134
|
+
- sin hooks gestionados por Pumuki
|
|
135
|
+
- sin `.ai_evidence.json`
|
|
136
|
+
- sin `artifacts/`
|
|
137
|
+
|
|
138
|
+
Validación automática de baseline limpio:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
cd /Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks
|
|
142
|
+
npm run -s validation:p9:ruralgo-baseline-clean -- \
|
|
143
|
+
--repo=/Users/juancarlosmerlosalbarracin/Developer/Projects/ruralgo-fork \
|
|
144
|
+
--json
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Esperado:
|
|
148
|
+
- `"ready": true`
|
|
149
|
+
- `"issues": []`
|
|
150
|
+
|
|
151
|
+
## 2) Instalar latest + checks de estado
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
npx --yes --package pumuki@latest pumuki install
|
|
155
|
+
npx --yes --package pumuki@latest pumuki status --json
|
|
156
|
+
npx --yes --package pumuki@latest pumuki doctor --json
|
|
157
|
+
ls -la .git/hooks | rg 'pre-commit|pre-push' || true
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Esperado:
|
|
161
|
+
- instalación operativa sin depender de `npm install` local
|
|
162
|
+
- hooks `pre-commit` y `pre-push` presentes
|
|
163
|
+
- `status` y `doctor` devuelven JSON válido
|
|
164
|
+
|
|
165
|
+
Validación automática de salud de instalación (status + hooks + doctor):
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
cd /Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks
|
|
169
|
+
npm run -s validation:p9:ruralgo-install-health -- \
|
|
170
|
+
--repo=/Users/juancarlosmerlosalbarracin/Developer/Projects/ruralgo-fork \
|
|
171
|
+
--json
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Esperado:
|
|
175
|
+
- `"ready": true`
|
|
176
|
+
- `"snapshot.lifecycleInstalled": true`
|
|
177
|
+
- `"snapshot.preCommitManaged": true`
|
|
178
|
+
- `"snapshot.prePushManaged": true`
|
|
179
|
+
- `"snapshot.doctorVerdictPass": true`
|
|
180
|
+
|
|
181
|
+
## 2.1) P9.F1.T4 — Verificar baseline versionado (openspec + ai_evidence)
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
cd /Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks
|
|
185
|
+
npm run -s validation:p9:ruralgo-baseline-versioned -- \
|
|
186
|
+
--repo=/Users/juancarlosmerlosalbarracin/Developer/Projects/ruralgo-fork \
|
|
187
|
+
--json
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Esperado:
|
|
191
|
+
- `"ready": true`
|
|
192
|
+
- `"snapshot.openspecProjectTracked": true`
|
|
193
|
+
- `"snapshot.openspecArchiveGitkeepTracked": true`
|
|
194
|
+
- `"snapshot.openspecSpecsGitkeepTracked": true`
|
|
195
|
+
- `"snapshot.aiEvidenceTracked": true`
|
|
196
|
+
|
|
197
|
+
## 2.2) P9.F2.T1 — RED del contrato API de contacto (sin implementar endpoint)
|
|
198
|
+
|
|
199
|
+
Arranca backend en modo test con entorno dummy para aislar errores de infraestructura:
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
cd /Users/juancarlosmerlosalbarracin/Developer/Projects/ruralgo-fork
|
|
203
|
+
PATH="$HOME/.nvm/versions/node/v20.20.0/bin:$PATH" \
|
|
204
|
+
NODE_ENV=test \
|
|
205
|
+
E2E_MODE=true \
|
|
206
|
+
SUPABASE_URL=http://127.0.0.1 \
|
|
207
|
+
SUPABASE_SERVICE_ROLE_KEY=dummy \
|
|
208
|
+
WEBHOOK_URL=http://127.0.0.1 \
|
|
209
|
+
TEST_ADMIN_EMAIL=admin@local.test \
|
|
210
|
+
TEST_ADMIN_PASSWORD=Admin123! \
|
|
211
|
+
TEST_SEEDED_EMAIL=seeded@local.test \
|
|
212
|
+
TEST_SEEDED_PASSWORD=Seeded123! \
|
|
213
|
+
TEST_REGULAR_EMAIL=user@local.test \
|
|
214
|
+
TEST_REGULAR_PASSWORD=User1234! \
|
|
215
|
+
E2E_ORDERS_TEST_EMAIL=e2e@local.test \
|
|
216
|
+
E2E_ORDERS_TEST_PASSWORD=Orders123! \
|
|
217
|
+
npm run -w apps/backend dev
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
En otra terminal, ejecutar probes RED:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
curl -s -i -X POST http://127.0.0.1:3000/api/contact-form \
|
|
224
|
+
-H 'Content-Type: application/json' \
|
|
225
|
+
-d '{"name":"Ana","email":"ana@example.com","message":"Hola"}'
|
|
226
|
+
|
|
227
|
+
curl -s -i -X POST http://127.0.0.1:3000/api/contact-form \
|
|
228
|
+
-H 'Content-Type: application/json' \
|
|
229
|
+
-d '{"name":"","email":"bad","message":""}'
|
|
230
|
+
|
|
231
|
+
curl -s -i -X POST http://127.0.0.1:3000/api/contact-form \
|
|
232
|
+
-H 'Content-Type: application/json' \
|
|
233
|
+
-H 'X-Force-External-Fail: 1' \
|
|
234
|
+
-d '{"name":"Ana","email":"ana@example.com","message":"Hola"}'
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Esperado en RED actual:
|
|
238
|
+
- respuestas `404 Cannot POST /api/contact-form` en los 3 casos (contrato aún no implementado).
|
|
239
|
+
|
|
240
|
+
Esperado tras completar GREEN (`P9.F2.T2`):
|
|
241
|
+
- caso válido => `200` con body `{"status":"sent"}`
|
|
242
|
+
- caso inválido => `400` con errores de validación
|
|
243
|
+
- caso `X-Force-External-Fail: 1` => `502` con mensaje saneado
|
|
244
|
+
|
|
245
|
+
Opcional (solo si el repo consumidor no bloquea por engines):
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
npm install --save-exact pumuki@latest
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## 3) Comportamiento del gate: bloquea y luego pasa
|
|
252
|
+
|
|
253
|
+
Crear una violación intencional:
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
cat > pumuki_e2e_violation.ts <<'TS'
|
|
257
|
+
console.log('violacion intencional');
|
|
258
|
+
TS
|
|
259
|
+
git add pumuki_e2e_violation.ts
|
|
260
|
+
npx --yes --package pumuki@latest pumuki-pre-commit; echo "pre-commit exit=$?"
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Corregir y volver a comprobar:
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
cat > pumuki_e2e_violation.ts <<'TS'
|
|
267
|
+
export const pumukiE2e = (): string => 'ok';
|
|
268
|
+
TS
|
|
269
|
+
git add pumuki_e2e_violation.ts
|
|
270
|
+
npx --yes --package pumuki@latest pumuki-pre-commit; echo "pre-commit-fixed exit=$?"
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Esperado:
|
|
274
|
+
- la primera ejecución bloquea
|
|
275
|
+
- la segunda ejecución pasa
|
|
276
|
+
|
|
277
|
+
## 4) Pre-push y gate CI local
|
|
278
|
+
|
|
279
|
+
```bash
|
|
280
|
+
git branch -f upstream-e2e HEAD
|
|
281
|
+
git branch --set-upstream-to=upstream-e2e feature/p9-api-contact-contract
|
|
282
|
+
npx --yes --package pumuki@latest pumuki-pre-push; echo "pre-push exit=$?"
|
|
283
|
+
GITHUB_BASE_REF=upstream-e2e npx --yes --package pumuki@latest pumuki-ci; echo "ci exit=$?"
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Esperado:
|
|
287
|
+
- pre-push y ci validan el scope actual (`staged/diff`) según política
|
|
288
|
+
|
|
289
|
+
## 5) Smoke de comandos loop
|
|
290
|
+
|
|
291
|
+
```bash
|
|
292
|
+
SID=$(npx --yes --package pumuki@latest pumuki loop run --objective="manual-e2e" --max-attempts=1 --json | jq -r '.session.id // .session_id')
|
|
293
|
+
echo "SID=$SID"
|
|
294
|
+
npx --yes --package pumuki@latest pumuki loop status --session="$SID" --json
|
|
295
|
+
npx --yes --package pumuki@latest pumuki loop list --json
|
|
296
|
+
npx --yes --package pumuki@latest pumuki loop export --session="$SID" --json
|
|
297
|
+
npx --yes --package pumuki@latest pumuki loop stop --session="$SID" --json
|
|
298
|
+
npx --yes --package pumuki@latest pumuki loop resume --session="$SID" --json || true
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Esperado:
|
|
302
|
+
- el ciclo de vida de la sesión loop responde con JSON válido
|
|
303
|
+
|
|
304
|
+
## 6) Smoke de servidores MCP (manual y visible)
|
|
305
|
+
|
|
306
|
+
Terminal A:
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
cd /Users/juancarlosmerlosalbarracin/Developer/Projects/ruralgo-fork
|
|
310
|
+
PUMUKI_EVIDENCE_PORT=7441 npx --yes --package pumuki@latest pumuki-mcp-evidence
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
Terminal B:
|
|
314
|
+
|
|
315
|
+
```bash
|
|
316
|
+
curl -s http://127.0.0.1:7441/health
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
Terminal C:
|
|
320
|
+
|
|
321
|
+
```bash
|
|
322
|
+
cd /Users/juancarlosmerlosalbarracin/Developer/Projects/ruralgo-fork
|
|
323
|
+
PUMUKI_ENTERPRISE_MCP_PORT=7491 npx --yes --package pumuki@latest pumuki-mcp-enterprise
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
Terminal D:
|
|
327
|
+
|
|
328
|
+
```bash
|
|
329
|
+
curl -s http://127.0.0.1:7491/health
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
Esperado:
|
|
333
|
+
- ambos endpoints de health devuelven `status=ok`
|
|
334
|
+
|
|
335
|
+
## 7) Desinstalación limpia (estado final)
|
|
336
|
+
|
|
337
|
+
```bash
|
|
338
|
+
npx --yes --package pumuki@latest pumuki uninstall --purge-artifacts
|
|
339
|
+
npm uninstall pumuki --save-exact || true
|
|
340
|
+
rm -rf node_modules package-lock.json .ai_evidence.json artifacts
|
|
341
|
+
ls -la .git/hooks | rg 'pre-commit|pre-push' || true
|
|
342
|
+
git status --short --branch
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
Esperado:
|
|
346
|
+
- sin hooks gestionados por Pumuki
|
|
347
|
+
- sin artefactos de Pumuki
|
|
348
|
+
- el repo queda controlado y limpio en `ruralgo-fork`
|
|
349
|
+
|
|
350
|
+
## 8) Cierre espejo P9 (F6.T4.ST2)
|
|
351
|
+
|
|
352
|
+
Aplica el cierre final en el espejo del consumidor para desbloquear `P9.F6.T4`:
|
|
353
|
+
|
|
354
|
+
```bash
|
|
355
|
+
cd /Users/juancarlosmerlosalbarracin/Developer/Projects/ruralgo-fork
|
|
356
|
+
mkdir -p docs/strategy
|
|
357
|
+
cat > docs/strategy/ruralgo-tracking-hub.md <<'MD'
|
|
358
|
+
# RuralGO Tracking Hub (P9)
|
|
359
|
+
|
|
360
|
+
- Fuente maestra: `/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/docs/validation/p9-ruralgo-fork-validation-tracking.md`
|
|
361
|
+
- Estado maestro: `P9.F6.T4.ST1=✅`, `P9.F6.T4.ST2=✅`
|
|
362
|
+
- Veredicto final P9: `GO`
|
|
363
|
+
- Cierre: `P9.T2 => ✅`
|
|
364
|
+
- Última sincronización: $(date '+%Y-%m-%d %H:%M:%S %Z')
|
|
365
|
+
MD
|
|
366
|
+
|
|
367
|
+
git status --short --branch docs/strategy/ruralgo-tracking-hub.md
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
Esperado:
|
|
371
|
+
- `docs/strategy/ruralgo-tracking-hub.md` presente y actualizado.
|
|
372
|
+
- cierre explícito del espejo con `P9.T2 => ✅` y veredicto `GO`.
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import type { RuleDefinition } from '../../core/rules/RuleDefinition';
|
|
2
|
+
import type { SkillsRuleSetLoadResult } from './skillsRuleSet';
|
|
3
|
+
|
|
4
|
+
export type SkillsCompliancePlatform = Extract<
|
|
5
|
+
NonNullable<RuleDefinition['platform']>,
|
|
6
|
+
'ios' | 'android' | 'backend' | 'frontend'
|
|
7
|
+
>;
|
|
8
|
+
|
|
9
|
+
export type SkillsComplianceFileEntry = {
|
|
10
|
+
file_path: string;
|
|
11
|
+
platform: SkillsCompliancePlatform;
|
|
12
|
+
required_rule_ids: string[];
|
|
13
|
+
applied_rule_ids: string[];
|
|
14
|
+
evidence_rule_ids: string[];
|
|
15
|
+
missing_rule_ids: string[];
|
|
16
|
+
status: 'OK' | 'INCOMPLETE';
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type SkillsComplianceSnapshot = {
|
|
20
|
+
required_rule_ids: string[];
|
|
21
|
+
applied_rule_ids: string[];
|
|
22
|
+
evidence_rule_ids: string[];
|
|
23
|
+
missing_rule_ids: string[];
|
|
24
|
+
counts: {
|
|
25
|
+
files_in_scope: number;
|
|
26
|
+
files_with_missing: number;
|
|
27
|
+
required: number;
|
|
28
|
+
applied: number;
|
|
29
|
+
evidence: number;
|
|
30
|
+
missing: number;
|
|
31
|
+
};
|
|
32
|
+
by_file: SkillsComplianceFileEntry[];
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const isTypeScriptOrJavaScript = (path: string): boolean => {
|
|
36
|
+
const normalized = path.toLowerCase();
|
|
37
|
+
return (
|
|
38
|
+
normalized.endsWith('.ts') ||
|
|
39
|
+
normalized.endsWith('.js') ||
|
|
40
|
+
normalized.endsWith('.mts') ||
|
|
41
|
+
normalized.endsWith('.cts') ||
|
|
42
|
+
normalized.endsWith('.mjs') ||
|
|
43
|
+
normalized.endsWith('.cjs')
|
|
44
|
+
);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const isReactPath = (path: string): boolean => {
|
|
48
|
+
const normalized = path.toLowerCase();
|
|
49
|
+
return normalized.endsWith('.tsx') || normalized.endsWith('.jsx');
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const normalizePath = (path: string): string => {
|
|
53
|
+
return path.replace(/\\/g, '/').replace(/^\.\//, '').trim();
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const inferPlatformFromPath = (
|
|
57
|
+
path: string
|
|
58
|
+
): SkillsCompliancePlatform | undefined => {
|
|
59
|
+
const normalized = normalizePath(path).toLowerCase();
|
|
60
|
+
|
|
61
|
+
if (normalized.endsWith('.swift')) {
|
|
62
|
+
return 'ios';
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (normalized.endsWith('.kt') || normalized.endsWith('.kts')) {
|
|
66
|
+
return 'android';
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (isReactPath(normalized)) {
|
|
70
|
+
return 'frontend';
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (!isTypeScriptOrJavaScript(normalized)) {
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (
|
|
78
|
+
normalized.startsWith('apps/frontend/') ||
|
|
79
|
+
normalized.startsWith('apps/web/') ||
|
|
80
|
+
/(^|\/)(frontend|web|client)(\/|$)/.test(normalized)
|
|
81
|
+
) {
|
|
82
|
+
return 'frontend';
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (
|
|
86
|
+
normalized.startsWith('apps/backend/') ||
|
|
87
|
+
/(^|\/)(backend|server|api)(\/|$)/.test(normalized)
|
|
88
|
+
) {
|
|
89
|
+
return 'backend';
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return undefined;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const toUniqueSorted = (values: ReadonlyArray<string>): string[] => {
|
|
96
|
+
return Array.from(
|
|
97
|
+
new Set(values.map((value) => value.trim()).filter((value) => value.length > 0))
|
|
98
|
+
).sort((left, right) => left.localeCompare(right));
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const intersectRuleIds = (
|
|
102
|
+
ruleIds: ReadonlyArray<string>,
|
|
103
|
+
selectedRuleIds: ReadonlySet<string>
|
|
104
|
+
): string[] => {
|
|
105
|
+
return toUniqueSorted(ruleIds.filter((ruleId) => selectedRuleIds.has(ruleId)));
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const subtractRuleIds = (
|
|
109
|
+
allRuleIds: ReadonlyArray<string>,
|
|
110
|
+
excludedRuleIds: ReadonlySet<string>
|
|
111
|
+
): string[] => {
|
|
112
|
+
return toUniqueSorted(allRuleIds.filter((ruleId) => !excludedRuleIds.has(ruleId)));
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const platformOrder: ReadonlyArray<SkillsCompliancePlatform> = [
|
|
116
|
+
'ios',
|
|
117
|
+
'android',
|
|
118
|
+
'backend',
|
|
119
|
+
'frontend',
|
|
120
|
+
];
|
|
121
|
+
|
|
122
|
+
const isSupportedPlatform = (
|
|
123
|
+
platform: RuleDefinition['platform']
|
|
124
|
+
): platform is SkillsCompliancePlatform => {
|
|
125
|
+
return platform !== undefined && platformOrder.includes(platform as SkillsCompliancePlatform);
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
export const evaluateSkillsCompliance = (params: {
|
|
129
|
+
skillsRuleSet: SkillsRuleSetLoadResult;
|
|
130
|
+
observedFilePaths: ReadonlyArray<string>;
|
|
131
|
+
activeRuleIds: ReadonlyArray<string>;
|
|
132
|
+
evaluatedRuleIds: ReadonlyArray<string>;
|
|
133
|
+
matchedRuleIds: ReadonlyArray<string>;
|
|
134
|
+
}): SkillsComplianceSnapshot | undefined => {
|
|
135
|
+
const activeRuleIdsSet = new Set(params.activeRuleIds);
|
|
136
|
+
const evaluatedRuleIdsSet = new Set(params.evaluatedRuleIds);
|
|
137
|
+
const matchedRuleIdsSet = new Set(params.matchedRuleIds);
|
|
138
|
+
|
|
139
|
+
const requiredByPlatform = new Map<SkillsCompliancePlatform, string[]>();
|
|
140
|
+
for (const rule of params.skillsRuleSet.rules) {
|
|
141
|
+
if (!isSupportedPlatform(rule.platform)) {
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
if (!activeRuleIdsSet.has(rule.id)) {
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
const current = requiredByPlatform.get(rule.platform) ?? [];
|
|
148
|
+
current.push(rule.id);
|
|
149
|
+
requiredByPlatform.set(rule.platform, current);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (requiredByPlatform.size === 0) {
|
|
153
|
+
return undefined;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const normalizedObservedFilePaths = toUniqueSorted(
|
|
157
|
+
params.observedFilePaths.map((path) => normalizePath(path))
|
|
158
|
+
);
|
|
159
|
+
const byFile: SkillsComplianceFileEntry[] = [];
|
|
160
|
+
|
|
161
|
+
for (const filePath of normalizedObservedFilePaths) {
|
|
162
|
+
const platform = inferPlatformFromPath(filePath);
|
|
163
|
+
if (!platform) {
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const requiredRuleIds = toUniqueSorted(requiredByPlatform.get(platform) ?? []);
|
|
168
|
+
if (requiredRuleIds.length === 0) {
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const appliedRuleIds = intersectRuleIds(requiredRuleIds, evaluatedRuleIdsSet);
|
|
173
|
+
const evidenceRuleIds = intersectRuleIds(requiredRuleIds, matchedRuleIdsSet);
|
|
174
|
+
const appliedRuleIdsSet = new Set(appliedRuleIds);
|
|
175
|
+
const missingRuleIds = subtractRuleIds(requiredRuleIds, appliedRuleIdsSet);
|
|
176
|
+
|
|
177
|
+
byFile.push({
|
|
178
|
+
file_path: filePath,
|
|
179
|
+
platform,
|
|
180
|
+
required_rule_ids: requiredRuleIds,
|
|
181
|
+
applied_rule_ids: appliedRuleIds,
|
|
182
|
+
evidence_rule_ids: evidenceRuleIds,
|
|
183
|
+
missing_rule_ids: missingRuleIds,
|
|
184
|
+
status: missingRuleIds.length > 0 ? 'INCOMPLETE' : 'OK',
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (byFile.length === 0) {
|
|
189
|
+
return undefined;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const requiredRuleIds = toUniqueSorted(byFile.flatMap((item) => item.required_rule_ids));
|
|
193
|
+
const appliedRuleIds = toUniqueSorted(byFile.flatMap((item) => item.applied_rule_ids));
|
|
194
|
+
const evidenceRuleIds = toUniqueSorted(byFile.flatMap((item) => item.evidence_rule_ids));
|
|
195
|
+
const missingRuleIds = toUniqueSorted(byFile.flatMap((item) => item.missing_rule_ids));
|
|
196
|
+
|
|
197
|
+
return {
|
|
198
|
+
required_rule_ids: requiredRuleIds,
|
|
199
|
+
applied_rule_ids: appliedRuleIds,
|
|
200
|
+
evidence_rule_ids: evidenceRuleIds,
|
|
201
|
+
missing_rule_ids: missingRuleIds,
|
|
202
|
+
counts: {
|
|
203
|
+
files_in_scope: byFile.length,
|
|
204
|
+
files_with_missing: byFile.filter((item) => item.missing_rule_ids.length > 0).length,
|
|
205
|
+
required: requiredRuleIds.length,
|
|
206
|
+
applied: appliedRuleIds.length,
|
|
207
|
+
evidence: evidenceRuleIds.length,
|
|
208
|
+
missing: missingRuleIds.length,
|
|
209
|
+
},
|
|
210
|
+
by_file: byFile,
|
|
211
|
+
};
|
|
212
|
+
};
|