pumuki 6.3.28 → 6.3.30

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.
Files changed (83) hide show
  1. package/README.md +57 -0
  2. package/core/gate/conditionMatches.test.ts +34 -0
  3. package/core/gate/evaluateRules.test.ts +46 -0
  4. package/core/gate/scopeMatcher.ts +46 -45
  5. package/docs/API_REFERENCE.md +5 -0
  6. package/docs/CONFIGURATION.md +20 -0
  7. package/docs/README.md +4 -11
  8. package/docs/registro-maestro-de-seguimiento.md +18 -0
  9. package/docs/{validation/p9-ruralgo-fork-validation-tracking.md → seguimiento-completo-validacion-ruralgo-03-03-2026.md} +1290 -27
  10. package/docs/validation/README.md +6 -13
  11. package/docs/validation/c022-phase-acceptance-contract.md +1 -1
  12. package/integrations/evidence/evidenceChain.ts +89 -0
  13. package/integrations/evidence/readEvidence.test.ts +121 -50
  14. package/integrations/evidence/readEvidence.ts +91 -6
  15. package/integrations/evidence/rulesCoverage.ts +0 -94
  16. package/integrations/evidence/schema.test.ts +0 -16
  17. package/integrations/evidence/schema.ts +13 -41
  18. package/integrations/evidence/writeEvidence.test.ts +82 -69
  19. package/integrations/evidence/writeEvidence.ts +35 -24
  20. package/integrations/gate/evaluateAiGate.ts +43 -229
  21. package/integrations/gate/stagePolicies.ts +261 -50
  22. package/integrations/git/EvidenceService.ts +9 -0
  23. package/integrations/git/findingTraceability.ts +3 -3
  24. package/integrations/git/gateWaiver.ts +143 -0
  25. package/integrations/git/resolveGitRefs.ts +11 -0
  26. package/integrations/git/runCliCommand.ts +0 -16
  27. package/integrations/git/runPlatformGate.ts +354 -38
  28. package/integrations/git/runPlatformGateEvaluation.ts +0 -13
  29. package/integrations/git/runPlatformGateEvidence.ts +17 -1
  30. package/integrations/git/stageRunners.ts +118 -145
  31. package/integrations/lifecycle/cli.ts +301 -233
  32. package/integrations/lifecycle/doctor.ts +363 -465
  33. package/integrations/lifecycle/hookBlock.ts +6 -2
  34. package/integrations/lifecycle/hookManager.ts +20 -2
  35. package/integrations/lifecycle/install.ts +3 -115
  36. package/integrations/lifecycle/openSpecBootstrap.ts +8 -68
  37. package/integrations/lifecycle/preWriteAutomation.ts +74 -14
  38. package/integrations/lifecycle/remoteCiDiagnostics.ts +382 -0
  39. package/integrations/mcp/aiGateCheck.ts +0 -2
  40. package/integrations/sdd/index.ts +1 -2
  41. package/integrations/sdd/openSpecCli.ts +2 -4
  42. package/integrations/sdd/policy.ts +146 -155
  43. package/integrations/sdd/sessionStore.ts +28 -138
  44. package/integrations/sdd/syncDocs.ts +168 -150
  45. package/integrations/sdd/types.ts +2 -3
  46. package/integrations/telemetry/gateTelemetry.ts +372 -0
  47. package/package.json +7 -20
  48. package/scripts/build-phase8-ready-handoff-summary.sh +1 -1
  49. package/scripts/check-package-manifest.ts +0 -49
  50. package/scripts/check-refactor-progress-single-active.sh +1 -1
  51. package/scripts/check-tracking-single-active.sh +3 -5
  52. package/scripts/close-phase5-escalation-submission.sh +1 -1
  53. package/scripts/framework-menu-consumer-preflight-lib.ts +1 -31
  54. package/scripts/framework-menu-consumer-runtime-lib.ts +3 -3
  55. package/scripts/framework-menu-legacy-audit-lib.ts +7 -35
  56. package/scripts/framework-menu-matrix-evidence-lib.ts +2 -6
  57. package/scripts/package-manifest-lib.ts +16 -13
  58. package/core/gate/evaluateGate.js +0 -5
  59. package/core/gate/evaluateRules.js +0 -5
  60. package/docs/EXECUTION_BOARD.md +0 -794
  61. package/docs/REFRACTOR_PROGRESS.md +0 -1917
  62. package/docs/validation/p9-ruralgo-bug-registry.md +0 -607
  63. package/docs/validation/real-repo-manual-e2e-ruralgo-fork.md +0 -372
  64. package/integrations/config/skillsCompliance.ts +0 -212
  65. package/integrations/evidence/integrity.ts +0 -352
  66. package/integrations/gate/waivers.ts +0 -209
  67. package/integrations/git/index.js +0 -5
  68. package/integrations/lifecycle/index.js +0 -5
  69. package/integrations/mcp/index.js +0 -5
  70. package/integrations/sdd/index.js +0 -5
  71. package/integrations/telemetry/structuredTelemetry.ts +0 -197
  72. package/scripts/build-p9-validation-manifests.ts +0 -53
  73. package/scripts/check-p9-ruralgo-baseline-clean.ts +0 -200
  74. package/scripts/check-p9-ruralgo-baseline-versioned.ts +0 -198
  75. package/scripts/check-p9-ruralgo-branch-ready.ts +0 -215
  76. package/scripts/check-p9-ruralgo-install-health.ts +0 -288
  77. package/scripts/check-p9-ruralgo-runtime-ready.ts +0 -188
  78. package/scripts/p9-ruralgo-baseline-clean-lib.ts +0 -117
  79. package/scripts/p9-ruralgo-baseline-versioned-lib.ts +0 -119
  80. package/scripts/p9-ruralgo-branch-ready-lib.ts +0 -128
  81. package/scripts/p9-ruralgo-install-health-lib.ts +0 -121
  82. package/scripts/p9-ruralgo-runtime-ready-lib.ts +0 -149
  83. package/scripts/p9-validation-manifests-lib.ts +0 -366
