pumuki 6.3.231 → 6.3.233

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.
@@ -75,3 +75,33 @@ test('evaluateGate devuelve BLOCK cuando existe al menos un finding bloqueante',
75
75
  assert.equal(result.warnings.length, 1);
76
76
  assert.equal(result.warnings[0]?.ruleId, 'rule.warn');
77
77
  });
78
+
79
+ test('evaluateGate bloquea cualquier severidad cuando la policy zero-violations usa INFO', () => {
80
+ const findings: Finding[] = [
81
+ {
82
+ ruleId: 'rule.info',
83
+ severity: 'INFO',
84
+ code: 'RULE_INFO',
85
+ message: 'Info finding',
86
+ },
87
+ {
88
+ ruleId: 'rule.warn',
89
+ severity: 'WARN',
90
+ code: 'RULE_WARN',
91
+ message: 'Warn finding',
92
+ },
93
+ ];
94
+
95
+ const result = evaluateGate(findings, {
96
+ stage: 'PRE_PUSH',
97
+ blockOnOrAbove: 'INFO',
98
+ warnOnOrAbove: 'INFO',
99
+ });
100
+
101
+ assert.equal(result.outcome, 'BLOCK');
102
+ assert.deepEqual(
103
+ result.blocking.map((finding) => finding.ruleId),
104
+ ['rule.info', 'rule.warn']
105
+ );
106
+ assert.deepEqual(result.warnings, []);
107
+ });
@@ -32,15 +32,46 @@ test('evaluateRules genera finding cuando la condicion coincide y usa code expli
32
32
  const findings = evaluateRules(rules, facts);
33
33
 
34
34
  assert.equal(findings.length, 1);
35
- assert.deepEqual(findings[0], {
36
- ruleId: 'rule.explicit.code',
37
- severity: 'WARN',
38
- code: 'BACKEND_FILE_MODIFIED',
39
- message: 'Backend file modified.',
40
- filePath: 'apps/backend/src/main.ts',
41
- matchedBy: 'FileChange',
42
- source: 'git',
43
- });
35
+ assert.equal(findings[0]?.ruleId, 'rule.explicit.code');
36
+ assert.equal(findings[0]?.severity, 'WARN');
37
+ assert.equal(findings[0]?.code, 'BACKEND_FILE_MODIFIED');
38
+ assert.equal(findings[0]?.message, 'Backend file modified.');
39
+ assert.equal(findings[0]?.filePath, 'apps/backend/src/main.ts');
40
+ assert.equal(findings[0]?.matchedBy, 'FileChange');
41
+ assert.equal(findings[0]?.source, 'git');
42
+ assert.equal(findings[0]?.blocking, true);
43
+ });
44
+
45
+ test('evaluateRules marca cualquier severity como bloqueante bajo contrato zero-violations', () => {
46
+ const rules: RuleSet = [
47
+ {
48
+ id: 'rule.info.blocking',
49
+ description: 'Info still blocks in enterprise zero-violations mode.',
50
+ severity: 'INFO',
51
+ when: {
52
+ kind: 'FileChange',
53
+ where: { pathPrefix: 'apps/frontend/', changeType: 'modified' },
54
+ },
55
+ then: {
56
+ kind: 'Finding',
57
+ message: 'Any finding blocks.',
58
+ },
59
+ },
60
+ ];
61
+ const facts = [
62
+ {
63
+ kind: 'FileChange',
64
+ path: 'apps/frontend/src/App.tsx',
65
+ changeType: 'modified',
66
+ source: 'git',
67
+ },
68
+ ] as const;
69
+
70
+ const findings = evaluateRules(rules, facts);
71
+
72
+ assert.equal(findings.length, 1);
73
+ assert.equal(findings[0]?.severity, 'INFO');
74
+ assert.equal(findings[0]?.blocking, true);
44
75
  });
45
76
 
