pumuki 6.3.162 → 6.3.164

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 CHANGED
@@ -6,6 +6,13 @@ This project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [6.3.164] - 2026-05-06
10
+
11
+ ### Fixed
12
+
13
+ - **PUMUKI-INC-130 XCTest helpers brownfield:** `trackForMemoryLeaks`/factory helpers that import `XCTest` but do not define `XCTestCase` suites or `test...` methods no longer trigger `skills.ios.critical-test-quality`.
14
+ - **Skills runtime enforcement:** declarative skill registry rules stay visible in coverage metadata without being counted as missing runtime AST detectors; AUTO rules without detector mapping still fail closed.
15
+
9
16
  ## [6.3.143] - 2026-05-05
10
17
 
11
18
  ### Fixed
package/VERSION CHANGED
@@ -1 +1 @@
1
- v6.3.132
1
+ v6.3.164
@@ -669,6 +669,62 @@ final class LoginModelTests: XCTestCase {
669
669
  assert.equal(hasSwiftModernizableXCTestSuiteUsage(missingQualityContract), false);
670
670
  });
671
671
 
672
+ test('detectores Swift Testing excluyen helpers y factories XCTest brownfield sin XCTestCase', () => {
673
+ const helperSource = `
674
+ import XCTest
675
+
676
+ final class AuthTestFactories {
677
+ static func makeToken() -> String {
678
+ "token"
679
+ }
680
+ }
681
+
682
+ func trackForMemoryLeaks(_ instance: AnyObject, file: StaticString = #filePath, line: UInt = #line) {
683
+ addTeardownBlock { _ = instance }
684
+ }
685
+ `;
686
+ const ruralGoHelperSource = `
687
+ import XCTest
688
+
689
+ final class WeakReference<T: AnyObject> {
690
+ weak var value: T?
691
+
692
+ init(_ value: T) {
693
+ self.value = value
694
+ }
695
+ }
696
+
697
+ func trackForMemoryLeaks(
698
+ _ instance: AnyObject,
699
+ testCase: XCTestCase,
700
+ file: StaticString = #filePath,
701
+ line: UInt = #line
702
+ ) {
703
+ nonisolated(unsafe) let reference = makeSUT(instance)
704
+ testCase.addTeardownBlock {
705
+ XCTAssertNil(
706
+ reference.value,
707
+ "Instance should have been deallocated. Potential memory leak.",
708
+ file: file,
709
+ line: line
710
+ )
711
+ }
712
+ }
713
+
714
+ private func makeSUT<T: AnyObject>(_ instance: T) -> WeakReference<T> {
715
+ WeakReference(instance)
716
+ }
717
+ `;
718
+
719
+ assert.equal(hasSwiftLegacyXCTestImportUsage(helperSource), false);
720
+ assert.equal(hasSwiftModernizableXCTestSuiteUsage(helperSource), false);
721
+ assert.equal(hasSwiftXCTestAssertionUsage(helperSource), false);
722
+ assert.equal(hasSwiftLegacyXCTestImportUsage(ruralGoHelperSource), false);
723
+ assert.equal(hasSwiftModernizableXCTestSuiteUsage(ruralGoHelperSource), false);
724
+ assert.equal(hasSwiftXCTestAssertionUsage(ruralGoHelperSource), false);
725
+ assert.equal(hasSwiftXCTUnwrapUsage(ruralGoHelperSource), false);
726
+ });
727
+
672
728
  test('hasSwiftXCTUnwrapUsage detecta XCTUnwrap real y evita strings', () => {
673
729
  const source = `
674
730
  let value = try XCTUnwrap(optionalValue)
@@ -840,11 +840,23 @@ const hasSwiftXCTestOnlyBrownfieldSuiteUsage = (source: string): boolean => {
840
840
  return !hasSwiftTestingImportUsage(source) && !hasSwiftTestingSuiteAttributeUsage(source);
841
841
  };
842
842
 
843
+ const hasSwiftXCTestHelperOrFactoryUsage = (source: string): boolean => {
844
+ return (
845
+ hasSwiftXCTestImportUsage(source) &&
846
+ !hasSwiftXCTestCaseSubclassUsage(source) &&
847
+ !hasSwiftLegacyXCTestMethodUsage(source)
848
+ );
849
+ };
850
+
843
851
  export const hasSwiftLegacyXCTestImportUsage = (source: string): boolean => {
844
852
  if (!hasSwiftXCTestImportUsage(source)) {
845
853
  return false;
846
854
  }
847
855
 
856
+ if (!hasSwiftXCTestCaseSubclassUsage(source) || !hasSwiftLegacyXCTestMethodUsage(source)) {
857
+ return false;
858
+ }
859
+
848
860
  if (hasSwiftLegacyXCTestUiOrPerformanceUsage(source)) {
849
861
  return false;
850
862
  }
@@ -881,6 +893,10 @@ export const hasSwiftXCTestAssertionUsage = (source: string): boolean => {
881
893
  return false;
882
894
  }
883
895
 
896
+ if (hasSwiftXCTestHelperOrFactoryUsage(source)) {
897
+ return false;
898
+ }
899
+
884
900
  if (hasSwiftXCTestOnlyBrownfieldSuiteUsage(source)) {
885
901
  return false;
886
902
  }
@@ -896,6 +912,10 @@ export const hasSwiftXCTUnwrapUsage = (source: string): boolean => {
896
912
  return false;
897
913
  }
898
914
 
915
+ if (hasSwiftXCTestHelperOrFactoryUsage(source)) {
916
+ return false;
917
+ }
918
+
899
919
  if (hasSwiftXCTestOnlyBrownfieldSuiteUsage(source)) {
900
920
  return false;
901
921
  }
@@ -912,6 +932,10 @@ const hasSwiftConfirmationUsage = (source: string): boolean => {
912
932
  };
913
933
 
914
934
  export const hasSwiftWaitForExpectationsUsage = (source: string): boolean => {
935
+ if (hasSwiftXCTestHelperOrFactoryUsage(source)) {
936
+ return false;
937
+ }
938
+
915
939
  const legacyWaitPattern = /\bwait\s*\(\s*for\s*:|\bwaitForExpectations\s*\(/;
916
940
  return collectSwiftFunctionDeclarations(source).some((declaration) => {
917
941
  if (!/\basync\b/.test(declaration.signature)) {
@@ -923,6 +947,10 @@ export const hasSwiftWaitForExpectationsUsage = (source: string): boolean => {
923
947
  };
924
948
 
925
949
  export const hasSwiftLegacyExpectationDescriptionUsage = (source: string): boolean => {
950
+ if (hasSwiftXCTestHelperOrFactoryUsage(source)) {
951
+ return false;
952
+ }
953
+
926
954
  return collectSwiftFunctionDeclarations(source).some((declaration) => {
927
955
  if (!/\basync\b/.test(declaration.signature)) {
928
956
  return false;
@@ -8,6 +8,15 @@ const PACKAGE_ROOT = resolve(__dirname, '..', '..');
8
8
 
9
9
  let cachedCoreSkillsLock: SkillsLockV1 | undefined;
10
10
 
11
+ const writeDebugFallback = (error: unknown): void => {
12
+ if (process.env.PUMUKI_DEBUG !== '1') {
13
+ return;
14
+ }
15
+
16
+ const message = error instanceof Error ? error.message : String(error);
17
+ process.stderr.write(`[pumuki][skills-lock] compile fallback: ${message}\n`);
18
+ };
19
+
11
20
  export const resolveCoreSkillsLockForPackageRoot = (
12
21
  packageRoot: string
13
22
  ): SkillsLockV1 | undefined => {
@@ -20,7 +29,8 @@ export const resolveCoreSkillsLockForPackageRoot = (
20
29
  if (compiledLock.bundles.length > 0) {
21
30
  return compiledLock;
22
31
  }
23
- } catch {
32
+ } catch (error) {
33
+ writeDebugFallback(error);
24
34
  }
25
35
 
26
36
  return loadSkillsLock(packageRoot);
@@ -603,7 +603,6 @@ export const loadSkillsRuleSetForStage = (
603
603
  continue;
604
604
  }
605
605
  if (evaluationMode !== 'AUTO') {
606
- unsupportedDetectorRuleIds.add(compiledRule.id);
607
606
  continue;
608
607
  }
609
608
  stageApplicableAutoRuleIds.add(compiledRule.id);
@@ -655,6 +655,13 @@ const isXCTestSource = (content: string): boolean => {
655
655
  return /\bimport\s+XCTest\b/.test(content) || /\bXCTestCase\b/.test(content);
656
656
  };
657
657
 
658
+ const isXCTestSuiteSource = (content: string): boolean => {
659
+ return (
660
+ /\bclass\s+[A-Za-z_][A-Za-z0-9_]*\s*:\s*XCTestCase\b/.test(content) &&
661
+ /^\s*(?:override\s+)?func\s+test[A-Za-z0-9_]*\s*\(/m.test(content)
662
+ );
663
+ };
664
+
658
665
  const isXCTestUiOrPerformanceCompatibilitySource = (content: string): boolean => {
659
666
  return /\bXCUIApplication\b|\bXCTMetric\b|\bmeasure\s*(?:\(|\{)/.test(content);
660
667
  };
@@ -678,6 +685,9 @@ const toIosTestsQualityBlockingFinding = (params: {
678
685
  if (!isXCTestSource(testFile.content)) {
679
686
  continue;
680
687
  }
688
+ if (!isXCTestSuiteSource(testFile.content)) {
689
+ continue;
690
+ }
681
691
  if (isXCTestUiOrPerformanceCompatibilitySource(testFile.content)) {
682
692
  continue;
683
693
  }
@@ -91,6 +91,15 @@ const fetchJson = async (url: string): Promise<unknown> => {
91
91
  return JSON.parse(text) as unknown;
92
92
  };
93
93
 
94
+ const writeDebugHealthProbeFailure = (error: unknown): void => {
95
+ if (process.env.PUMUKI_DEBUG !== '1') {
96
+ return;
97
+ }
98
+
99
+ const message = error instanceof Error ? error.message : String(error);
100
+ process.stderr.write(`[pumuki-mcp-evidence-stdio] health probe fallback: ${message}\n`);
101
+ };
102
+
94
103
  const startOrReuseEvidenceHttp = async (): Promise<{
95
104
  host: string;
96
105
  port: number;
@@ -108,8 +117,8 @@ const startOrReuseEvidenceHttp = async (): Promise<{
108
117
  if (health.status === 'ok') {
109
118
  return { host, port: requestedPort, route };
110
119
  }
111
- } catch {
112
- // ignored
120
+ } catch (error) {
121
+ writeDebugHealthProbeFailure(error);
113
122
  }
114
123
 
115
124
  const portInUse = await isPortInUse(host, requestedPort);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pumuki",
3
- "version": "6.3.162",
3
+ "version": "6.3.164",
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": {