package/README.md CHANGED
@@ -124,6 +124,63 @@ Rule modes:
124
124
  9. Provider-agnostic adapter scaffolding (`codex`, `claude`, `cursor`, `windsurf`, `opencode`).
125
125
  10. Optional MCP servers for evidence and enterprise context.
126
126
 
127
+ ## Policy-as-Code (Enterprise)
128
+
129
+ Pumuki supports a signed and versioned stage-policy contract at:
130
+
131
+ - `.pumuki/policy-as-code.json`
132
+
133
+ Minimal contract:
134
+
135
+ ```json
136
+ {
137
+ "version": "1.0",
138
+ "source": "default",
139
+ "expires_at": "2026-12-31T23:59:59.000Z",
140
+ "signatures": {
141
+ "PRE_COMMIT": "<sha256-hex>",
142
+ "PRE_PUSH": "<sha256-hex>",
143
+ "CI": "<sha256-hex>"
144
+ }
145
+ }
146
+ ```
147
+
148
+ Runtime behavior:
149
+
150
+ - If the contract is missing, Pumuki computes deterministic local metadata and still emits `policy_version`, `policy_signature`, and `policy_source`.
151
+ - If present, the contract is validated against active runtime policy for source/stage/signature.
152
+ - Validation states are emitted as `valid`, `invalid`, `expired`, or `unknown-source`.
153
+ - `PUMUKI_POLICY_STRICT=1` turns non-valid states into blocking findings (`governance.policy-as-code.invalid`).
154
+
155
+ Operational fallback:
156
+
157
+ - Keep strict mode disabled while bootstrapping a repo without a canonical contract.
158
+ - Enable strict mode once contract generation/signatures are part of your baseline pipeline.
159
+
160
+ ## Telemetry Export (Enterprise)
161
+
162
+ Pumuki can export structured gate telemetry with a stable event schema (`telemetry_event_v1`) for SIEM/observability pipelines.
163
+
164
+ Default behavior remains unchanged: telemetry export is disabled unless explicitly configured.
165
+
166
+ Enable one or both outputs:
167
+
168
+ - `PUMUKI_TELEMETRY_JSONL_PATH`: local JSONL target (absolute or repo-relative path)
169
+ - `PUMUKI_TELEMETRY_OTEL_ENDPOINT`: OTLP HTTP logs endpoint (`/v1/logs`)
170
+ - `PUMUKI_TELEMETRY_OTEL_SERVICE_NAME`: optional OTel service name (default: `pumuki`)
171
+ - `PUMUKI_TELEMETRY_OTEL_TIMEOUT_MS`: optional OTel timeout in ms (default: `1500`)
172
+
173
+ Example:
174
+
175
+ ```bash
176
+ export PUMUKI_TELEMETRY_JSONL_PATH=".pumuki/artifacts/gate-telemetry.jsonl"
177
+ export PUMUKI_TELEMETRY_OTEL_ENDPOINT="https://otel.example/v1/logs"
178
+ export PUMUKI_TELEMETRY_OTEL_SERVICE_NAME="pumuki-enterprise"
179
+ npx --yes pumuki-pre-commit
180
+ ```
181
+
182
+ Each event captures deterministic stage/outcome/policy/repo context per gate execution.
183
+
127
184
  ## Framework Maintainer Flow (This Repo)