46
77
  test('evaluateRules usa id de la regla como code cuando no se define en consecuencia', () => {
@@ -23,8 +23,7 @@ type FindingTarget = {
23
23
  expected_fix?: string;
24
24
  };
25
25
 
26
- const isBlockingSeverity = (severity: RuleDefinition['severity']): boolean =>
27
- severity === 'CRITICAL' || severity === 'ERROR';
26
+ const isBlockingSeverity = (_severity: RuleDefinition['severity']): boolean => true;
28
27
 
29
28
  export type EvaluateRulesCoverageResult = {
30
29
  findings: ReadonlyArray<Finding>;
@@ -124,26 +124,35 @@ const toGatePolicyRecordFromEnterpriseThresholds = (
124
124
  };
125
125
  };
126
126
 
127
+ const ZERO_VIOLATION_BLOCK_ON_OR_ABOVE: GatePolicy['blockOnOrAbove'] = 'INFO';
128
+ const ZERO_VIOLATION_WARN_ON_OR_ABOVE: GatePolicy['warnOnOrAbove'] = 'INFO';
129
+
130
+ const enforceZeroViolationPolicy = (policy: GatePolicy): GatePolicy => ({
131
+ ...policy,
132
+ blockOnOrAbove: ZERO_VIOLATION_BLOCK_ON_OR_ABOVE,
133
+ warnOnOrAbove: ZERO_VIOLATION_WARN_ON_OR_ABOVE,
134
+ });
135
+
127
136
  const defaultPolicyByStage: Record<SkillsStage, GatePolicy> = {
128
137
  PRE_WRITE: {
129
138
  stage: 'PRE_WRITE',
130
- blockOnOrAbove: 'ERROR',
131
- warnOnOrAbove: 'WARN',
139
+ blockOnOrAbove: ZERO_VIOLATION_BLOCK_ON_OR_ABOVE,
140
+ warnOnOrAbove: ZERO_VIOLATION_WARN_ON_OR_ABOVE,
132
141
  },
133
142
  PRE_COMMIT: {
134
143
  stage: 'PRE_COMMIT',
135
- blockOnOrAbove: 'ERROR',
136
- warnOnOrAbove: 'WARN',
144
+ blockOnOrAbove: ZERO_VIOLATION_BLOCK_ON_OR_ABOVE,
145
+ warnOnOrAbove: ZERO_VIOLATION_WARN_ON_OR_ABOVE,
137
146
  },
138
147
  PRE_PUSH: {
139
148
  stage: 'PRE_PUSH',
140
- blockOnOrAbove: 'ERROR',
141
- warnOnOrAbove: 'WARN',
149
+ blockOnOrAbove: ZERO_VIOLATION_BLOCK_ON_OR_ABOVE,
150
+ warnOnOrAbove: ZERO_VIOLATION_WARN_ON_OR_ABOVE,
142
151
  },
143
152
  CI: {
144
153
  stage: 'CI',
145
- blockOnOrAbove: 'ERROR',
146
- warnOnOrAbove: 'WARN',
154
+ blockOnOrAbove: ZERO_VIOLATION_BLOCK_ON_OR_ABOVE,
155
+ warnOnOrAbove: ZERO_VIOLATION_WARN_ON_OR_ABOVE,
147
156
  },
148
157
  };
149
158
 
@@ -624,7 +633,7 @@ export const resolvePolicyForStage = (
624
633
  const profilePolicy = profileName
625
634
  ? hardModePolicyProfileByStage[profileName][stage]
626
635
  : null;
627
- const hardModePolicy = profilePolicy ?? hardModePolicyByStage[stage];
636
+ const hardModePolicy = enforceZeroViolationPolicy(profilePolicy ?? hardModePolicyByStage[stage]);
628
637
  const bundle = profileName
629
638
  ? `gate-policy.hard-mode.${profileName}.${stage}`
630
639
  : `gate-policy.hard-mode.${stage}`;
@@ -693,8 +702,8 @@ export const resolvePolicyForStage = (
693
702
 
694
703
  const resolvedPolicy: GatePolicy = {
695
704
  stage: defaults.stage,
696
- blockOnOrAbove: stageOverride.blockOnOrAbove,
697
- warnOnOrAbove: stageOverride.warnOnOrAbove,
705
+ blockOnOrAbove: ZERO_VIOLATION_BLOCK_ON_OR_ABOVE,
706
+ warnOnOrAbove: ZERO_VIOLATION_WARN_ON_OR_ABOVE,
698
707
  };
699
708
 
700
709
  const bundle = `gate-policy.skills.policy.${stage}`;
@@ -256,10 +256,7 @@ const toResultScope = (params: {
256
256
  };
257
257
 
258
258
  const isFindingBlocking = (finding: SnapshotFinding): boolean => {
259
- if (typeof finding.blocking === 'boolean') {
260
- return finding.blocking;
261
- }
262
- return finding.severity === 'CRITICAL' || finding.severity === 'ERROR';
259
+ return Boolean(finding.ruleId);
263
260
  };
264
261
 
265
262
  const toLifecycleAuditFinding = (finding: SnapshotFinding): LifecycleAuditFinding => ({
@@ -85,26 +85,37 @@ const toGatePolicyRecordFromEnterpriseThresholds = (
85
85
  };
86
86
  };
87
87
 
88
+ const ZERO_VIOLATION_BLOCK_ON_OR_ABOVE: GatePolicy['blockOnOrAbove'] = 'INFO';
89
+ const ZERO_VIOLATION_WARN_ON_OR_ABOVE: GatePolicy['warnOnOrAbove'] = 'INFO';
90
+
91
+ const enforceZeroViolationPolicy = (policy: GatePolicy): GatePolicy => {
92
+ return {
93
+ ...policy,
94
+ blockOnOrAbove: ZERO_VIOLATION_BLOCK_ON_OR_ABOVE,
95
+ warnOnOrAbove: ZERO_VIOLATION_WARN_ON_OR_ABOVE,
96
+ };
97
+ };
98
+
88
99
  const defaultPolicyByStage: Record<SkillsStage, GatePolicy> = {
89
100
  PRE_WRITE: {
90
101
  stage: 'PRE_WRITE',
91
- blockOnOrAbove: 'ERROR',
92
- warnOnOrAbove: 'WARN',
102
+ blockOnOrAbove: ZERO_VIOLATION_BLOCK_ON_OR_ABOVE,
103
+ warnOnOrAbove: ZERO_VIOLATION_WARN_ON_OR_ABOVE,
93
104
  },
94
105
  PRE_COMMIT: {
95
106
  stage: 'PRE_COMMIT',
96
- blockOnOrAbove: 'ERROR',
97
- warnOnOrAbove: 'WARN',
107
+ blockOnOrAbove: ZERO_VIOLATION_BLOCK_ON_OR_ABOVE,
108
+ warnOnOrAbove: ZERO_VIOLATION_WARN_ON_OR_ABOVE,
98
109
  },
99
110
  PRE_PUSH: {
100
111
  stage: 'PRE_PUSH',
101
- blockOnOrAbove: 'ERROR',
102
- warnOnOrAbove: 'WARN',
112
+ blockOnOrAbove: ZERO_VIOLATION_BLOCK_ON_OR_ABOVE,
113
+ warnOnOrAbove: ZERO_VIOLATION_WARN_ON_OR_ABOVE,
103
114
  },
104
115
  CI: {
105
116
  stage: 'CI',
106
- blockOnOrAbove: 'ERROR',
107
- warnOnOrAbove: 'WARN',
117
+ blockOnOrAbove: ZERO_VIOLATION_BLOCK_ON_OR_ABOVE,
118
+ warnOnOrAbove: ZERO_VIOLATION_WARN_ON_OR_ABOVE,
108
119
  },
109
120
  };
110
121
 
@@ -374,7 +385,7 @@ export const resolveExplicitPolicyProfileForStage = (
374
385
  const profilePolicy = profileName
375
386
  ? hardModePolicyProfileByStage[profileName][stage]
376
387
  : null;
377
- const hardModePolicy = profilePolicy ?? hardModePolicyByStage[stage];
388
+ const hardModePolicy = enforceZeroViolationPolicy(profilePolicy ?? hardModePolicyByStage[stage]);
378
389
  return {
379
390
  policy: hardModePolicy,
380
391
  source: 'hard-mode',
@@ -394,8 +405,8 @@ export const resolveExplicitPolicyProfileForStage = (
394
405
  return {
395
406
  policy: {
396
407
  stage: defaults.stage,
397
- blockOnOrAbove: stageOverride.blockOnOrAbove,
398
- warnOnOrAbove: stageOverride.warnOnOrAbove,
408
+ blockOnOrAbove: ZERO_VIOLATION_BLOCK_ON_OR_ABOVE,
409
+ warnOnOrAbove: ZERO_VIOLATION_WARN_ON_OR_ABOVE,
399
410
  },
400
411
  source: 'skills.policy',
401
412
  layer: 'policy-pack',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pumuki",
3
- "version": "6.3.231",
3
+ "version": "6.3.233",
4
4
  "description": "Enterprise-grade AST Intelligence System with multi-platform support (iOS, Android, Backend, Frontend) and Feature-First + DDD + Clean Architecture enforcement. Includes dynamic violations API for intelligent querying.",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -8,20 +8,20 @@ export const buildAuditSummaryPayload = (
8
8
  ): SystemNotificationPayload => {
9
9
  if (event.criticalViolations > 0) {
10
10
  return {
11
- title: 'AST Audit Complete',
11
+ title: 'AST Audit Blocked',
12
12
  message: `🔴 ${event.criticalViolations} CRITICAL, ${event.highViolations} HIGH violations`,
13
13
  };
14
14
  }
15
15
  if (event.highViolations > 0) {
16
16
  return {
17
- title: 'AST Audit Complete',
17
+ title: 'AST Audit Blocked',
18
18
  message: `🟡 ${event.highViolations} HIGH violations found`,
19
19
  };
20
20
  }
21
21
  if (event.totalViolations > 0) {
22
22
  return {
23
- title: 'AST Audit Complete',
24
- message: `🔵 ${event.totalViolations} violations (no blockers)`,
23
+ title: 'AST Audit Blocked',
24
+ message: `🔴 ${event.totalViolations} violations block the gate`,
25
25
  };
26
26
  }
27
27
  return {