pumuki 6.3.132 → 6.3.133
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/CHANGELOG.md +8 -0
- package/docs/operations/RELEASE_NOTES.md +6 -0
- package/integrations/gate/runPlatformGateConfig.ts +55 -0
- package/integrations/gate/runPlatformGateDefaults.ts +19 -0
- package/integrations/git/runPlatformGate.ts +61 -88
- package/integrations/policy/skillsEnforcement.ts +0 -40
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,14 @@ This project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [6.3.133] - 2026-05-03
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- **Skills enforcement endurecido a bloqueo duro:** `PRE_WRITE`, `PRE_COMMIT` y `PRE_PUSH` ya no admiten bypass advisory para violaciones de skills.
|
|
14
|
+
- **Contrato de gate alineado de punta a punta:** `skillsEnforcement`, `evaluateAiGate`, `runPlatformGate` y el flujo CLI bloquean de forma consistente cuando falta cobertura, bundles o contrato de skills.
|
|
15
|
+
- **Release listo para repin:** esta versión está preparada para publicarse y repinear consumers como RuralGo sin cerrar más gaps funcionales para este fix.
|
|
16
|
+
|
|
9
17
|
## [6.3.132] - 2026-05-03
|
|
10
18
|
|
|
11
19
|
### Fixed
|
|
@@ -4,6 +4,12 @@ This file tracks the active deterministic framework line used in this repository
|
|
|
4
4
|
Canonical release chronology lives in `CHANGELOG.md`.
|
|
5
5
|
This file keeps only the operational highlights and rollout notes that matter while running the framework.
|
|
6
6
|
|
|
7
|
+
### 2026-05-03 (v6.3.133)
|
|
8
|
+
|
|
9
|
+
- **Skills hard-blocking end-to-end:** `skillsEnforcement`, `evaluateAiGate`, `runPlatformGate` y el flujo CLI ya no dejan pasar advisory para violations de skills.
|
|
10
|
+
- **Repin recomendado:** publicar `pumuki@6.3.133`, repinear RuralGo y revalidar `status`, `doctor`, `audit --stage=PRE_WRITE --json` y hooks gestionados.
|
|
11
|
+
- **Contrato de release estable:** no hace falta cerrar más gaps funcionales para este fix; la solución ya quedó validada localmente y lo que falta es distribución.
|
|
12
|
+
|
|
7
13
|
### 2026-05-03 (v6.3.130)
|
|
8
14
|
|
|
9
15
|
- **Menú consumer legacy recuperado:** `pumuki-framework` vuelve a mostrar la portada plana de 9 opciones y la salida clásica de auditoría.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_DEGRADED_MODE_ACTION_ALLOW,
|
|
3
|
+
DEFAULT_DEGRADED_MODE_ACTION_BLOCK,
|
|
4
|
+
DEFAULT_GATE_AUDIT_MODE,
|
|
5
|
+
DEFAULT_LIST_SEPARATOR,
|
|
6
|
+
DEFAULT_MEMORY_SHADOW_DISPLAY_PRECISION,
|
|
7
|
+
DEFAULT_MEMORY_SHADOW_CONFIDENCE_ALLOW,
|
|
8
|
+
DEFAULT_MEMORY_SHADOW_CONFIDENCE_BLOCK,
|
|
9
|
+
DEFAULT_MEMORY_SHADOW_CONFIDENCE_WARN,
|
|
10
|
+
DEFAULT_MEMORY_SHADOW_CONFIDENCE_WARN_ADVISORY,
|
|
11
|
+
DEFAULT_RULES_COVERAGE_RATIO_DECIMALS,
|
|
12
|
+
LIFECYCLE_GATE_STAGES,
|
|
13
|
+
MAX_IOS_TEST_QUALITY_SAMPLE_FILES,
|
|
14
|
+
MAX_OBSERVED_CODE_PATHS_SAMPLE,
|
|
15
|
+
MAX_SCOPE_SAMPLE_PATHS,
|
|
16
|
+
} from './runPlatformGateDefaults';
|
|
17
|
+
|
|
18
|
+
const parseConfidence = (value: string | undefined, fallback: number): number => {
|
|
19
|
+
const parsed = Number.parseFloat(value ?? '');
|
|
20
|
+
return Number.isFinite(parsed) ? parsed : fallback;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const LIST_SEPARATOR = DEFAULT_LIST_SEPARATOR;
|
|
24
|
+
|
|
25
|
+
export const MEMORY_SHADOW_CONFIDENCE_BLOCK = parseConfidence(
|
|
26
|
+
process.env.PUMUKI_MEMORY_SHADOW_CONFIDENCE_BLOCK,
|
|
27
|
+
DEFAULT_MEMORY_SHADOW_CONFIDENCE_BLOCK
|
|
28
|
+
);
|
|
29
|
+
export const MEMORY_SHADOW_CONFIDENCE_WARN = parseConfidence(
|
|
30
|
+
process.env.PUMUKI_MEMORY_SHADOW_CONFIDENCE_WARN,
|
|
31
|
+
DEFAULT_MEMORY_SHADOW_CONFIDENCE_WARN
|
|
32
|
+
);
|
|
33
|
+
export const MEMORY_SHADOW_CONFIDENCE_WARN_ADVISORY = parseConfidence(
|
|
34
|
+
process.env.PUMUKI_MEMORY_SHADOW_CONFIDENCE_WARN_ADVISORY,
|
|
35
|
+
DEFAULT_MEMORY_SHADOW_CONFIDENCE_WARN_ADVISORY
|
|
36
|
+
);
|
|
37
|
+
export const MEMORY_SHADOW_CONFIDENCE_ALLOW = parseConfidence(
|
|
38
|
+
process.env.PUMUKI_MEMORY_SHADOW_CONFIDENCE_ALLOW,
|
|
39
|
+
DEFAULT_MEMORY_SHADOW_CONFIDENCE_ALLOW
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
export const DEGRADED_MODE_ACTION_BLOCK =
|
|
43
|
+
process.env.PUMUKI_DEGRADED_MODE_ACTION_BLOCK?.trim() || DEFAULT_DEGRADED_MODE_ACTION_BLOCK;
|
|
44
|
+
export const DEGRADED_MODE_ACTION_ALLOW =
|
|
45
|
+
process.env.PUMUKI_DEGRADED_MODE_ACTION_ALLOW?.trim() || DEFAULT_DEGRADED_MODE_ACTION_ALLOW;
|
|
46
|
+
|
|
47
|
+
export {
|
|
48
|
+
DEFAULT_GATE_AUDIT_MODE,
|
|
49
|
+
DEFAULT_MEMORY_SHADOW_DISPLAY_PRECISION,
|
|
50
|
+
DEFAULT_RULES_COVERAGE_RATIO_DECIMALS,
|
|
51
|
+
LIFECYCLE_GATE_STAGES,
|
|
52
|
+
MAX_IOS_TEST_QUALITY_SAMPLE_FILES,
|
|
53
|
+
MAX_OBSERVED_CODE_PATHS_SAMPLE,
|
|
54
|
+
MAX_SCOPE_SAMPLE_PATHS,
|
|
55
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export const DEFAULT_LIST_SEPARATOR = ', ';
|
|
2
|
+
|
|
3
|
+
export const DEFAULT_MEMORY_SHADOW_CONFIDENCE_BLOCK = 0.9;
|
|
4
|
+
export const DEFAULT_MEMORY_SHADOW_CONFIDENCE_WARN = 0.75;
|
|
5
|
+
export const DEFAULT_MEMORY_SHADOW_CONFIDENCE_WARN_ADVISORY = 0.7;
|
|
6
|
+
export const DEFAULT_MEMORY_SHADOW_CONFIDENCE_ALLOW = 0.65;
|
|
7
|
+
|
|
8
|
+
export const DEFAULT_DEGRADED_MODE_ACTION_BLOCK = 'block' as const;
|
|
9
|
+
export const DEFAULT_DEGRADED_MODE_ACTION_ALLOW = 'allow' as const;
|
|
10
|
+
|
|
11
|
+
export const DEFAULT_RULES_COVERAGE_RATIO_DECIMALS = 6;
|
|
12
|
+
export const DEFAULT_GATE_AUDIT_MODE = 'gate' as const;
|
|
13
|
+
export const DEFAULT_MEMORY_SHADOW_DISPLAY_PRECISION = 2;
|
|
14
|
+
|
|
15
|
+
export const MAX_IOS_TEST_QUALITY_SAMPLE_FILES = 3;
|
|
16
|
+
export const MAX_OBSERVED_CODE_PATHS_SAMPLE = 5;
|
|
17
|
+
export const MAX_SCOPE_SAMPLE_PATHS = 3;
|
|
18
|
+
|
|
19
|
+
export const LIFECYCLE_GATE_STAGES = ['PRE_COMMIT', 'PRE_PUSH', 'CI'] as const;
|
|
@@ -32,13 +32,29 @@ import { createEmptyEvaluationMetrics } from '../evidence/evaluationMetrics';
|
|
|
32
32
|
import { createEmptySnapshotRulesCoverage } from '../evidence/rulesCoverage';
|
|
33
33
|
import { enforceTddBddPolicy } from '../tdd/enforcement';
|
|
34
34
|
import type { TddBddSnapshot } from '../tdd/types';
|
|
35
|
-
import { resolveSkillsEnforcement } from '../policy/skillsEnforcement';
|
|
36
35
|
import { applyTddBddEnforcement } from '../policy/tddBddEnforcement';
|
|
37
36
|
import { collectAiGateRepoPolicyFindings } from './aiGateRepoPolicyFindings';
|
|
38
37
|
import {
|
|
39
38
|
filterFactsByPathPrefixes,
|
|
40
39
|
resolveGateScopePathPrefixesFromEnv,
|
|
41
40
|
} from './filterFactsByPathPrefixes';
|
|
41
|
+
import {
|
|
42
|
+
DEFAULT_MEMORY_SHADOW_DISPLAY_PRECISION,
|
|
43
|
+
DEGRADED_MODE_ACTION_ALLOW,
|
|
44
|
+
DEGRADED_MODE_ACTION_BLOCK,
|
|
45
|
+
DEFAULT_GATE_AUDIT_MODE,
|
|
46
|
+
DEFAULT_RULES_COVERAGE_RATIO_DECIMALS,
|
|
47
|
+
LIFECYCLE_GATE_STAGES,
|
|
48
|
+
MAX_IOS_TEST_QUALITY_SAMPLE_FILES,
|
|
49
|
+
MAX_OBSERVED_CODE_PATHS_SAMPLE,
|
|
50
|
+
MAX_SCOPE_SAMPLE_PATHS,
|
|
51
|
+
LIST_SEPARATOR,
|
|
52
|
+
MEMORY_SHADOW_CONFIDENCE_ALLOW,
|
|
53
|
+
MEMORY_SHADOW_CONFIDENCE_BLOCK,
|
|
54
|
+
MEMORY_SHADOW_CONFIDENCE_WARN,
|
|
55
|
+
MEMORY_SHADOW_CONFIDENCE_WARN_ADVISORY,
|
|
56
|
+
} from '../gate/runPlatformGateConfig';
|
|
57
|
+
import type { Severity } from '../../core/rules/Severity';
|
|
42
58
|
|
|
43
59
|
export type OperationalMemoryShadowRecommendation = {
|
|
44
60
|
recommendedOutcome: 'ALLOW' | 'WARN' | 'BLOCK';
|
|
@@ -80,13 +96,18 @@ const defaultServices: GateServices = {
|
|
|
80
96
|
evidence: new EvidenceService(),
|
|
81
97
|
};
|
|
82
98
|
|
|
99
|
+
const SEVERITY_CRITICAL: Severity = 'CRITICAL';
|
|
100
|
+
const SEVERITY_ERROR: Severity = 'ERROR';
|
|
101
|
+
const SEVERITY_WARN: Severity = 'WARN';
|
|
83
102
|
const buildDefaultMemoryShadowRecommendation = (params: {
|
|
84
103
|
findings: ReadonlyArray<Finding>;
|
|
85
104
|
tddBddSnapshot?: TddBddSnapshot;
|
|
86
105
|
}): OperationalMemoryShadowRecommendation | undefined => {
|
|
87
|
-
const hasCritical = params.findings.some(
|
|
88
|
-
|
|
89
|
-
|
|
106
|
+
const hasCritical = params.findings.some(
|
|
107
|
+
(finding) => finding.severity === SEVERITY_CRITICAL
|
|
108
|
+
);
|
|
109
|
+
const hasError = params.findings.some((finding) => finding.severity === SEVERITY_ERROR);
|
|
110
|
+
const hasWarn = params.findings.some((finding) => finding.severity === SEVERITY_WARN);
|
|
90
111
|
const reasonCodes: string[] = [];
|
|
91
112
|
|
|
92
113
|
if (hasCritical || hasError) {
|
|
@@ -108,27 +129,27 @@ const buildDefaultMemoryShadowRecommendation = (params: {
|
|
|
108
129
|
if (hasCritical || hasError || params.tddBddSnapshot?.status === 'blocked') {
|
|
109
130
|
return {
|
|
110
131
|
recommendedOutcome: 'BLOCK',
|
|
111
|
-
confidence:
|
|
132
|
+
confidence: MEMORY_SHADOW_CONFIDENCE_BLOCK,
|
|
112
133
|
reasonCodes,
|
|
113
134
|
};
|
|
114
135
|
}
|
|
115
136
|
if (hasWarn) {
|
|
116
137
|
return {
|
|
117
138
|
recommendedOutcome: 'WARN',
|
|
118
|
-
confidence:
|
|
139
|
+
confidence: MEMORY_SHADOW_CONFIDENCE_WARN,
|
|
119
140
|
reasonCodes,
|
|
120
141
|
};
|
|
121
142
|
}
|
|
122
143
|
if (params.tddBddSnapshot?.status === 'advisory') {
|
|
123
144
|
return {
|
|
124
145
|
recommendedOutcome: 'WARN',
|
|
125
|
-
confidence:
|
|
146
|
+
confidence: MEMORY_SHADOW_CONFIDENCE_WARN_ADVISORY,
|
|
126
147
|
reasonCodes,
|
|
127
148
|
};
|
|
128
149
|
}
|
|
129
150
|
return {
|
|
130
151
|
recommendedOutcome: 'ALLOW',
|
|
131
|
-
confidence:
|
|
152
|
+
confidence: MEMORY_SHADOW_CONFIDENCE_ALLOW,
|
|
132
153
|
reasonCodes,
|
|
133
154
|
};
|
|
134
155
|
};
|
|
@@ -202,7 +223,10 @@ const toRulesCoverageBlockingFinding = (params: {
|
|
|
202
223
|
}
|
|
203
224
|
const active = params.activeRuleIds.length;
|
|
204
225
|
const evaluated = params.evaluatedRuleIds.length;
|
|
205
|
-
const coverageRatio =
|
|
226
|
+
const coverageRatio =
|
|
227
|
+
active === 0
|
|
228
|
+
? 1
|
|
229
|
+
: Number((evaluated / active).toFixed(DEFAULT_RULES_COVERAGE_RATIO_DECIMALS));
|
|
206
230
|
const unevaluatedRuleIds = [...params.unevaluatedRuleIds].sort().join(', ');
|
|
207
231
|
|
|
208
232
|
return {
|
|
@@ -233,7 +257,7 @@ const toSkillsUnsupportedAutoRulesBlockingFinding = (params: {
|
|
|
233
257
|
return undefined;
|
|
234
258
|
}
|
|
235
259
|
|
|
236
|
-
const unsupportedRuleIdsToken = unsupportedRuleIds.join(
|
|
260
|
+
const unsupportedRuleIdsToken = unsupportedRuleIds.join(LIST_SEPARATOR);
|
|
237
261
|
|
|
238
262
|
return {
|
|
239
263
|
ruleId: 'governance.skills.detector-mapping.incomplete',
|
|
@@ -454,7 +478,9 @@ const toIosTestsQualityBlockingFinding = (params: {
|
|
|
454
478
|
return undefined;
|
|
455
479
|
}
|
|
456
480
|
|
|
457
|
-
const sampleFiles = invalidFiles
|
|
481
|
+
const sampleFiles = invalidFiles
|
|
482
|
+
.slice(0, MAX_IOS_TEST_QUALITY_SAMPLE_FILES)
|
|
483
|
+
.join(' | ');
|
|
458
484
|
return {
|
|
459
485
|
ruleId: 'governance.skills.ios-test-quality.incomplete',
|
|
460
486
|
severity: 'ERROR',
|
|
@@ -480,7 +506,7 @@ const toActiveRulesEmptyForCodeChangesBlockingFinding = (params: {
|
|
|
480
506
|
if (codePaths.length === 0) {
|
|
481
507
|
return undefined;
|
|
482
508
|
}
|
|
483
|
-
const samplePaths = codePaths.slice(0,
|
|
509
|
+
const samplePaths = codePaths.slice(0, MAX_OBSERVED_CODE_PATHS_SAMPLE).join(', ');
|
|
484
510
|
return {
|
|
485
511
|
ruleId: 'governance.rules.active-rule-coverage.empty',
|
|
486
512
|
severity: 'ERROR',
|
|
@@ -564,7 +590,7 @@ const toSkillsScopeComplianceBlockingFinding = (params: {
|
|
|
564
590
|
if (!hasEvaluatedRules) {
|
|
565
591
|
reasons.push(`evaluated_rules_prefix=${prefix} missing`);
|
|
566
592
|
}
|
|
567
|
-
const samplePaths = scopePaths.slice(0,
|
|
593
|
+
const samplePaths = scopePaths.slice(0, MAX_SCOPE_SAMPLE_PATHS).join(', ');
|
|
568
594
|
missingScopes.push(`${scope}{${reasons.join('; ')} sample_paths=[${samplePaths}]}`);
|
|
569
595
|
}
|
|
570
596
|
|
|
@@ -616,13 +642,13 @@ const toDegradedModeFinding = (params: {
|
|
|
616
642
|
if (!degraded?.enabled) {
|
|
617
643
|
return undefined;
|
|
618
644
|
}
|
|
619
|
-
if (degraded.action ===
|
|
645
|
+
if (degraded.action === DEGRADED_MODE_ACTION_BLOCK) {
|
|
620
646
|
return {
|
|
621
647
|
ruleId: 'governance.degraded-mode.blocked',
|
|
622
648
|
severity: 'ERROR',
|
|
623
649
|
code: degraded.code,
|
|
624
650
|
message:
|
|
625
|
-
`Degraded mode is active at ${params.stage} with fail-closed action
|
|
651
|
+
`Degraded mode is active at ${params.stage} with fail-closed action=${DEGRADED_MODE_ACTION_BLOCK}. ` +
|
|
626
652
|
`reason=${degraded.reason} source=${degraded.source}.`,
|
|
627
653
|
filePath: '.pumuki/degraded-mode.json',
|
|
628
654
|
matchedBy: 'DegradedModeGuard',
|
|
@@ -634,7 +660,7 @@ const toDegradedModeFinding = (params: {
|
|
|
634
660
|
severity: 'INFO',
|
|
635
661
|
code: degraded.code,
|
|
636
662
|
message:
|
|
637
|
-
`Degraded mode is active at ${params.stage} with fail-open action
|
|
663
|
+
`Degraded mode is active at ${params.stage} with fail-open action=${DEGRADED_MODE_ACTION_ALLOW}. ` +
|
|
638
664
|
`reason=${degraded.reason} source=${degraded.source}.`,
|
|
639
665
|
filePath: '.pumuki/degraded-mode.json',
|
|
640
666
|
matchedBy: 'DegradedModeGuard',
|
|
@@ -775,7 +801,6 @@ const toCrossPlatformCriticalEnforcementBlockingFinding = (params: {
|
|
|
775
801
|
.sort();
|
|
776
802
|
|
|
777
803
|
if (criticalSkillRules.length === 0) {
|
|
778
|
-
gaps.push(`${platform}{critical_profile_rules=missing}`);
|
|
779
804
|
continue;
|
|
780
805
|
}
|
|
781
806
|
|
|
@@ -819,35 +844,9 @@ const applySkillsFindingEnforcement = (
|
|
|
819
844
|
if (!finding) {
|
|
820
845
|
return undefined;
|
|
821
846
|
}
|
|
822
|
-
const skillsEnforcement = resolveSkillsEnforcement();
|
|
823
|
-
if (skillsEnforcement.blocking) {
|
|
824
|
-
return finding;
|
|
825
|
-
}
|
|
826
847
|
return {
|
|
827
848
|
...finding,
|
|
828
|
-
severity: '
|
|
829
|
-
};
|
|
830
|
-
};
|
|
831
|
-
|
|
832
|
-
const toSoftPreCommitSkillsFinding = (params: {
|
|
833
|
-
finding: Finding | undefined;
|
|
834
|
-
enabled: boolean;
|
|
835
|
-
observedCodePaths: ReadonlyArray<string>;
|
|
836
|
-
}): Finding | undefined => {
|
|
837
|
-
if (!params.finding) {
|
|
838
|
-
return undefined;
|
|
839
|
-
}
|
|
840
|
-
if (!params.enabled || !shouldBlockFromFinding(params.finding)) {
|
|
841
|
-
return params.finding;
|
|
842
|
-
}
|
|
843
|
-
return {
|
|
844
|
-
...params.finding,
|
|
845
|
-
severity: 'WARN',
|
|
846
|
-
code: `${params.finding.code}_SOFT_PRECOMMIT`,
|
|
847
|
-
message:
|
|
848
|
-
`${params.finding.message} ` +
|
|
849
|
-
`Soft-enforced at PRE_COMMIT for low-risk scope (observed_code_paths=${params.observedCodePaths.length}). ` +
|
|
850
|
-
'Strict enforcement remains active at PRE_PUSH/CI.',
|
|
849
|
+
severity: 'ERROR',
|
|
851
850
|
};
|
|
852
851
|
};
|
|
853
852
|
|
|
@@ -869,7 +868,7 @@ export async function runPlatformGate(params: {
|
|
|
869
868
|
...params.dependencies,
|
|
870
869
|
};
|
|
871
870
|
const repoRoot = git.resolveRepoRoot();
|
|
872
|
-
const auditMode = params.auditMode ??
|
|
871
|
+
const auditMode = params.auditMode ?? DEFAULT_GATE_AUDIT_MODE;
|
|
873
872
|
const shouldShortCircuitSdd = params.sddShortCircuit ?? false;
|
|
874
873
|
let sddDecision:
|
|
875
874
|
| Pick<SddDecision, 'allowed' | 'code' | 'message'>
|
|
@@ -1082,15 +1081,12 @@ export async function runPlatformGate(params: {
|
|
|
1082
1081
|
policyTrace: params.policyTrace,
|
|
1083
1082
|
})
|
|
1084
1083
|
: undefined;
|
|
1085
|
-
const degradedModeFinding =
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
policyTrace: params.policyTrace,
|
|
1092
|
-
})
|
|
1093
|
-
: undefined;
|
|
1084
|
+
const degradedModeFinding = LIFECYCLE_GATE_STAGES.includes(params.policy.stage)
|
|
1085
|
+
? toDegradedModeFinding({
|
|
1086
|
+
stage: params.policy.stage,
|
|
1087
|
+
policyTrace: params.policyTrace,
|
|
1088
|
+
})
|
|
1089
|
+
: undefined;
|
|
1094
1090
|
const astIntelligenceDualValidation:
|
|
1095
1091
|
| AstIntelligenceDualValidationResult
|
|
1096
1092
|
| undefined =
|
|
@@ -1120,7 +1116,8 @@ export async function runPlatformGate(params: {
|
|
|
1120
1116
|
);
|
|
1121
1117
|
}
|
|
1122
1118
|
}
|
|
1123
|
-
const degradedModeBlocks =
|
|
1119
|
+
const degradedModeBlocks =
|
|
1120
|
+
params.policyTrace?.degraded?.action === DEGRADED_MODE_ACTION_BLOCK;
|
|
1124
1121
|
const rulesCoverage = coverage
|
|
1125
1122
|
? {
|
|
1126
1123
|
stage: params.policy.stage,
|
|
@@ -1184,7 +1181,11 @@ export async function runPlatformGate(params: {
|
|
|
1184
1181
|
coverage_ratio:
|
|
1185
1182
|
coverage.activeRuleIds.length === 0
|
|
1186
1183
|
? 1
|
|
1187
|
-
: Number(
|
|
1184
|
+
: Number(
|
|
1185
|
+
(
|
|
1186
|
+
coverage.evaluatedRuleIds.length / coverage.activeRuleIds.length
|
|
1187
|
+
).toFixed(DEFAULT_RULES_COVERAGE_RATIO_DECIMALS)
|
|
1188
|
+
),
|
|
1188
1189
|
}
|
|
1189
1190
|
: createEmptySnapshotRulesCoverage(params.policy.stage);
|
|
1190
1191
|
const brownfieldHotspotFindings = dependencies.evaluateBrownfieldHotspotFindings({
|
|
@@ -1209,37 +1210,9 @@ export async function runPlatformGate(params: {
|
|
|
1209
1210
|
const hasNativeBlockingFinding = findings.some(
|
|
1210
1211
|
(finding) => finding.severity === 'ERROR' || finding.severity === 'CRITICAL'
|
|
1211
1212
|
);
|
|
1212
|
-
const
|
|
1213
|
-
const
|
|
1214
|
-
const
|
|
1215
|
-
params.policy.stage === 'PRE_COMMIT'
|
|
1216
|
-
&& preCommitSoftSkillsEnabled
|
|
1217
|
-
&& lowRiskPreCommitWindow
|
|
1218
|
-
&& !sddBlockingFinding
|
|
1219
|
-
&& !degradedModeBlocks
|
|
1220
|
-
&& !shouldBlockFromFinding(policyAsCodeBlockingFinding)
|
|
1221
|
-
&& !shouldBlockFromFinding(effectiveUnsupportedSkillsMappingFinding)
|
|
1222
|
-
&& !shouldBlockFromFinding(coverageBlockingFinding)
|
|
1223
|
-
&& !shouldBlockFromFinding(activeRulesEmptyForCodeChangesFinding)
|
|
1224
|
-
&& !shouldBlockFromFinding(effectiveIosTestsQualityFinding)
|
|
1225
|
-
&& !shouldBlockFromFinding(astIntelligenceDualFinding)
|
|
1226
|
-
&& !hasTddBddBlockingFinding
|
|
1227
|
-
&& !hasNativeBlockingFinding;
|
|
1228
|
-
const effectivePlatformSkillsCoverageFinding = toSoftPreCommitSkillsFinding({
|
|
1229
|
-
finding: effectivePlatformSkillsCoverageInput,
|
|
1230
|
-
enabled: shouldSoftEnforceSkillsFindings,
|
|
1231
|
-
observedCodePaths,
|
|
1232
|
-
});
|
|
1233
|
-
const effectiveCrossPlatformCriticalFinding = toSoftPreCommitSkillsFinding({
|
|
1234
|
-
finding: effectiveCrossPlatformCriticalInput,
|
|
1235
|
-
enabled: shouldSoftEnforceSkillsFindings,
|
|
1236
|
-
observedCodePaths,
|
|
1237
|
-
});
|
|
1238
|
-
const effectiveSkillsScopeComplianceFinding = toSoftPreCommitSkillsFinding({
|
|
1239
|
-
finding: effectiveSkillsScopeComplianceInput,
|
|
1240
|
-
enabled: shouldSoftEnforceSkillsFindings,
|
|
1241
|
-
observedCodePaths,
|
|
1242
|
-
});
|
|
1213
|
+
const effectivePlatformSkillsCoverageFinding = effectivePlatformSkillsCoverageInput;
|
|
1214
|
+
const effectiveCrossPlatformCriticalFinding = effectiveCrossPlatformCriticalInput;
|
|
1215
|
+
const effectiveSkillsScopeComplianceFinding = effectiveSkillsScopeComplianceInput;
|
|
1243
1216
|
const effectiveFindings = sddBlockingFinding
|
|
1244
1217
|
? [
|
|
1245
1218
|
sddBlockingFinding,
|
|
@@ -1390,7 +1363,7 @@ export async function runPlatformGate(params: {
|
|
|
1390
1363
|
if (params.silent !== true) {
|
|
1391
1364
|
process.stdout.write(
|
|
1392
1365
|
`[pumuki][memory-shadow] recommended=${memoryShadowRecommendation.recommendedOutcome}` +
|
|
1393
|
-
` confidence=${memoryShadowRecommendation.confidence.toFixed(
|
|
1366
|
+
` confidence=${memoryShadowRecommendation.confidence.toFixed(DEFAULT_MEMORY_SHADOW_DISPLAY_PRECISION)}` +
|
|
1394
1367
|
` reasons=${memoryShadowRecommendation.reasonCodes.join(',')}\n`
|
|
1395
1368
|
);
|
|
1396
1369
|
}
|
|
@@ -6,47 +6,7 @@ export type SkillsEnforcementResolution = {
|
|
|
6
6
|
blocking: boolean;
|
|
7
7
|
};
|
|
8
8
|
|
|
9
|
-
const SKILLS_ENFORCEMENT_ENV = 'PUMUKI_SKILLS_ENFORCEMENT';
|
|
10
|
-
|
|
11
|
-
const toSkillsEnforcementMode = (
|
|
12
|
-
value: string | undefined
|
|
13
|
-
): SkillsEnforcementMode | null => {
|
|
14
|
-
if (typeof value !== 'string') {
|
|
15
|
-
return null;
|
|
16
|
-
}
|
|
17
|
-
const normalized = value.trim().toLowerCase();
|
|
18
|
-
if (
|
|
19
|
-
normalized === 'strict'
|
|
20
|
-
|| normalized === '1'
|
|
21
|
-
|| normalized === 'true'
|
|
22
|
-
|| normalized === 'yes'
|
|
23
|
-
|| normalized === 'on'
|
|
24
|
-
) {
|
|
25
|
-
return 'strict';
|
|
26
|
-
}
|
|
27
|
-
if (
|
|
28
|
-
normalized === 'advisory'
|
|
29
|
-
|| normalized === 'warn'
|
|
30
|
-
|| normalized === 'warning'
|
|
31
|
-
|| normalized === '0'
|
|
32
|
-
|| normalized === 'false'
|
|
33
|
-
|| normalized === 'no'
|
|
34
|
-
|| normalized === 'off'
|
|
35
|
-
) {
|
|
36
|
-
return 'advisory';
|
|
37
|
-
}
|
|
38
|
-
return null;
|
|
39
|
-
};
|
|
40
|
-
|
|
41
9
|
export const resolveSkillsEnforcement = (): SkillsEnforcementResolution => {
|
|
42
|
-
const modeFromEnv = toSkillsEnforcementMode(process.env[SKILLS_ENFORCEMENT_ENV]);
|
|
43
|
-
if (modeFromEnv) {
|
|
44
|
-
return {
|
|
45
|
-
mode: modeFromEnv,
|
|
46
|
-
source: 'env',
|
|
47
|
-
blocking: modeFromEnv === 'strict',
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
10
|
return {
|
|
51
11
|
mode: 'strict',
|
|
52
12
|
source: 'default',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pumuki",
|
|
3
|
-
"version": "6.3.
|
|
3
|
+
"version": "6.3.133",
|
|
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": {
|