128
185
 
129
186
  Use this only when working in the Pumuki framework repository itself:
@@ -108,3 +108,37 @@ test('conditionMatches soporta condiciones compuestas All, Any y Not', () => {
108
108
 
109
109
  assert.equal(conditionMatches(composedCondition, facts), true);
110
110
  });
111
+
112
+ test('conditionMatches respeta include glob swift y no matchea archivos no swift', () => {
113
+ const scopedCondition: Condition = {
114
+ kind: 'All',
115
+ conditions: [
116
+ {
117
+ kind: 'FileContent',
118
+ contains: ['!'],
119
+ },
120
+ {
121
+ kind: 'Not',
122
+ condition: {
123
+ kind: 'FileContent',
124
+ contains: ['IBOutlet'],
125
+ },
126
+ },
127
+ ],
128
+ };
129
+ const scopedFacts = [
130
+ {
131
+ kind: 'FileContent' as const,
132
+ path: 'apps/admin-dashboard/middleware.ts',
133
+ content: 'if (token != null) { return NextResponse.next(); }',
134
+ source: 'repo',
135
+ },
136
+ ];
137
+
138
+ assert.equal(
139
+ conditionMatches(scopedCondition, scopedFacts, {
140
+ include: ['**/*.swift'],
141
+ }),
142
+ false
143
+ );
144
+ });
@@ -199,3 +199,49 @@ test('evaluateRules genera un finding por cada heuristica coincidente', () => {
199
199
  );
200
200
  assert.equal(findings.every((finding) => finding.matchedBy === 'Heuristic'), true);
201
201
  });
