pumuki 6.3.70 → 6.3.72
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/AGENTS.md +269 -0
- package/CHANGELOG.md +666 -0
- package/README.md +32 -0
- package/docs/README.md +7 -2
- package/docs/operations/RELEASE_NOTES.md +15 -0
- package/docs/product/CONFIGURATION.md +12 -0
- package/docs/product/USAGE.md +24 -3
- package/docs/tracking/plan-curso-pumuki-stack-my-architecture.md +111 -0
- package/integrations/evidence/buildEvidence.ts +15 -0
- package/integrations/evidence/operationalHints.ts +110 -0
- package/integrations/evidence/schema.ts +16 -0
- package/integrations/evidence/writeEvidence.ts +3 -0
- package/integrations/gate/remediationCatalog.ts +40 -0
- package/integrations/git/GitService.ts +25 -0
- package/integrations/git/filterFactsByPathPrefixes.ts +61 -0
- package/integrations/git/runPlatformGate.ts +12 -4
- package/integrations/git/runPlatformGateFacts.ts +7 -0
- package/integrations/git/stageRunners.ts +82 -28
- package/integrations/lifecycle/cli.ts +32 -3
- package/integrations/lifecycle/doctor.ts +112 -0
- package/integrations/mcp/aiGateCheck.ts +2 -11
- package/integrations/mcp/preFlightCheck.ts +2 -1
- package/integrations/sdd/openSpecCli.ts +12 -3
- package/package.json +4 -1
- package/scripts/consumer-menu-matrix-baseline-report-lib.ts +13 -38
- package/scripts/framework-menu-consumer-actions-lib.ts +28 -4
- package/scripts/framework-menu-consumer-preflight-hints.ts +5 -2
- package/scripts/framework-menu-consumer-runtime-actions.ts +86 -6
- package/scripts/framework-menu-consumer-runtime-audit.ts +36 -2
- package/scripts/framework-menu-consumer-runtime-evidence-classic.ts +140 -0
- package/scripts/framework-menu-consumer-runtime-lib.ts +2 -0
- package/scripts/framework-menu-consumer-runtime-types.ts +3 -1
- package/scripts/framework-menu-evidence-summary-lib.ts +1 -0
- package/scripts/framework-menu-evidence-summary-read.ts +57 -5
- package/scripts/framework-menu-evidence-summary-severity.ts +3 -1
- package/scripts/framework-menu-evidence-summary-types.ts +7 -0
- package/scripts/framework-menu-gate-lib.ts +9 -0
- package/scripts/framework-menu-layout-data.ts +5 -0
- package/scripts/framework-menu-matrix-baseline-lib.ts +15 -14
- package/scripts/framework-menu-matrix-canary-lib.ts +22 -1
- package/scripts/framework-menu-matrix-evidence-lib.ts +1 -0
- package/scripts/framework-menu-matrix-evidence-types.ts +13 -1
- package/scripts/framework-menu-matrix-runner-lib.ts +35 -0
- package/scripts/framework-menu-system-notifications-macos.ts +4 -0
- package/scripts/framework-menu.ts +3 -0
package/README.md
CHANGED
|
@@ -12,6 +12,12 @@ Pumuki gives engineering teams one deterministic execution model across local de
|
|
|
12
12
|
|
|
13
13
|
`Facts -> Rules -> Gate -> .ai_evidence.json (v2.1)`
|
|
14
14
|
|
|
15
|
+
## Qué NO es Pumuki
|
|
16
|
+
|
|
17
|
+
- **No** es el producto de negocio de tu repositorio (la app, el marketplace, el servicio que entregas a usuarios): es **gobernanza y contrato de entrega** sobre el código.
|
|
18
|
+
- **No** sustituye tests de dominio, contratos de API ni E2E: el gate ayuda a **cumplir políticas y evidencias**; la calidad funcional la define tu equipo con pruebas y criterios de aceptación.
|
|
19
|
+
- **No** garantiza por sí solo “un producto excelente”: sin reglas de equipo, revisión humana y criterios claros, solo obtienes **cumplimiento de lo que configuraste**.
|
|
20
|
+
|
|
15
21
|
## Who This README Is For
|
|
16
22
|
|
|
17
23
|
| Profile | Use this path first |
|
|
@@ -20,6 +26,32 @@ Pumuki gives engineering teams one deterministic execution model across local de
|
|
|
20
26
|
| Framework maintainers (this repo) | [Framework Maintainer Flow](#framework-maintainer-flow-this-repo) |
|
|
21
27
|
| Platform/architecture owners | [Enterprise Operations Baseline](#enterprise-operations-baseline) |
|
|
22
28
|
|
|
29
|
+
## Rutas de adopción
|
|
30
|
+
|
|
31
|
+
Elige un perfil y profundiza en los enlaces; **no** repite aquí reglas largas (skills, GitFlow, políticas) — están en `AGENTS.md` y en la documentación enlazada.
|
|
32
|
+
|
|
33
|
+
| Perfil | Qué instalar / arrancar | Stages habituales | Opcional típico |
|
|
34
|
+
|--------|-------------------------|-------------------|-----------------|
|
|
35
|
+
| **Mínimo** | `npm install --save-exact pumuki` (en repos Git el `postinstall` puede ejecutar `pumuki install` para hooks y lifecycle). | Hooks Git: **PRE_COMMIT**, **PRE_PUSH**; cadena **PRE_WRITE** cuando el hook lo encadena (según versión y config). | Evidencia [`.ai_evidence.json` v2.1](docs/mcp/ai-evidence-v2.1-contract.md); reglas core embebidas. |
|
|
36
|
+
| **Estándar** | Lo anterior + flujo **OpenSpec/SDD** bajo `openspec/` según tu política. | Lo anterior + validación SDD por stage (`pumuki sdd validate --stage=…`). | Sesiones SDD, cambios versionados bajo `openspec/changes/`. |
|
|
37
|
+
| **Enterprise completo** | `pumuki bootstrap --enterprise` (o equivalente documentado) + `skills.lock.json` / reglas custom / [policy-as-code](docs/product/CONFIGURATION.md) donde aplique. | Lo anterior + **CI** (`pumuki-ci`) y comprobaciones de alineación (`doctor`, parity). | [Skills / MCP](docs/mcp/mcp-servers-overview.md), `pumuki doctor --parity`, notificaciones, [hard mode](docs/product/CONFIGURATION.md). |
|
|
38
|
+
|
|
39
|
+
Referencias canónicas (profundizar aquí): [Instalación](docs/product/INSTALLATION.md), [Uso y gates](docs/product/USAGE.md), [Configuración](docs/product/CONFIGURATION.md), [AGENTS.md](AGENTS.md) (contrato agentes/skills/GitFlow en repos que lo adopten), [índice de documentación](docs/README.md).
|
|
40
|
+
|
|
41
|
+
Formación opcional (curso **Pumuki** dentro del hub *Stack My Architecture*): [https://stack-my-architecture-hub.vercel.app/pumuki/](https://stack-my-architecture-hub.vercel.app/pumuki/) · seguimiento de la iniciativa en [docs/tracking/plan-curso-pumuki-stack-my-architecture.md](docs/tracking/plan-curso-pumuki-stack-my-architecture.md).
|
|
42
|
+
|
|
43
|
+
## Comandos esenciales
|
|
44
|
+
|
|
45
|
+
Cinco entradas que cubren el 80 % del día a día en un consumidor; el detalle está en los enlaces.
|
|
46
|
+
|
|
47
|
+
1. **`npx pumuki doctor --json`** — Versión efectiva, drift, lifecycle, parity y avisos (p. ej. `pathExecutionHazard`). Detalle: [API_REFERENCE](docs/product/API_REFERENCE.md), [USAGE](docs/product/USAGE.md).
|
|
48
|
+
2. **`npx pumuki status --json`** — Estado resumido del menú/lifecycle y alineación de versión. Detalle: [USAGE](docs/product/USAGE.md).
|
|
49
|
+
3. **`npx pumuki install`** (o deja que el `postinstall` lo ejecute en Git) — Hooks y lifecycle en el repo. Detalle: [INSTALLATION](docs/product/INSTALLATION.md).
|
|
50
|
+
4. **Gates locales** — `npx pumuki-pre-write`, `npx pumuki-pre-commit` (y `pumuki-pre-push` cuando toque push). Detalle: [USAGE](docs/product/USAGE.md), [Troubleshooting (USAGE)](docs/product/USAGE.md#troubleshooting).
|
|
51
|
+
5. **SDD por stage (enterprise)** — `npx pumuki sdd validate --stage=PRE_COMMIT` (u otro stage). Detalle: [USAGE](docs/product/USAGE.md), [INSTALLATION](docs/product/INSTALLATION.md#troubleshooting) si falla el bootstrap.
|
|
52
|
+
|
|
53
|
+
Si algo bloquea o el mensaje no es claro: [Troubleshooting](#troubleshooting) (más abajo en este README), [USAGE § Troubleshooting](docs/product/USAGE.md#troubleshooting) y [GitHub Issues](https://github.com/SwiftEnProfundidad/ast-intelligence-hooks/issues).
|
|
54
|
+
|
|
23
55
|
## 5-Minute Quick Start (Consumer)
|
|
24
56
|
|
|
25
57
|
Prerequisites:
|
package/docs/README.md
CHANGED
|
@@ -4,6 +4,8 @@ Mapa corto y humano de la documentación oficial de Pumuki.
|
|
|
4
4
|
|
|
5
5
|
## Si buscas algo concreto
|
|
6
6
|
|
|
7
|
+
- Quiero límites del producto, perfil de adopción y comandos mínimos (sin leer todo el README largo):
|
|
8
|
+
- `README.md` (secciones **Qué NO es Pumuki**, **Rutas de adopción**, **Comandos esenciales**)
|
|
7
9
|
- Quiero instalar y arrancar Pumuki en un repo consumidor:
|
|
8
10
|
- `README.md`
|
|
9
11
|
- `docs/product/INSTALLATION.md`
|
|
@@ -35,6 +37,8 @@ Mapa corto y humano de la documentación oficial de Pumuki.
|
|
|
35
37
|
|
|
36
38
|
- Quiero saber en qué estamos ahora:
|
|
37
39
|
- `docs/tracking/plan-activo-de-trabajo.md`
|
|
40
|
+
- Quiero el seguimiento del curso Stack My Architecture (Pumuki), iniciativa formativa aparte del espejo operativo:
|
|
41
|
+
- `docs/tracking/plan-curso-pumuki-stack-my-architecture.md`
|
|
38
42
|
|
|
39
43
|
## Estructura oficial
|
|
40
44
|
|
|
@@ -62,8 +66,9 @@ Mapa corto y humano de la documentación oficial de Pumuki.
|
|
|
62
66
|
|
|
63
67
|
- `docs/tracking/`
|
|
64
68
|
- Seguimiento permitido y solo el imprescindible.
|
|
65
|
-
-
|
|
66
|
-
-
|
|
69
|
+
- Espejo operativo de producto y consumidores: `docs/tracking/plan-activo-de-trabajo.md` (unica fuente de verdad para ese ambito).
|
|
70
|
+
- Curso Pumuki (Stack My Architecture): diseño pedagógico + seguimiento de entrega en `docs/tracking/plan-curso-pumuki-stack-my-architecture.md` (no sustituye al plan activo).
|
|
71
|
+
- Regla hard: solo puede existir una tarea `🚧` en cada documento de seguimiento que lo use.
|
|
67
72
|
|
|
68
73
|
## Fuera de `docs/`
|
|
69
74
|
|
|
@@ -6,6 +6,21 @@ This file keeps only the operational highlights and rollout notes that matter wh
|
|
|
6
6
|
|
|
7
7
|
## 2026-04 (CLI stability and macOS notifications)
|
|
8
8
|
|
|
9
|
+
### 2026-04-11 (v6.3.72)
|
|
10
|
+
|
|
11
|
+
- **Tarball npm**: `package.json` → `files` incluye `AGENTS.md`, `CHANGELOG.md` y `docs/tracking/plan-curso-pumuki-stack-my-architecture.md` para lectura canónica vía npm / jsDelivr sin depender solo del repo Git.
|
|
12
|
+
- **`gate.blocked` (macOS)**: banner de Notification Center **y** modal por defecto (evita cero notificaciones si el modal no llega a mostrarse desde un hook); dedupe opcional: `PUMUKI_MACOS_GATE_BLOCKED_BANNER_DEDUPE=1`.
|
|
13
|
+
- **Menú / matriz consumer**: opciones motor `11–14`, matriz baseline alineada, vista classic opcional, etc. (ver `CHANGELOG.md`).
|
|
14
|
+
- **Rollout**: `pumuki@6.3.72`; `pumuki doctor --json` + repin en consumidores (p. ej. RuralGO).
|
|
15
|
+
|
|
16
|
+
### 2026-04-06 (v6.3.71)
|
|
17
|
+
|
|
18
|
+
- **Evidencia v2.1**: bloque `operational_hints` (`requires_second_pass`, resumen operativo, desglose por severidad de reglas). Alineado con PRE_COMMIT solo-docs + evidencia trackeada (INC-069) cuando no se re-stagea el JSON automáticamente.
|
|
19
|
+
- **Monorepo**: `PUMUKI_GATE_SCOPE_PATH_PREFIXES` acota el primer alcance de hechos por prefijos de ruta.
|
|
20
|
+
- **Paridad CI/local**: `pumuki doctor --parity` y fichero opcional `.pumuki/ci-parity-expected.json` (fallo con exit 1 si hay drift respecto al esperado).
|
|
21
|
+
- **MCP y hooks**: mismas pistas de remediación por código de violación vía catálogo compartido.
|
|
22
|
+
- **Rollout**: `pumuki@6.3.71`; repin en consumidores cuando se publique npm; validar hooks y `doctor --parity` si fijáis expectativas de CI.
|
|
23
|
+
|
|
9
24
|
### 2026-04-06 (v6.3.70)
|
|
10
25
|
|
|
11
26
|
- **Consumidores con pre-commit en pre-push**: con `.ai_evidence.json` **versionado**, `PRE_PUSH` en **ALLOW/WARN** omite persistir en disco para no ensuciar el árbol tras el gate; variable `PUMUKI_PRE_PUSH_ALWAYS_WRITE_TRACKED_EVIDENCE=1` si necesitas el snapshot `PRE_PUSH` en fichero trackeado (puede exigir flujo de commit explícito).
|
|
@@ -317,6 +317,18 @@ Environment variables:
|
|
|
317
317
|
- `PUMUKI_PREWRITE_WORKTREE_WARN_THRESHOLD` (default: `12`)
|
|
318
318
|
- `PUMUKI_PREWRITE_WORKTREE_BLOCK_THRESHOLD` (default: `24`)
|
|
319
319
|
|
|
320
|
+
## Alcance del gate por prefijos (monorepos)
|
|
321
|
+
|
|
322
|
+
- `PUMUKI_GATE_SCOPE_PATH_PREFIXES`: prefijos de ruta separados por **coma** o **punto y coma** (p. ej. `apps/backend,apps/web-app`). Se normalizan barras invertidas a `/`. El **primer** conjunto de hechos del alcance del stage (p. ej. staged o rango de commits) se filtra a rutas bajo esos prefijos. Hechos sin ruta de archivo reconocible (p. ej. algunas dependencias) se conservan para no romper reglas transversales.
|
|
323
|
+
|
|
324
|
+
## Paridad local vs CI (`pumuki doctor`)
|
|
325
|
+
|
|
326
|
+
- Fichero opcional **`.pumuki/ci-parity-expected.json`** (commit en el repo consumer): JSON mínimo con los campos que quieras fijar, p. ej. `pumuki_package_version`, `pre_commit_policy_hash`, `pre_commit_policy_bundle`. Con `pumuki doctor --parity` (y opcionalmente `--json`), Pumuki calcula el perfil actual y, si existe el fichero esperado, rellena `parity_comparison`; cualquier desajuste hace **exit code 1**.
|
|
327
|
+
|
|
328
|
+
## Evidencia en PRE_COMMIT con índice solo documentación
|
|
329
|
+
|
|
330
|
+
- `PUMUKI_PRE_COMMIT_ALWAYS_RESTAGE_TRACKED_EVIDENCE` (`1|true|yes`): fuerza el `git add` automático de `.ai_evidence.json` después de un `PRE_COMMIT` exitoso aunque el índice solo contenga rutas `*.md` / `*.mdx` (además de la propia evidencia). Por defecto, en ese alcance Pumuki **no** ensarta la evidencia en el commit: el snapshot se refresca en disco y puedes decidir si lo incluyes (`git add -- .ai_evidence.json`). Cubre el caso de commits puramente documentales sin mezclar un diff grande de evidencia (p. ej. informes upstream tipo PUMUKI-INC-069).
|
|
331
|
+
|
|
320
332
|
## Evidencia en PRE_PUSH con `.ai_evidence.json` trackeado
|
|
321
333
|
|
|
322
334
|
- `PUMUKI_PRE_PUSH_ALWAYS_WRITE_TRACKED_EVIDENCE` (`1|true|yes`): fuerza la escritura del snapshot en `PRE_PUSH` aunque `.ai_evidence.json` esté versionado. Por defecto (sin esta variable), si el fichero está en el índice de git y el outcome no es `BLOCK`, Pumuki **no** muta el archivo para no romper hooks encadenados (p. ej. `pre-commit` ejecutado desde `pre-push`).
|
package/docs/product/USAGE.md
CHANGED
|
@@ -14,6 +14,11 @@ Production operations baseline (SLA/SLO, incident response and alerting):
|
|
|
14
14
|
Visual walkthrough for menu Option 1 captures:
|
|
15
15
|
- `docs/operations/framework-menu-consumer-walkthrough.md`
|
|
16
16
|
|
|
17
|
+
Stack My Architecture (optional training hub; includes the dedicated Pumuki course):
|
|
18
|
+
|
|
19
|
+
- Public static site: `https://stack-my-architecture-hub.vercel.app/pumuki/`
|
|
20
|
+
- Initiative tracking in this repo: `docs/tracking/plan-curso-pumuki-stack-my-architecture.md`
|
|
21
|
+
|
|
17
22
|
## Prerequisites
|
|
18
23
|
|
|
19
24
|
- Node.js `>=18`
|
|
@@ -72,6 +77,8 @@ Platform activation:
|
|
|
72
77
|
|
|
73
78
|
Pumuki enforces OpenSpec policy/session before allowing normal gate execution.
|
|
74
79
|
|
|
80
|
+
OpenSpec CLI resolution is **repo-local only**: Pumuki runs `openspec` from **`node_modules/.bin`** in the repository under check. A binary named `openspec` elsewhere on your **`PATH`** (global install, another tool) is **not** used. Add **`@fission-ai/openspec`** to the consumer project (for example via `pumuki install` / `bootstrap`) so laptops and CI behave the same; otherwise you may see **`OPENSPEC_MISSING`** even when `openspec --version` succeeds in an interactive shell.
|
|
81
|
+
|
|
75
82
|
Minimal daily flow:
|
|
76
83
|
|
|
77
84
|
```bash
|
|
@@ -123,7 +130,10 @@ Use `A` to switch to `Advanced` mode (full options), and `C` to return to `Consu
|
|
|
123
130
|
Advanced mode options include short inline contextual help.
|
|
124
131
|
Consumer mode is now a minimal read-only shell:
|
|
125
132
|
|
|
126
|
-
- `1/2/3/4` are the canonical
|
|
133
|
+
- `1/2/3/4` are the canonical gate flows with **consumer preflight** before evaluation (labels state scope and PRE_COMMIT vs PRE_PUSH).
|
|
134
|
+
- `11/12/13/14` run the **engine** with **no preflight**: staged only, unstaged only (index→working tree + untracked), full working tree under **PRE_COMMIT**, or **all tracked files** (full repo). They write `.ai_evidence.json` on **PRE_COMMIT** engine runs like other menu audits.
|
|
135
|
+
- After each successful evidence read, the menu prints a **second panel** (“Classic evidence view”) with **ANSI-colored** enterprise/legacy severity counts, optional **platform** rows from `snapshot.platforms`, and a longer ranked violation list. Disable with `PUMUKI_MENU_VINTAGE_REPORT=0`.
|
|
136
|
+
- Options **2** and **4** (PRE_PUSH): if outcome is **PASS** or **WARN**, a short hint explains that a **tracked** `.ai_evidence.json` may **not** be rewritten on disk; use `PUMUKI_PRE_PUSH_ALWAYS_WRITE_TRACKED_EVIDENCE=1` for local debugging.
|
|
127
137
|
- `8` exports the same evidence snapshot in markdown form
|
|
128
138
|
- `5/6/7/9` remain available only as `Legacy Read-Only Diagnostics`
|
|
129
139
|
|
|
@@ -242,7 +252,7 @@ Stage mapping:
|
|
|
242
252
|
If a scope is empty, the menu prints an explicit operational hint (`Scope vacío`), so `PASS` with zero findings is distinguishable from a clean repository scan.
|
|
243
253
|
|
|
244
254
|
System notifications (macOS) can be enabled from advanced menu option `31` (persisted in `.pumuki/system-notifications.json`).
|
|
245
|
-
On non-macOS platforms, the same payloads are written to **stderr** by default (visible in the terminal) because there is no native banner API. Set `PUMUKI_DISABLE_STDERR_NOTIFICATIONS=1` to silence that path (delivery reports `unsupported-platform` on those OSes). On macOS, set `PUMUKI_NOTIFICATION_STDERR_MIRROR=1` to duplicate **any** notification payload to stderr in addition to the system notification. For **`gate.blocked`** specifically, stderr mirroring is **on by default** when the macOS path reports success (so a failed push/commit still prints a `[pumuki]` block in the terminal even if the banner does not appear); disable only that default with `PUMUKI_DISABLE_GATE_BLOCKED_STDERR_MIRROR=1`. The **blocked modal** (Swift floating / AppleScript) with **Desactivar / Silenciar 30 min / Mantener activas** is **on by default** whenever notifications are enabled and `blockedDialogEnabled` is omitted in `.pumuki/system-notifications.json`. Turn it off with `"blockedDialogEnabled": false` or `PUMUKI_MACOS_BLOCKED_DIALOG=0`.
|
|
255
|
+
On non-macOS platforms, the same payloads are written to **stderr** by default (visible in the terminal) because there is no native banner API. Set `PUMUKI_DISABLE_STDERR_NOTIFICATIONS=1` to silence that path (delivery reports `unsupported-platform` on those OSes). On macOS, set `PUMUKI_NOTIFICATION_STDERR_MIRROR=1` to duplicate **any** notification payload to stderr in addition to the system notification. For **`gate.blocked`** specifically, stderr mirroring is **on by default** when the macOS path reports success (so a failed push/commit still prints a `[pumuki]` block in the terminal even if the banner does not appear); disable only that default with `PUMUKI_DISABLE_GATE_BLOCKED_STDERR_MIRROR=1`. The **blocked modal** (Swift floating / AppleScript) with **Desactivar / Silenciar 30 min / Mantener activas** is **on by default** whenever notifications are enabled and `blockedDialogEnabled` is omitted in `.pumuki/system-notifications.json`. Turn it off with `"blockedDialogEnabled": false` or `PUMUKI_MACOS_BLOCKED_DIALOG=0`. **`gate.blocked`** now emits **both** the Notification Center banner (`osascript`) **and** the interactive modal by default, so consumers (e.g. hooks in other repos) still get a visible banner if the modal cannot attach to a GUI session. To restore the previous “modal only” behaviour and suppress the duplicate banner, set `PUMUKI_MACOS_GATE_BLOCKED_BANNER_DEDUPE=1`. If you see **no** notifications at all: confirm `PUMUKI_DISABLE_SYSTEM_NOTIFICATIONS` is unset, delete or fix `.pumuki/system-notifications.json` (absent file defaults to enabled), and ensure the terminal app is allowed to show notifications in **System Settings → Notifications**.
|
|
246
256
|
Blocked notifications now use a native Swift floating modal (bottom-right) by default, with AppleScript fallback.
|
|
247
257
|
Override mode with `PUMUKI_MACOS_BLOCKED_DIALOG_MODE=auto|swift-floating|applescript`.
|
|
248
258
|
Custom skills import is available in advanced menu option `33` (writes `/.pumuki/custom-rules.json`).
|
|
@@ -287,6 +297,8 @@ npx --yes pumuki install --with-mcp --agent=codex
|
|
|
287
297
|
npx --yes pumuki doctor
|
|
288
298
|
# include deterministic adapter/mcp wiring health checks
|
|
289
299
|
npx --yes pumuki doctor --deep --json
|
|
300
|
+
# parity profile vs .pumuki/ci-parity-expected.json (CI/local alignment)
|
|
301
|
+
npx --yes pumuki doctor --parity --json
|
|
290
302
|
|
|
291
303
|
# show lifecycle status
|
|
292
304
|
npx --yes pumuki status
|
|
@@ -563,6 +575,7 @@ npx --yes tsx@4.21.0 scripts/reconcile-consumer-backlog-issues.ts \
|
|
|
563
575
|
|
|
564
576
|
OpenSpec integration behavior:
|
|
565
577
|
- `pumuki bootstrap --enterprise --agent=<name>` orquesta `install + adapter wiring + doctor --deep` en un solo paso.
|
|
578
|
+
- SDD/OpenSpec enforcement invokes the CLI only from **`{repo}/node_modules/.bin/openspec`** (no fallback to a generic `openspec` on `PATH`).
|
|
566
579
|
- `pumuki install` auto-bootstraps OpenSpec (`@fission-ai/openspec`) when missing/incompatible and scaffolds `openspec/` project baseline when absent.
|
|
567
580
|
- `pumuki install --with-mcp` adds adapter/MCP wiring bootstrap and prints MCP health summary on completion.
|
|
568
581
|
- `pumuki update --latest` migrates legacy `openspec` package to `@fission-ai/openspec` before hook reinstall.
|
|
@@ -671,7 +684,9 @@ npm run toolkit:clean-artifacts -- --dry-run
|
|
|
671
684
|
|
|
672
685
|
- Reads staged changes with `git diff --cached --name-status`.
|
|
673
686
|
- Builds facts from staged content.
|
|
687
|
+
- Opcional: `PUMUKI_GATE_SCOPE_PATH_PREFIXES` acota el primer alcance de hechos a prefijos del monorepo (ver `docs/product/CONFIGURATION.md`).
|
|
674
688
|
- Requires valid SDD/OpenSpec status (session + active change + validation).
|
|
689
|
+
- Si `.ai_evidence.json` está **versionado** y el hook refresca el snapshot en disco tras un gate **no** bloqueante, por defecto Pumuki vuelve a hacer `git add` de ese fichero **salvo** que lo único en el índice (ignorando `.ai_evidence.json` / `.AI_EVIDENCE.json`) sean rutas de documentación (`*.md`, `*.mdx`). En ese caso la evidencia se actualiza en disco pero **no** se ensarta en el commit: puedes añadirla manualmente (`git add -- .ai_evidence.json`) o activar el comportamiento anterior con `PUMUKI_PRE_COMMIT_ALWAYS_RESTAGE_TRACKED_EVIDENCE=1` (ver `docs/product/CONFIGURATION.md`). En stderr (si no va en modo silencioso) verás un aviso `[pumuki][evidence-sync]`.
|
|
675
690
|
|
|
676
691
|
### PRE_PUSH
|
|
677
692
|
|
|
@@ -711,11 +726,15 @@ Cada ejecución del gate escribe evidencia determinista en:
|
|
|
711
726
|
|
|
712
727
|
- `.ai_evidence.json`
|
|
713
728
|
|
|
714
|
-
|
|
729
|
+
Excepciones:
|
|
730
|
+
|
|
731
|
+
- En `PRE_PUSH`, si el fichero está trackeado y el outcome no es `BLOCK`, la escritura al path anterior se omite (ver sección PRE_PUSH arriba). La telemetría interna del gate sigue generándose; solo se evita mutar el árbol de trabajo.
|
|
732
|
+
- En `PRE_COMMIT`, si el fichero está trackeado y el índice es solo documentación (`*.md` / `*.mdx`), el fichero puede actualizarse en disco sin auto-`git add` (ver sección PRE_COMMIT arriba).
|
|
715
733
|
|
|
716
734
|
Schema and behavior:
|
|
717
735
|
|
|
718
736
|
- `version: "2.1"` is the source of truth
|
|
737
|
+
- `operational_hints` (opcional pero recomendado en runs recientes): `requires_second_pass` (boolean), `second_pass_reason` (string o null), `human_summary_lines` (1–4 líneas legibles), `rule_execution_breakdown` (conteos evaluated / blocking / warn / info / skipped out-of-scope). Útil para tooling y para entender el resultado sin abrir todo el snapshot.
|
|
719
738
|
- `snapshot` + `ledger`
|
|
720
739
|
- `platforms` and `rulesets` tracking
|
|
721
740
|
- `snapshot.sdd_metrics` tracks stage-level SDD enforcement metadata
|
|
@@ -798,6 +817,8 @@ npx --yes pumuki sdd status
|
|
|
798
817
|
npx --yes pumuki sdd validate --stage=PRE_COMMIT
|
|
799
818
|
```
|
|
800
819
|
|
|
820
|
+
If the gate reports **`OPENSPEC_MISSING`** but `openspec --version` works in the terminal, you are likely using a **global** OpenSpec install. Pumuki does not use that path; install the package in the repo (`npm install`, `pumuki install`, or `pumuki bootstrap`) so `node_modules/.bin/openspec` exists.
|
|
821
|
+
|
|
801
822
|
Open or refresh session if needed:
|
|
802
823
|
|
|
803
824
|
```bash
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Diseño pedagógico y seguimiento — Curso Pumuki (Stack My Architecture)
|
|
2
|
+
|
|
3
|
+
Este documento define **qué debe aprender una persona**, **en qué orden**, **cómo se comprueba** y **qué confusiones hay que romper**. El seguimiento de repos y build va **al final**; no sustituye el diseño.
|
|
4
|
+
|
|
5
|
+
No sustituye el espejo de producto en [`plan-activo-de-trabajo.md`](./plan-activo-de-trabajo.md).
|
|
6
|
+
|
|
7
|
+
## Leyenda operativa
|
|
8
|
+
|
|
9
|
+
- ✅ Entregado en repo curso + coherente con USAGE/INSTALLATION
|
|
10
|
+
- 🚧 Única tarea activa (máx. 1)
|
|
11
|
+
- ⏳ Pendiente
|
|
12
|
+
- ⛔ Bloqueado
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 1. Para quién es y qué problema resuelve
|
|
17
|
+
|
|
18
|
+
**Quién:** desarrollador o tech lead que debe **vivir** con hooks, CI y (a veces) agentes; no auditor de slides.
|
|
19
|
+
|
|
20
|
+
**Problema:** en la práctica mezcla *SDD*, *gate*, *MCP*, *evidencia* y *menú*; cuando algo bloquea no sabe **qué capa** falló ni **qué comando** la inspecciona.
|
|
21
|
+
|
|
22
|
+
**Éxito del curso:** tras cerrarlo, en un repo real puede (1) nombrar el **stage** y el **scope** de un fallo, (2) leer **`.ai_evidence.json`** y relacionarlo con stderr, (3) distinguir **enforcement** (hooks/CI) de **lectura/agente** (MCP), (4) ejecutar el **flujo SDD mínimo** sin confundirlo con “arreglar reglas”, (5) instalar, actualizar o **retirar** Pumuki sin dejar hooks huérfanos.
|
|
23
|
+
|
|
24
|
+
Si eso no se cumple, el curso falla aunque el HTML sea bonito.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 2. Modelo mental único (todo el curso orbita aquí)
|
|
29
|
+
|
|
30
|
+
Una sola frase que el alumno debe poder repetir:
|
|
31
|
+
|
|
32
|
+
**Hechos del diff/código → reglas efectivas → decisión del gate por stage → registro en evidencia v2.1.**
|
|
33
|
+
|
|
34
|
+
Todo lo demás (menú, MCP, notificaciones, `doctor`) es **acceso** a ese mismo pipeline o **comodidad**; no es un segundo producto.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## 3. Confusiones que el material debe desmontar de forma explícita
|
|
39
|
+
|
|
40
|
+
Cada unidad del curso debe tener al menos un párrafo “**no confundas**” o un mini escenario:
|
|
41
|
+
|
|
42
|
+
| Confusión típica | Verdad operativa |
|
|
43
|
+
|------------------|------------------|
|
|
44
|
+
| “Sin MCP no hay Pumuki” | Los **hooks y CI** son el enforcement; MCP es **opcional** para IDE/agente. |
|
|
45
|
+
| “SDD es lo mismo que el gate” | SDD/OpenSpec gobierna el **cambio**; el gate evalúa **código + política + evidencia** en un **scope** concreto. |
|
|
46
|
+
| “`openspec` en el PATH basta” | Pumuki usa OpenSpec **repo-local** (`node_modules/.bin`). |
|
|
47
|
+
| “PRE_COMMIT limpio ⇒ push seguro” | **PRE_PUSH** mira otro **scope** (`upstream..HEAD`). |
|
|
48
|
+
| “El menú es la fuente de verdad” | El menú **orquesta** diagnósticos; la fuente de verdad es **policy + stage + evidencia**. |
|
|
49
|
+
| “Borrar el paquete limpia el repo” | `npm uninstall pumuki` **no** quita hooks/lifecycle; hace falta **`pumuki remove`** / flujo documentado. |
|
|
50
|
+
|
|
51
|
+
Si el Markdown del curso no nombra estas líneas, el plan pedagógico sigue vacío aunque haya tablas de check.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## 4. Secuencia didáctica (orden de primera lectura)
|
|
56
|
+
|
|
57
|
+
El repo del curso incluye la **columna vertebral en prosa** `00-preparacion/03-recorrido-cero-a-cien-pumuki.md` (0→100 % sin saltos) y el **proyecto guiado** `02-modulos/13-proyecto-guiado-de-la-a-la-z.md` (fases A–M con criterios de hecho). Esta tabla U0–U10 sigue siendo el contrato de **outcomes**; esas piezas son el **relato** y el **laboratorio** que los materializan.
|
|
58
|
+
|
|
59
|
+
El **mapa completo** (`00-mapa-completo-del-producto.md`) es **referencia** para quien ya perdió el hilo; la **primera pasada** debe seguir esta secuencia para no cargar conceptos antes de tiempo.
|
|
60
|
+
|
|
61
|
+
| Orden | Unidad | Objetivo observable (el alumno demuestra…) | Actividad mínima en lab | Criterio de dominio |
|
|
62
|
+
|-------|--------|---------------------------------------------|-------------------------|----------------------|
|
|
63
|
+
| U0 | Preparación + versión + lab | Que existe documentación canónica y un repo donde ensayar | Abrir USAGE e INSTALLATION; fijar versión mínima `pumuki` | Explica en una frase dónde miente un “funciona en mi máquina” sin `doctor` |
|
|
64
|
+
| U1 | Contrato + stages + cobertura | Qué pregunta **cada** stage y qué es `unevaluated_rule_ids` | Un `pre-commit` / `pre-push` y leer evidencia | Predice scope antes de ejecutar y acierta al comparar con JSON |
|
|
65
|
+
| U2 | Instalación y primer verde | Postinstall, `bootstrap` vs `install`, `pathExecutionHazard` | `doctor --json` antes/después de un cambio reversible | Usa `alignmentCommand` o workaround sin improvisar |
|
|
66
|
+
| U3 | Ciclo de vida completo | Diferencia `npm uninstall`, `pumuki uninstall`, `pumuki remove`, `update --latest` | Simular retirada en rama de prueba | Lista qué queda en disco tras cada comando |
|
|
67
|
+
| U4 | Evidencia | Dónde se escribe, cuándo **no** se reescribe (PRE_PUSH trackeado), restage PRE_COMMIT | Diff de `.ai_evidence.json` entre stages | Explica un caso “hook modificó archivo” sin pánico |
|
|
68
|
+
| U5 | Menú interactivo | Consumer vs Advanced; 1–4/8/9; matrix; variables UI | Correr `pumuki-framework` y una opción de cada familia | Enlaza opción de menú con **stage** y **scope** equivalentes |
|
|
69
|
+
| U6 | MCP | Evidence vs enterprise; HTTP vs stdio; recibo PRE_WRITE | Levantar o inspeccionar config en `.pumuki/adapter.json` | Explica por qué el gate puede pasar con MCP caído |
|
|
70
|
+
| U7 | SDD/OpenSpec | Flujo diario: `sdd status`, `session`, `validate`; catálogo de códigos | Abrir sesión de cambio y validar un stage | Clasifica un JSON de bloqueo en “falta OpenSpec” vs “falta sesión” |
|
|
71
|
+
| U8 | Notificaciones y watch | macOS vs stderr; `system-notifications.json`; anti-spam de `watch` | Una sesión `watch --once` o documentada | Elige variable correcta para silenciar o espejar |
|
|
72
|
+
| U9 | Perfiles, Governance, monorepo | Cuándo bajar de enterprise; prefijos de scope; parity | (Según perfil del equipo) | Justifica un perfil sin autoboicot |
|
|
73
|
+
| U10 | Cierre | Checklist operativa propia del equipo | Checklist escrita a partir del curso | Puede enseñar el modelo mental §2 a otra persona en 3 minutos |
|
|
74
|
+
|
|
75
|
+
**Regla:** ninguna fila U1–U10 puede considerarse “hecha” solo con un enlace a USAGE; debe existir **narrativa + comando + actividad + criterio** en el Markdown del curso.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## 5. Qué el curso no debe intentar (límites)
|
|
80
|
+
|
|
81
|
+
- Sustituir el curso **SDD** (OpenSpec, Kanban del cambio) ni el **Governance** (AGENTS, cultura): solo **enganchar** Pumuki a ellos.
|
|
82
|
+
- Sustituir tests de producto, revisión humana ni criterios de negocio.
|
|
83
|
+
- Prometer “cero lectura de USAGE”: USAGE sigue siendo norma; el curso debe **enseñar** lo mismo con **menor fricción**, no duplicar mal.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## 6. Estado de entrega en el repo (operativo, subordinado al §4)
|
|
88
|
+
|
|
89
|
+
| Unidad §4 | Estado en `stack-my-architecture-pumuki` |
|
|
90
|
+
|-----------|-------------------------------------------|
|
|
91
|
+
| U0–U2 | ✅ Base + módulo 2; ciclo de vida **completo** en **08** |
|
|
92
|
+
| U3 | ✅ `02-modulos/08-ciclo-de-vida-install-uninstall-actualizacion.md` |
|
|
93
|
+
| U4 | ✅ `02-modulos/09-evidencia-por-stage-y-ai-evidence-json.md` |
|
|
94
|
+
| U5 | ✅ `02-modulos/10-menu-interactivo-matrix-y-preflight.md` |
|
|
95
|
+
| U6 | ✅ `02-modulos/11-mcp-enforcement-vs-lectura-agente.md` |
|
|
96
|
+
| U7 | ✅ Módulo **04** ampliado (§4.6–4.8 + criterio dominio) |
|
|
97
|
+
| U8 | ✅ `02-modulos/12-notificaciones-macos-stderr-y-watch.md` |
|
|
98
|
+
| U9–U10 | ✅ Revisar checklist **07** frente a criterios §4 en próxima iteración |
|
|
99
|
+
|
|
100
|
+
| Task | Estado |
|
|
101
|
+
|------|--------|
|
|
102
|
+
| Implementar U3–U8 en `.md` + `FILE_ORDER` + validación | ✅ |
|
|
103
|
+
| CHANGELOG curso + rebuild HTML + sync hub local | ✅ (incl. CSS lectura **0.3.1**) |
|
|
104
|
+
| Push hub + deploy Vercel (ver curso en prod) | 🚧 |
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## 7. Auditoría técnica (no confundir con evaluación del alumno)
|
|
109
|
+
|
|
110
|
+
- `python3 scripts/validate-course-structure.py` y `check-links.py` en repo curso.
|
|
111
|
+
- Publicación hub según tu script; URL `/pumuki/` 200.
|
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
ConsolidationSuppressedFinding,
|
|
8
8
|
CompatibilityViolation,
|
|
9
9
|
EvidenceLines,
|
|
10
|
+
EvidenceOperationalHints,
|
|
10
11
|
HumanIntentState,
|
|
11
12
|
LedgerEntry,
|
|
12
13
|
PlatformState,
|
|
@@ -23,6 +24,7 @@ import { buildSnapshotPlatformSummaries } from './platformSummary';
|
|
|
23
24
|
import { resolveHumanIntent } from './humanIntent';
|
|
24
25
|
import { normalizeSnapshotEvaluationMetrics } from './evaluationMetrics';
|
|
25
26
|
import { normalizeSnapshotRulesCoverage } from './rulesCoverage';
|
|
27
|
+
import { buildEvidenceOperationalHints } from './operationalHints';
|
|
26
28
|
|
|
27
29
|
type BuildFindingInput = Finding & {
|
|
28
30
|
file?: string;
|
|
@@ -50,6 +52,9 @@ export type BuildEvidenceParams = {
|
|
|
50
52
|
};
|
|
51
53
|
sddMetrics?: SddMetrics;
|
|
52
54
|
repoState?: RepoState;
|
|
55
|
+
operationalHintsExtra?: Partial<
|
|
56
|
+
Pick<EvidenceOperationalHints, 'requires_second_pass' | 'second_pass_reason'>
|
|
57
|
+
>;
|
|
53
58
|
};
|
|
54
59
|
|
|
55
60
|
const normalizeLines = (lines?: EvidenceLines): EvidenceLines | undefined => {
|
|
@@ -766,9 +771,19 @@ export function buildEvidence(params: BuildEvidenceParams): AiEvidenceV2_1 {
|
|
|
766
771
|
previousEvidence: params.previousEvidence,
|
|
767
772
|
});
|
|
768
773
|
|
|
774
|
+
const operational_hints = buildEvidenceOperationalHints({
|
|
775
|
+
stage: params.stage,
|
|
776
|
+
outcome,
|
|
777
|
+
findings: normalizedFindings,
|
|
778
|
+
rulesCoverage: normalizedRulesCoverage,
|
|
779
|
+
evaluationMetrics: normalizedEvaluationMetrics,
|
|
780
|
+
extra: params.operationalHintsExtra,
|
|
781
|
+
});
|
|
782
|
+
|
|
769
783
|
return {
|
|
770
784
|
version: '2.1',
|
|
771
785
|
timestamp: now,
|
|
786
|
+
operational_hints,
|
|
772
787
|
snapshot: {
|
|
773
788
|
stage: params.stage,
|
|
774
789
|
audit_mode: params.auditMode ?? 'gate',
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import type { GateOutcome } from '../../core/gate/GateOutcome';
|
|
2
|
+
import type { GateStage } from '../../core/gate/GateStage';
|
|
3
|
+
import { resolveRemediationHintOrDefault } from '../gate/remediationCatalog';
|
|
4
|
+
import type {
|
|
5
|
+
EvidenceOperationalHints,
|
|
6
|
+
EvidenceRuleExecutionBreakdown,
|
|
7
|
+
SnapshotEvaluationMetrics,
|
|
8
|
+
SnapshotFinding,
|
|
9
|
+
SnapshotRulesCoverage,
|
|
10
|
+
} from './schema';
|
|
11
|
+
|
|
12
|
+
const truncate = (value: string, max: number): string => {
|
|
13
|
+
const t = value.trim();
|
|
14
|
+
if (t.length <= max) {
|
|
15
|
+
return t;
|
|
16
|
+
}
|
|
17
|
+
return `${t.slice(0, max - 1)}…`;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const buildRuleExecutionBreakdown = (params: {
|
|
21
|
+
findings: ReadonlyArray<SnapshotFinding>;
|
|
22
|
+
rulesCoverage?: SnapshotRulesCoverage;
|
|
23
|
+
evaluationMetrics?: SnapshotEvaluationMetrics;
|
|
24
|
+
}): EvidenceRuleExecutionBreakdown => {
|
|
25
|
+
const matched_blocking_count = params.findings.filter(
|
|
26
|
+
(f) =>
|
|
27
|
+
f.severity === 'ERROR' ||
|
|
28
|
+
f.severity === 'CRITICAL' ||
|
|
29
|
+
f.blocking === true
|
|
30
|
+
).length;
|
|
31
|
+
const matched_warn_count = params.findings.filter((f) => f.severity === 'WARN').length;
|
|
32
|
+
const matched_info_count = params.findings.filter((f) => f.severity === 'INFO').length;
|
|
33
|
+
const evaluated_count =
|
|
34
|
+
params.rulesCoverage?.counts?.evaluated ?? params.evaluationMetrics?.evaluated_rule_ids.length ?? 0;
|
|
35
|
+
const active = params.rulesCoverage?.counts?.active ?? 0;
|
|
36
|
+
const evaluatedFromCoverage = params.rulesCoverage?.counts?.evaluated;
|
|
37
|
+
const skipped_out_of_scope_count =
|
|
38
|
+
typeof params.rulesCoverage?.counts?.unevaluated === 'number'
|
|
39
|
+
? params.rulesCoverage.counts.unevaluated
|
|
40
|
+
: active > 0 && typeof evaluatedFromCoverage === 'number'
|
|
41
|
+
? Math.max(0, active - evaluatedFromCoverage)
|
|
42
|
+
: 0;
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
evaluated_count: Math.max(0, evaluated_count),
|
|
46
|
+
matched_blocking_count,
|
|
47
|
+
matched_warn_count,
|
|
48
|
+
matched_info_count,
|
|
49
|
+
skipped_out_of_scope_count: Math.max(0, skipped_out_of_scope_count),
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const buildHumanSummaryLines = (params: {
|
|
54
|
+
stage: GateStage;
|
|
55
|
+
outcome: GateOutcome;
|
|
56
|
+
findings: ReadonlyArray<SnapshotFinding>;
|
|
57
|
+
}): string[] => {
|
|
58
|
+
const lines: string[] = [`${params.stage}: outcome=${params.outcome}.`];
|
|
59
|
+
if (params.outcome === 'BLOCK') {
|
|
60
|
+
const blocking =
|
|
61
|
+
params.findings.find((f) => f.severity === 'CRITICAL' || f.severity === 'ERROR') ??
|
|
62
|
+
params.findings.find((f) => f.blocking === true) ??
|
|
63
|
+
params.findings[0];
|
|
64
|
+
if (blocking) {
|
|
65
|
+
lines.push(`${blocking.code}: ${truncate(blocking.message, 140)}`);
|
|
66
|
+
lines.push(resolveRemediationHintOrDefault(blocking.code));
|
|
67
|
+
}
|
|
68
|
+
return lines.slice(0, 3);
|
|
69
|
+
}
|
|
70
|
+
const warn = params.findings.find((f) => f.severity === 'WARN');
|
|
71
|
+
if (warn) {
|
|
72
|
+
lines.push(`WARN ${warn.code}: ${truncate(warn.message, 120)}`);
|
|
73
|
+
}
|
|
74
|
+
return lines.slice(0, 3);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export const buildEvidenceOperationalHints = (params: {
|
|
78
|
+
stage: GateStage;
|
|
79
|
+
outcome: GateOutcome;
|
|
80
|
+
findings: ReadonlyArray<SnapshotFinding>;
|
|
81
|
+
rulesCoverage?: SnapshotRulesCoverage;
|
|
82
|
+
evaluationMetrics?: SnapshotEvaluationMetrics;
|
|
83
|
+
extra?: Partial<Pick<EvidenceOperationalHints, 'requires_second_pass' | 'second_pass_reason'>>;
|
|
84
|
+
}): EvidenceOperationalHints => {
|
|
85
|
+
const breakdown = buildRuleExecutionBreakdown({
|
|
86
|
+
findings: params.findings,
|
|
87
|
+
rulesCoverage: params.rulesCoverage,
|
|
88
|
+
evaluationMetrics: params.evaluationMetrics,
|
|
89
|
+
});
|
|
90
|
+
let human_summary_lines = buildHumanSummaryLines({
|
|
91
|
+
stage: params.stage,
|
|
92
|
+
outcome: params.outcome,
|
|
93
|
+
findings: params.findings,
|
|
94
|
+
});
|
|
95
|
+
if (params.extra?.requires_second_pass === true) {
|
|
96
|
+
human_summary_lines = [
|
|
97
|
+
...human_summary_lines,
|
|
98
|
+
'La evidencia trackeada se actualizó en disco pero no entró en el índice; si debe ir en este commit: git add -- .ai_evidence.json',
|
|
99
|
+
];
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
requires_second_pass: params.extra?.requires_second_pass ?? false,
|
|
103
|
+
second_pass_reason:
|
|
104
|
+
params.extra?.requires_second_pass === true
|
|
105
|
+
? (params.extra.second_pass_reason ?? null)
|
|
106
|
+
: null,
|
|
107
|
+
human_summary_lines: human_summary_lines.slice(0, 4),
|
|
108
|
+
rule_execution_breakdown: breakdown,
|
|
109
|
+
};
|
|
110
|
+
};
|
|
@@ -206,10 +206,26 @@ export type EvidenceChain = {
|
|
|
206
206
|
sequence: number;
|
|
207
207
|
};
|
|
208
208
|
|
|
209
|
+
export type EvidenceRuleExecutionBreakdown = {
|
|
210
|
+
evaluated_count: number;
|
|
211
|
+
matched_blocking_count: number;
|
|
212
|
+
matched_warn_count: number;
|
|
213
|
+
matched_info_count: number;
|
|
214
|
+
skipped_out_of_scope_count: number;
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
export type EvidenceOperationalHints = {
|
|
218
|
+
requires_second_pass: boolean;
|
|
219
|
+
second_pass_reason: string | null;
|
|
220
|
+
human_summary_lines: string[];
|
|
221
|
+
rule_execution_breakdown?: EvidenceRuleExecutionBreakdown;
|
|
222
|
+
};
|
|
223
|
+
|
|
209
224
|
export type AiEvidenceV2_1 = {
|
|
210
225
|
version: '2.1';
|
|
211
226
|
timestamp: string;
|
|
212
227
|
evidence_chain?: EvidenceChain;
|
|
228
|
+
operational_hints?: EvidenceOperationalHints;
|
|
213
229
|
snapshot: Snapshot;
|
|
214
230
|
ledger: LedgerEntry[];
|
|
215
231
|
platforms: Record<string, PlatformState>;
|
|
@@ -342,6 +342,9 @@ const toStableEvidence = (
|
|
|
342
342
|
return {
|
|
343
343
|
version: '2.1',
|
|
344
344
|
timestamp: evidence.timestamp,
|
|
345
|
+
...(typeof evidence.operational_hints !== 'undefined'
|
|
346
|
+
? { operational_hints: evidence.operational_hints }
|
|
347
|
+
: {}),
|
|
345
348
|
snapshot: {
|
|
346
349
|
stage: evidence.snapshot.stage,
|
|
347
350
|
audit_mode: normalizedAuditMode,
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export const DEFAULT_GATE_REMEDIATION =
|
|
2
|
+
'Corrige la causa del bloqueo y vuelve a ejecutar el gate.';
|
|
3
|
+
|
|
4
|
+
export const REMEDIATION_HINT_BY_CODE: Readonly<Record<string, string>> = {
|
|
5
|
+
EVIDENCE_MISSING: 'Regenera .ai_evidence.json ejecutando una auditoría.',
|
|
6
|
+
EVIDENCE_INVALID: 'Corrige/regenera .ai_evidence.json y vuelve a ejecutar el gate.',
|
|
7
|
+
EVIDENCE_CHAIN_INVALID: 'Regenera evidencia para restaurar la cadena criptográfica.',
|
|
8
|
+
EVIDENCE_STAGE_SYNC_FAILED:
|
|
9
|
+
'Sincroniza la evidencia trackeada y reintenta: git add -- .ai_evidence.json && git commit --amend --no-edit',
|
|
10
|
+
EVIDENCE_STALE: 'Refresca evidencia antes de continuar.',
|
|
11
|
+
EVIDENCE_REPO_ROOT_MISMATCH: 'Regenera evidencia desde este mismo repositorio.',
|
|
12
|
+
EVIDENCE_BRANCH_MISMATCH: 'Regenera evidencia en la rama actual y reintenta.',
|
|
13
|
+
EVIDENCE_RULES_COVERAGE_MISSING: 'Ejecuta auditoría completa para recalcular rules_coverage.',
|
|
14
|
+
EVIDENCE_RULES_COVERAGE_INCOMPLETE: 'Asegura coverage_ratio=1 y unevaluated=0.',
|
|
15
|
+
ACTIVE_RULE_IDS_EMPTY_FOR_CODE_CHANGES_HIGH:
|
|
16
|
+
'Reconcilia policy/skills y reintenta PRE_COMMIT: npx --yes --package pumuki@latest pumuki policy reconcile --strict --json && npx --yes --package pumuki@latest pumuki-pre-commit',
|
|
17
|
+
EVIDENCE_ACTIVE_RULE_IDS_EMPTY_FOR_CODE_CHANGES:
|
|
18
|
+
'Reconcilia policy/skills y revalida PRE_WRITE: npx --yes --package pumuki@latest pumuki policy reconcile --strict --json && npx --yes --package pumuki@latest pumuki sdd validate --stage=PRE_WRITE --json',
|
|
19
|
+
GITFLOW_PROTECTED_BRANCH: 'Trabaja en feature/* y evita ramas protegidas.',
|
|
20
|
+
EVIDENCE_PREWRITE_WORKTREE_OVER_LIMIT:
|
|
21
|
+
'Reduce archivos staged/unstaged por debajo del umbral (o ajusta PUMUKI_PREWRITE_WORKTREE_*); divide el trabajo en commits más pequeños.',
|
|
22
|
+
EVIDENCE_PREWRITE_WORKTREE_WARN:
|
|
23
|
+
'El worktree supera el umbral de aviso; reduce alcance antes del siguiente commit/push.',
|
|
24
|
+
PRE_PUSH_UPSTREAM_MISSING: 'Ejecuta: git push --set-upstream origin <branch>',
|
|
25
|
+
PRE_PUSH_UPSTREAM_MISALIGNED:
|
|
26
|
+
'Alinea upstream con la rama actual: git branch --unset-upstream && git push --set-upstream origin <branch>',
|
|
27
|
+
MANIFEST_MUTATION_DETECTED:
|
|
28
|
+
'Los hooks/gates no deben modificar manifests. Revisa wiring y ejecuta upgrade explícito solo cuando aplique (por ejemplo: pumuki update --latest).',
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const resolveRemediationHintForViolationCode = (code: string): string | undefined => {
|
|
32
|
+
const trimmed = code.trim();
|
|
33
|
+
if (trimmed.length === 0) {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
return REMEDIATION_HINT_BY_CODE[trimmed];
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const resolveRemediationHintOrDefault = (code: string): string =>
|
|
40
|
+
resolveRemediationHintForViolationCode(code) ?? DEFAULT_GATE_REMEDIATION;
|
|
@@ -9,6 +9,7 @@ export { parseNameStatus } from './gitDiffUtils';
|
|
|
9
9
|
export interface IGitService {
|
|
10
10
|
runGit(args: ReadonlyArray<string>, cwd?: string): string;
|
|
11
11
|
getStagedFacts(extensions: ReadonlyArray<string>): ReadonlyArray<Fact>;
|
|
12
|
+
getUnstagedFacts(extensions: ReadonlyArray<string>): ReadonlyArray<Fact>;
|
|
12
13
|
getRepoFacts(extensions: ReadonlyArray<string>): ReadonlyArray<Fact>;
|
|
13
14
|
getRepoAndStagedFacts(extensions: ReadonlyArray<string>): ReadonlyArray<Fact>;
|
|
14
15
|
getStagedAndUnstagedFacts(extensions: ReadonlyArray<string>): ReadonlyArray<Fact>;
|
|
@@ -44,6 +45,30 @@ export class GitService implements IGitService {
|
|
|
44
45
|
);
|
|
45
46
|
}
|
|
46
47
|
|
|
48
|
+
getUnstagedFacts(extensions: ReadonlyArray<string>): ReadonlyArray<Fact> {
|
|
49
|
+
const nameStatus = this.runGit(['diff', '--name-status']);
|
|
50
|
+
const changes = parseNameStatus(nameStatus).filter((change) =>
|
|
51
|
+
hasAllowedExtension(change.path, extensions)
|
|
52
|
+
);
|
|
53
|
+
const untrackedPaths = this.runGit(['ls-files', '--others', '--exclude-standard'])
|
|
54
|
+
.split('\n')
|
|
55
|
+
.map((line) => line.trim())
|
|
56
|
+
.filter((line) => line.length > 0)
|
|
57
|
+
.filter((path) => hasAllowedExtension(path, extensions));
|
|
58
|
+
const unstagedPaths = new Set(changes.map((change) => change.path));
|
|
59
|
+
const untrackedChanges = untrackedPaths
|
|
60
|
+
.filter((path) => !unstagedPaths.has(path))
|
|
61
|
+
.map((path) => ({
|
|
62
|
+
path,
|
|
63
|
+
changeType: 'added' as const,
|
|
64
|
+
}));
|
|
65
|
+
const mergedChanges = [...changes, ...untrackedChanges];
|
|
66
|
+
const repoRoot = this.resolveRepoRoot();
|
|
67
|
+
return buildFactsFromChanges(mergedChanges, 'git:unstaged', (filePath) =>
|
|
68
|
+
this.readWorkingTreeFile(repoRoot, filePath)
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
47
72
|
getRepoFacts(extensions: ReadonlyArray<string>): ReadonlyArray<Fact> {
|
|
48
73
|
const trackedFiles = this.runGit(['ls-files'])
|
|
49
74
|
.split('\n')
|