pumuki 6.3.150 → 6.3.151

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.
@@ -447,6 +447,88 @@ const collectStagedPaths = (git: IGitService, repoRoot: string): ReadonlyArray<s
447
447
  }
448
448
  };
449
449
 
450
+ const toBlockingFindingsForPaths = (
451
+ findings: ReadonlyArray<Finding>,
452
+ paths: ReadonlySet<string>
453
+ ): ReadonlyArray<Finding> => {
454
+ return findings.filter((finding) => {
455
+ if (finding.severity !== 'ERROR' && finding.severity !== 'CRITICAL') {
456
+ return false;
457
+ }
458
+ const path = finding.filePath ? toNormalizedPath(finding.filePath) : '';
459
+ return path.length > 0 && paths.has(path);
460
+ });
461
+ };
462
+
463
+ const buildHeadFactsForPaths = (params: {
464
+ git: IGitService;
465
+ repoRoot: string;
466
+ paths: ReadonlyArray<string>;
467
+ }): ReadonlyArray<Fact> => {
468
+ const facts: Fact[] = [];
469
+ for (const path of params.paths) {
470
+ try {
471
+ const content = params.git.runGit(['show', `HEAD:${path}`], params.repoRoot);
472
+ facts.push({
473
+ kind: 'FileChange',
474
+ path,
475
+ changeType: 'modified',
476
+ source: 'git:staged:HEAD',
477
+ });
478
+ facts.push({
479
+ kind: 'FileContent',
480
+ path,
481
+ content,
482
+ source: 'git:staged:HEAD',
483
+ });
484
+ } catch {
485
+ continue;
486
+ }
487
+ }
488
+ return facts;
489
+ };
490
+
491
+ const toRemediationProgressAllowedFinding = (params: {
492
+ stage: Exclude<GateStage, 'STAGED'>;
493
+ currentBlockingCount: number;
494
+ previousBlockingCount: number;
495
+ paths: ReadonlyArray<string>;
496
+ ruleIds: ReadonlyArray<string>;
497
+ }): Finding => {
498
+ const samplePaths = params.paths.slice(0, MAX_SCOPE_SAMPLE_PATHS).join(LIST_SEPARATOR);
499
+ const sampleRuleIds = params.ruleIds.slice(0, MAX_SCOPE_SAMPLE_PATHS).join(LIST_SEPARATOR);
500
+ return {
501
+ ruleId: 'governance.remediation.progress.allowed',
502
+ severity: 'INFO',
503
+ code: 'REMEDIATION_PROGRESS_ALLOWED',
504
+ message:
505
+ `Remediation progress allowed at ${params.stage}: ` +
506
+ `previous_blocking_findings=${params.previousBlockingCount} ` +
507
+ `current_blocking_findings=${params.currentBlockingCount} ` +
508
+ `paths=[${samplePaths}] remediated_rule_ids=[${sampleRuleIds}]. ` +
509
+ 'Feature work remains blocked until global skills enforcement is complete.',
510
+ filePath: '.ai_evidence.json',
511
+ matchedBy: 'RemediationProgressGuard',
512
+ source: 'remediation-progress',
513
+ blocking: false,
514
+ };
515
+ };
516
+
517
+ const toRemediationProgressAdvisoryFinding = (finding: Finding): Finding => ({
518
+ ...finding,
519
+ severity: 'INFO',
520
+ code:
521
+ finding.code === 'SKILLS_GLOBAL_ENFORCEMENT_INCOMPLETE_CRITICAL'
522
+ ? 'SKILLS_GLOBAL_ENFORCEMENT_INCOMPLETE_REMEDIATION_ADVISORY'
523
+ : finding.code === 'TDD_BDD_EVIDENCE_STALE'
524
+ ? 'TDD_BDD_EVIDENCE_STALE_REMEDIATION_ADVISORY'
525
+ : finding.code,
526
+ message:
527
+ `${finding.message} Remediation progress mode converted this blocker to advisory ` +
528
+ 'because the staged diff reduces existing supported-detector findings and introduces none.',
529
+ blocking: false,
530
+ });
531
+
450
532
  const shouldAugmentStagedSkillsContractFactsWithRepoFacts = (params: {
451
533
  scope: GateScope;
452
534
  facts: ReadonlyArray<Fact>;
@@ -1305,16 +1387,91 @@ export async function runPlatformGate(params: {
1305
1387
  const hasNativeBlockingFinding = findings.some(
1306
1388
  (finding) => finding.severity === 'ERROR' || finding.severity === 'CRITICAL'
1307
1389
  );
1390
+ const stagedCodePaths = stagedPaths.filter((path) => isObservedCodePath(path));
1391
+ const stagedCodePathSet = new Set(stagedCodePaths);
1392
+ const currentBlockingFindingsForStagedPaths = toBlockingFindingsForPaths(
1393
+ findings,
1394
+ stagedCodePathSet
1395
+ );
1396
+ const previousFactsForStagedPaths =
1397
+ isStrictEnforcementStage(params.policy.stage) &&
1398
+ params.scope.kind === 'staged' &&
1399
+ stagedCodePaths.length > 0 &&
1400
+ currentBlockingFindingsForStagedPaths.length === 0
1401
+ ? buildHeadFactsForPaths({
1402
+ git,
1403
+ repoRoot,
1404
+ paths: stagedCodePaths,
1405
+ })
1406
+ : [];
1407
+ const previousEvaluationForStagedPaths =
1408
+ previousFactsForStagedPaths.length > 0
1409
+ ? dependencies.evaluatePlatformGateFindings({
1410
+ facts: previousFactsForStagedPaths,
1411
+ stage: params.policy.stage,
1412
+ repoRoot,
1413
+ })
1414
+ : undefined;
1415
+ const previousBlockingFindingsForStagedPaths = previousEvaluationForStagedPaths
1416
+ ? toBlockingFindingsForPaths(
1417
+ previousEvaluationForStagedPaths.findings,
1418
+ stagedCodePathSet
1419
+ )
1420
+ : [];
1421
+ const remediationProgressFinding =
1422
+ previousBlockingFindingsForStagedPaths.length > currentBlockingFindingsForStagedPaths.length &&
1423
+ currentBlockingFindingsForStagedPaths.length === 0
1424
+ ? toRemediationProgressAllowedFinding({
1425
+ stage: params.policy.stage as Exclude<GateStage, 'STAGED'>,
1426
+ currentBlockingCount: currentBlockingFindingsForStagedPaths.length,
1427
+ previousBlockingCount: previousBlockingFindingsForStagedPaths.length,
1428
+ paths: stagedCodePaths,
1429
+ ruleIds: [
1430
+ ...new Set(
1431
+ previousBlockingFindingsForStagedPaths.map((finding) => finding.ruleId)
1432
+ ),
1433
+ ].sort(),
1434
+ })
1435
+ : undefined;
1436
+ const remediationProgressAllowsGlobalGap = remediationProgressFinding !== undefined;
1437
+ const effectiveTddBddFindings = remediationProgressAllowsGlobalGap
1438
+ ? tddBddEvaluation.findings.map((finding) =>
1439
+ finding.code === 'TDD_BDD_EVIDENCE_STALE'
1440
+ ? toRemediationProgressAdvisoryFinding(finding)
1441
+ : finding
1442
+ )
1443
+ : tddBddEvaluation.findings;
1444
+ const effectiveTddBddSnapshot =
1445
+ remediationProgressAllowsGlobalGap &&
1446
+ tddBddSnapshot?.status === 'blocked' &&
1447
+ tddBddEvaluation.findings.length > 0 &&
1448
+ tddBddEvaluation.findings.every((finding) => finding.code === 'TDD_BDD_EVIDENCE_STALE')
1449
+ ? {
1450
+ ...tddBddSnapshot,
1451
+ status: 'advisory' as const,
1452
+ evidence: {
1453
+ ...tddBddSnapshot.evidence,
1454
+ errors: ['TDD_BDD_EVIDENCE_STALE_REMEDIATION_ADVISORY'],
1455
+ },
1456
+ }
1457
+ : tddBddSnapshot;
1458
+ const effectiveHasTddBddBlockingFinding = effectiveTddBddFindings.some(
1459
+ (finding) => finding.severity === 'ERROR' || finding.severity === 'CRITICAL'
1460
+ );
1308
1461
  const effectivePlatformSkillsCoverageFinding = effectivePlatformSkillsCoverageInput;
1309
1462
  const effectiveCrossPlatformCriticalFinding = effectiveCrossPlatformCriticalInput;
1310
1463
  const effectiveSkillsScopeComplianceFinding = effectiveSkillsScopeComplianceInput;
1464
+ const effectiveUnsupportedDetectorSkillsFindingForOutcome =
1465
+ remediationProgressAllowsGlobalGap && effectiveUnsupportedDetectorSkillsFinding
1466
+ ? toRemediationProgressAdvisoryFinding(effectiveUnsupportedDetectorSkillsFinding)
1467
+ : effectiveUnsupportedDetectorSkillsFinding;
1311
1468
  const effectiveFindings = sddBlockingFinding
1312
1469
  ? [
1313
1470
  sddBlockingFinding,
1314
1471
  ...(degradedModeFinding ? [degradedModeFinding] : []),
1315
1472
  ...(policyAsCodeBlockingFinding ? [policyAsCodeBlockingFinding] : []),
1316
1473
  ...(effectiveUnsupportedSkillsMappingFinding ? [effectiveUnsupportedSkillsMappingFinding] : []),
1317
- ...(effectiveUnsupportedDetectorSkillsFinding ? [effectiveUnsupportedDetectorSkillsFinding] : []),
1474
+ ...(effectiveUnsupportedDetectorSkillsFindingForOutcome ? [effectiveUnsupportedDetectorSkillsFindingForOutcome] : []),
1318
1475
  ...(effectivePlatformSkillsCoverageFinding ? [effectivePlatformSkillsCoverageFinding] : []),
1319
1476
  ...(effectiveCrossPlatformCriticalFinding ? [effectiveCrossPlatformCriticalFinding] : []),
1320
1477
  ...(effectiveSkillsScopeComplianceFinding ? [effectiveSkillsScopeComplianceFinding] : []),
@@ -1323,11 +1480,12 @@ export async function runPlatformGate(params: {
1323
1480
  ...(astIntelligenceDualFinding ? [astIntelligenceDualFinding] : []),
1324
1481
  ...(coverageBlockingFinding ? [coverageBlockingFinding] : []),
1325
1482
  ...brownfieldHotspotFindings,
1326
- ...tddBddEvaluation.findings,
1483
+ ...effectiveTddBddFindings,
1484
+ ...(remediationProgressFinding ? [remediationProgressFinding] : []),
1327
1485
  ...findings,
1328
1486
  ]
1329
1487
  : effectiveUnsupportedSkillsMappingFinding
1330
- || effectiveUnsupportedDetectorSkillsFinding
1488
+ || effectiveUnsupportedDetectorSkillsFindingForOutcome
1331
1489
  || effectivePlatformSkillsCoverageFinding
1332
1490
  || effectiveCrossPlatformCriticalFinding
1333
1491
  || effectiveSkillsScopeComplianceFinding
@@ -1338,12 +1496,13 @@ export async function runPlatformGate(params: {
1338
1496
  || brownfieldHotspotFindings.length > 0
1339
1497
  || policyAsCodeBlockingFinding
1340
1498
  || degradedModeFinding
1341
- || tddBddEvaluation.findings.length > 0
1499
+ || effectiveTddBddFindings.length > 0
1500
+ || remediationProgressFinding
1342
1501
  ? [
1343
1502
  ...(degradedModeFinding ? [degradedModeFinding] : []),
1344
1503
  ...(policyAsCodeBlockingFinding ? [policyAsCodeBlockingFinding] : []),
1345
1504
  ...(effectiveUnsupportedSkillsMappingFinding ? [effectiveUnsupportedSkillsMappingFinding] : []),
1346
- ...(effectiveUnsupportedDetectorSkillsFinding ? [effectiveUnsupportedDetectorSkillsFinding] : []),
1505
+ ...(effectiveUnsupportedDetectorSkillsFindingForOutcome ? [effectiveUnsupportedDetectorSkillsFindingForOutcome] : []),
1347
1506
  ...(effectivePlatformSkillsCoverageFinding ? [effectivePlatformSkillsCoverageFinding] : []),
1348
1507
  ...(effectiveCrossPlatformCriticalFinding ? [effectiveCrossPlatformCriticalFinding] : []),
1349
1508
  ...(effectiveSkillsScopeComplianceFinding ? [effectiveSkillsScopeComplianceFinding] : []),
@@ -1352,20 +1511,22 @@ export async function runPlatformGate(params: {
1352
1511
  ...(astIntelligenceDualFinding ? [astIntelligenceDualFinding] : []),
1353
1512
  ...(coverageBlockingFinding ? [coverageBlockingFinding] : []),
1354
1513
  ...brownfieldHotspotFindings,
1355
- ...tddBddEvaluation.findings,
1514
+ ...effectiveTddBddFindings,
1515
+ ...(remediationProgressFinding ? [remediationProgressFinding] : []),
1356
1516
  ...findings,
1357
1517
  ]
1358
1518
  : brownfieldHotspotFindings.length > 0
1359
1519
  ? [...brownfieldHotspotFindings, ...findings]
1360
1520
  : findings;
1361
1521
  const hasAstIntelligenceBlockingFinding = shouldBlockFromFinding(astIntelligenceDualFinding);
1362
- const decision = dependencies.evaluateGate([...effectiveFindings], params.policy);
1522
+ const gateDecisionFindings = effectiveFindings.filter((finding) => finding.blocking !== false);
1523
+ const decision = dependencies.evaluateGate([...gateDecisionFindings], params.policy);
1363
1524
  const baseGateOutcome =
1364
1525
  sddBlockingFinding ||
1365
1526
  degradedModeBlocks ||
1366
1527
  shouldBlockFromFinding(policyAsCodeBlockingFinding) ||
1367
1528
  shouldBlockFromFinding(effectiveUnsupportedSkillsMappingFinding) ||
1368
- shouldBlockFromFinding(effectiveUnsupportedDetectorSkillsFinding) ||
1529
+ shouldBlockFromFinding(effectiveUnsupportedDetectorSkillsFindingForOutcome) ||
1369
1530
  shouldBlockFromFinding(effectivePlatformSkillsCoverageFinding) ||
1370
1531
  shouldBlockFromFinding(effectiveCrossPlatformCriticalFinding) ||
1371
1532
  shouldBlockFromFinding(effectiveSkillsScopeComplianceFinding) ||
@@ -1374,9 +1535,9 @@ export async function runPlatformGate(params: {
1374
1535
  hasAstIntelligenceBlockingFinding ||
1375
1536
  shouldBlockFromFinding(coverageBlockingFinding) ||
1376
1537
  brownfieldHotspotFindings.some((finding) => shouldBlockFromFinding(finding)) ||
1377
- hasTddBddBlockingFinding
1538
+ effectiveHasTddBddBlockingFinding
1378
1539
  ? 'BLOCK'
1379
- : (decision.outcome === 'PASS' && tddBddSnapshot?.status === 'advisory'
1540
+ : (decision.outcome === 'PASS' && effectiveTddBddSnapshot?.status === 'advisory'
1380
1541
  ? 'WARN'
1381
1542
  : decision.outcome);
1382
1543
  const gateWaiverStage =
@@ -1426,7 +1587,7 @@ export async function runPlatformGate(params: {
1426
1587
  try {
1427
1588
  memoryShadowRecommendation = dependencies.buildMemoryShadowRecommendation({
1428
1589
  findings: findingsWithWaiver,
1429
- ...(tddBddSnapshot ? { tddBddSnapshot } : {}),
1590
+ ...(effectiveTddBddSnapshot ? { tddBddSnapshot: effectiveTddBddSnapshot } : {}),
1430
1591
  });
1431
1592
  } catch (error) {
1432
1593
  const rawReason = error instanceof Error ? error.message : String(error);
@@ -1477,7 +1638,7 @@ export async function runPlatformGate(params: {
1477
1638
  filesScanned,
1478
1639
  evaluationMetrics,
1479
1640
  rulesCoverage,
1480
- ...(tddBddSnapshot ? { tddBdd: tddBddSnapshot } : {}),
1641
+ ...(effectiveTddBddSnapshot ? { tddBdd: effectiveTddBddSnapshot } : {}),
1481
1642
  ...(memoryShadow ? { memoryShadow } : {}),
1482
1643
  repoRoot,
1483
1644
  detectedPlatforms,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pumuki",
3
- "version": "6.3.150",
3
+ "version": "6.3.151",
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": {