202
+
203
+ test('evaluateRules no genera finding de iOS cuando el scope es swift y el archivo es TypeScript', () => {
204
+ const rules: RuleSet = [
205
+ {
206
+ id: 'ios.no-force-unwrap',
207
+ description: 'Disallows force unwraps in iOS code.',
208
+ severity: 'CRITICAL',
209
+ scope: {
210
+ include: ['**/*.swift'],
211
+ },
212
+ when: {
213
+ kind: 'All',
214
+ conditions: [
215
+ {
216
+ kind: 'FileContent',
217
+ contains: ['!'],
218
+ },
219
+ {
220
+ kind: 'Not',
221
+ condition: {
222
+ kind: 'FileContent',
223
+ contains: ['IBOutlet'],
224
+ },
225
+ },
226
+ ],
227
+ },
228
+ then: {
229
+ kind: 'Finding',
230
+ message: 'Force unwraps are not allowed in iOS code.',
231
+ code: 'IOS_NO_FORCE_UNWRAP',
232
+ },
233
+ },
234
+ ];
235
+ const facts = [
236
+ {
237
+ kind: 'FileContent',
238
+ path: 'apps/admin-dashboard/middleware.ts',
239
+ content: 'if (token != null) { return NextResponse.next(); }',
240
+ source: 'repo',
241
+ },
242
+ ] as const;
243
+
244
+ const findings = evaluateRules(rules, facts);
245
+
246
+ assert.deepEqual(findings, []);
247
+ });
@@ -1,68 +1,70 @@
1
- import type { RuleDefinition } from '../rules/RuleDefinition';
2
-
3
- type RuleScope = RuleDefinition['scope'];
4
-
5
- const SPECIAL_REGEX_CHARS = /[|\\{}()[\]^$+?.]/;
6
- const regexCache = new Map<string, RegExp>();
1
+ type ScopePattern = {
2
+ include?: ReadonlyArray<string>;
3
+ exclude?: ReadonlyArray<string>;
4
+ };
7
5
 
8
- const normalize = (value: string): string => {
6
+ const normalizePath = (value: string): string => {
9
7
  return value.replace(/\\/g, '/');
10
8
  };
11
9
 
12
- const escapeRegexChar = (value: string): string => {
13
- return SPECIAL_REGEX_CHARS.test(value) ? `\\${value}` : value;
10
+ const escapeRegex = (value: string): string => {
11
+ return value.replace(/[|\\{}()[\]^$+?.]/g, '\\$&');
14
12
  };
15
13
 
16
14
  const toGlobRegex = (pattern: string): RegExp => {
17
- const cached = regexCache.get(pattern);
18
- if (cached) {
19
- return cached;
20
- }
21
-
22
15
  let regex = '^';
23
- for (let index = 0; index < pattern.length;) {
24
- if (pattern.startsWith('**/', index)) {
25
- regex += '(?:.*/)?';
26
- index += 3;
16
+ for (let index = 0; index < pattern.length; index += 1) {
17
+ const current = pattern[index];
18
+ if (current === '*') {
19
+ const next = pattern[index + 1];
20
+ if (next === '*') {
21
+ const nextNext = pattern[index + 2];
22
+ if (nextNext === '/') {
23
+ regex += '(?:.*/)?';
24
+ index += 2;
25
+ } else {
26
+ regex += '.*';
27
+ index += 1;
28
+ }
29
+ } else {
30
+ regex += '[^/]*';
31
+ }
27
32
  continue;
28
33
  }
29
- if (pattern.startsWith('**', index)) {
30
- regex += '.*';
31
- index += 2;
34
+ if (current === '?') {
35
+ regex += '[^/]';
32
36
  continue;
33
37
  }
34
-
35
- const char = pattern[index];
36
- if (char === '*') {
37
- regex += '[^/]*';
38
- index += 1;
39
- continue;
40
- }
41
-
42
- regex += escapeRegexChar(char);
43
- index += 1;
38
+ regex += escapeRegex(current);
44
39
  }
45
40
  regex += '$';
41
+ return new RegExp(regex);
42
+ };
46
43
 
47
- const compiled = new RegExp(regex);
48
- regexCache.set(pattern, compiled);
49
- return compiled;
44
+ const extractPrefix = (pattern: string): string => {
45
+ const wildcardIndex = pattern.search(/[*?]/);
46
+ return wildcardIndex === -1 ? pattern : pattern.slice(0, wildcardIndex);
50
47
  };
51
48
 
52
- const matchesPattern = (path: string, pattern: string): boolean => {
53
- const normalizedPath = normalize(path);
54
- const normalizedPattern = normalize(pattern);
49
+ const isTrailingWildcardPattern = (pattern: string): boolean => {
50
+ const wildcardIndex = pattern.search(/[*?]/);
51
+ if (wildcardIndex === -1) {
52
+ return false;
53
+ }
54
+ const suffix = pattern.slice(wildcardIndex);
55
+ return /^[*?]+$/.test(suffix);
56
+ };
55
57
 
56
- const wildcardIndex = normalizedPattern.indexOf('*');
58
+ export const matchesPattern = (path: string, pattern: string): boolean => {
59
+ const normalizedPath = normalizePath(path);
60
+ const normalizedPattern = normalizePath(pattern);
61
+ const wildcardIndex = normalizedPattern.search(/[*?]/);
57
62
  if (wildcardIndex === -1) {
58
63
  return normalizedPath.startsWith(normalizedPattern);
59
64
  }
60
-
61
- const prefix = normalizedPattern.slice(0, wildcardIndex);
62
- if (prefix.length > 0 && normalizedPath.startsWith(prefix)) {
63
- return true;
65
+ if (isTrailingWildcardPattern(normalizedPattern)) {
66
+ return normalizedPath.startsWith(extractPrefix(normalizedPattern));
64
67
  }
65
-
66
68
  return toGlobRegex(normalizedPattern).test(normalizedPath);
67
69
  };
68
70
 
@@ -70,10 +72,9 @@ const matchesAnyPattern = (path: string, patterns: ReadonlyArray<string>): boole
70
72
  return patterns.some((pattern) => matchesPattern(path, pattern));
71
73
  };
72
74
 
73
- export const matchesScope = (path: string, scope?: RuleScope): boolean => {
75
+ export const matchesScope = (path: string, scope?: ScopePattern): boolean => {
74
76
  const include = scope?.include;
75
77
  const exclude = scope?.exclude;
76
-
77
78
  if (exclude && exclude.length > 0 && matchesAnyPattern(path, exclude)) {
78
79
  return false;
79
80
  }
@@ -110,6 +110,11 @@ Contract:
110
110
  - evidence `ai_gate.status = BLOCKED`
111
111
  - protected branch use (`main/master/develop/dev` by default)
112
112
  - Returns deterministic payload: `status`, `allowed`, `violations[]`, `evidence`, `repo_state`.
113
+ - Evidence source contract (auditability):
114
+ - `evidence.source.source`
115
+ - `evidence.source.path`
116
+ - `evidence.source.digest`
117
+ - `evidence.source.generated_at`
113
118
 
114
119
  ## PRE_WRITE JSON envelope
115
120
 
@@ -97,6 +97,26 @@ Defined in `integrations/gate/stagePolicies.ts`:
97
97
  - `PRE_PUSH`: block `ERROR`, warn from `WARN`
98
98
  - `CI`: block `ERROR`, warn from `WARN`
99
99
 
100
+ ## Gate telemetry export (optional)
101
+
102
+ Structured telemetry output is disabled by default and can be enabled with environment variables:
103
+
104
+ - `PUMUKI_TELEMETRY_JSONL_PATH`:
105
+ - JSONL file path for `telemetry_event_v1` records.
106
+ - Accepts absolute path or repo-relative path.
107
+ - `PUMUKI_TELEMETRY_OTEL_ENDPOINT`:
108
+ - OTLP HTTP logs endpoint (`/v1/logs`).
109
+ - `PUMUKI_TELEMETRY_OTEL_SERVICE_NAME`:
110
+ - Optional service name for OTel payload (`default: pumuki`).
111
+ - `PUMUKI_TELEMETRY_OTEL_TIMEOUT_MS`:
112
+ - Optional timeout for OTel dispatch in milliseconds (`default: 1500`).
113
+
114
+ Notes:
115
+
116
+ - You can enable JSONL only, OTel only, or both.
117
+ - If unset, no telemetry export is attempted.
118
+ - Gate execution remains deterministic even when OTel endpoint is unavailable (best-effort dispatch).
119
+
100
120
  ## Heuristic pilot flag
101
121
 
102
122
  Enable semantic heuristic rules:
package/docs/README.md CHANGED
@@ -2,18 +2,14 @@
2
2
 
3
3
  Canonical index for active Pumuki documentation.
4
4
 
5
- ## Ciclo Activo (Seguimiento Temporal)
5
+ ## Seguimiento Activo (único)
6
6
 
7
- - Seguimiento diario (único y simplificado): `docs/EXECUTION_BOARD.md`.
8
- - Seguimiento simple de validación real en repo no-mock: `docs/validation/p9-ruralgo-fork-validation-tracking.md`.
9
- - Cierre funcional previo: `P6` (verificación exhaustiva interna real/mock, `371/371`) consolidado en `docs/REFRACTOR_PROGRESS.md`.
10
- - Alcance activo actual: `P9` (validación manual guiada en repo real externo `ruralgo-fork`) en `docs/validation/p9-ruralgo-fork-validation-tracking.md`.
11
- - Ultimo cierre oficial previo: ciclo `022` consolidado en `docs/validation/c022-phase-acceptance-contract.md`.
12
- - Politica: una sola tarea en construccion (`🚧`) en todo momento.
7
+ - Maestro: `docs/registro-maestro-de-seguimiento.md`
8
+ - Plan activo: `docs/seguimiento-completo-validacion-ruralgo-03-03-2026.md`
9
+ - Política: una sola tarea en construcción (`🚧`) en el plan activo.
13
10
 
14
11
  ## Product and Architecture
15
12
 
16
- - `docs/EXECUTION_BOARD.md`: tablero activo de seguimiento (simple).
17
13
  - `docs/ARCHITECTURE.md`: normative architecture contract.
18
14
  - `docs/HOW_IT_WORKS.md`: facts-to-gate execution flow.
19
15
  - `docs/API_REFERENCE.md`: public APIs, binaries, and command surfaces.
@@ -55,9 +51,6 @@ Canonical index for active Pumuki documentation.
55
51
  - `docs/validation/c022-phase-acceptance-contract.md`
56
52
  - `docs/validation/enterprise-consumer-isolation-policy.md`
57
53
  - `docs/validation/mock-consumer-integration-runbook.md`
58
- - `docs/validation/p9-ruralgo-bug-registry.md`
59
- - `docs/validation/p9-ruralgo-fork-validation-tracking.md`
60
- - `docs/validation/real-repo-manual-e2e-ruralgo-fork.md`
61
54
  - `docs/validation/detection-audit-baseline.md`
62
55
  - `docs/validation/skills-rollout-consumer-repositories.md`
63
56
 
@@ -0,0 +1,18 @@
1
+ # Registro Maestro de Seguimiento
2
+
3
+ ## Objetivo
4
+ - Mantener trazabilidad ejecutiva en un solo punto.
5
+ - Referenciar un único plan activo con fases, tasks y leyenda.
6
+
7
+ ## Estado actual
8
+ - Plan activo: `docs/seguimiento-completo-validacion-ruralgo-03-03-2026.md`
9
+ - Estado del plan: EN CURSO
10
+ - Task activa (`🚧`): `P12.F1.T42` (sincronizar canónico RuralGO tras cierre de `#543` y actualizar refs reales en feedback/master plan).
11
+
12
+ ## Historial resumido
13
+ - No se mantienen MDs históricos de seguimiento en este repositorio.
14
+ - La trazabilidad histórica relevante debe consolidarse dentro del plan activo o en documentación oficial no temporal.
15
+
16
+ ## Regla de operación
17
+ - Debe existir exactamente una task `🚧` en el plan activo.
18
+ - No se crean nuevos MDs de seguimiento salvo instrucción explícita.