pumuki 6.3.174 → 6.3.176
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/VERSION +1 -1
- package/core/facts/detectors/text/ios.test.ts +39 -0
- package/core/facts/detectors/text/ios.ts +7 -0
- package/core/facts/extractHeuristicFacts.ts +1 -0
- package/core/rules/presets/heuristics/ios.test.ts +6 -1
- package/core/rules/presets/heuristics/ios.ts +18 -0
- package/docs/codex-skills/core-data-expert.md +4 -2
- package/docs/rule-packs/ios.md +1 -1
- package/docs/validation/ios-avdlee-parity-matrix.md +1 -1
- package/integrations/config/skillsDetectorRegistry.ts +3 -0
- package/integrations/lifecycle/policyReconcile.ts +24 -3
- package/package.json +1 -1
- package/skills.lock.json +26 -2
- package/vendor/skills/core-data-expert/SKILL.md +4 -2
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
v6.3.
|
|
1
|
+
v6.3.176
|
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
hasSwiftModernizableXCTestSuiteUsage,
|
|
28
28
|
hasSwiftAssumeIsolatedUsage,
|
|
29
29
|
hasSwiftCoreDataLayerLeakUsage,
|
|
30
|
+
hasSwiftSwiftDataLayerLeakUsage,
|
|
30
31
|
hasSwiftNonisolatedUnsafeUsage,
|
|
31
32
|
hasSwiftNSManagedObjectAsyncBoundaryUsage,
|
|
32
33
|
hasSwiftNSManagedObjectBoundaryUsage,
|
|
@@ -618,6 +619,44 @@ struct DetailView: View {
|
|
|
618
619
|
assert.equal(hasSwiftCoreDataLayerLeakUsage(ignored), false);
|
|
619
620
|
});
|
|
620
621
|
|
|
622
|
+
test('hasSwiftSwiftDataLayerLeakUsage detecta SwiftData fuera de infraestructura', () => {
|
|
623
|
+
const source = `
|
|
624
|
+
import SwiftData
|
|
625
|
+
|
|
626
|
+
struct DetailView: View {
|
|
627
|
+
@Environment(\\.modelContext) private var modelContext
|
|
628
|
+
@Query(sort: \\TodoModel.title) private var todos: [TodoModel]
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
final class DetailUseCase {
|
|
632
|
+
private let container: ModelContainer
|
|
633
|
+
private let context: ModelContext
|
|
634
|
+
private let descriptor = FetchDescriptor<TodoModel>()
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
@Model
|
|
638
|
+
final class TodoModel {
|
|
639
|
+
var title: String
|
|
640
|
+
}
|
|
641
|
+
`;
|
|
642
|
+
const ignored = `
|
|
643
|
+
import Foundation
|
|
644
|
+
|
|
645
|
+
struct DetailView: View {
|
|
646
|
+
let selectedID: Todo.ID?
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
final class DetailUseCase {
|
|
650
|
+
func execute() async throws -> [Todo] { [] }
|
|
651
|
+
private let predicate: Predicate<Todo>?
|
|
652
|
+
private let sort = SortDescriptor(\\Todo.title)
|
|
653
|
+
}
|
|
654
|
+
`;
|
|
655
|
+
|
|
656
|
+
assert.equal(hasSwiftSwiftDataLayerLeakUsage(source), true);
|
|
657
|
+
assert.equal(hasSwiftSwiftDataLayerLeakUsage(ignored), false);
|
|
658
|
+
});
|
|
659
|
+
|
|
621
660
|
test('hasSwiftNSManagedObjectStateLeakUsage detecta fugas a SwiftUI state y ViewModels', () => {
|
|
622
661
|
const source = `
|
|
623
662
|
final class TodoEntity: NSManagedObject {}
|
|
@@ -800,6 +800,13 @@ export const hasSwiftCoreDataLayerLeakUsage = (source: string): boolean => {
|
|
|
800
800
|
);
|
|
801
801
|
};
|
|
802
802
|
|
|
803
|
+
export const hasSwiftSwiftDataLayerLeakUsage = (source: string): boolean => {
|
|
804
|
+
return hasSwiftSanitizedRegexMatch(
|
|
805
|
+
source,
|
|
806
|
+
/\bimport\s+SwiftData\b|@\s*Query\b|@\s*Model\b|\b(?:ModelContext|ModelContainer|FetchDescriptor)\b|\.modelContext\b/g
|
|
807
|
+
);
|
|
808
|
+
};
|
|
809
|
+
|
|
803
810
|
export const hasSwiftNSManagedObjectStateLeakUsage = (source: string): boolean => {
|
|
804
811
|
const typeDeclarations = parseSwiftTypeDeclarations(source);
|
|
805
812
|
if (typeDeclarations.length === 0) {
|
|
@@ -630,6 +630,7 @@ const textDetectorRegistry: ReadonlyArray<TextDetectorRegistryEntry> = [
|
|
|
630
630
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftNSManagedObjectBoundaryUsage, ruleId: 'heuristics.ios.core-data.nsmanagedobject-boundary.ast', code: 'HEURISTICS_IOS_CORE_DATA_NSMANAGEDOBJECT_BOUNDARY_AST', message: 'AST heuristic detected NSManagedObject in a shared boundary.' },
|
|
631
631
|
{ platform: 'ios', pathCheck: isIOSSwiftPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftNSManagedObjectAsyncBoundaryUsage, ruleId: 'heuristics.ios.core-data.nsmanagedobject-async-boundary.ast', code: 'HEURISTICS_IOS_CORE_DATA_NSMANAGEDOBJECT_ASYNC_BOUNDARY_AST', message: 'AST heuristic detected NSManagedObject in an async boundary.' },
|
|
632
632
|
{ platform: 'ios', pathCheck: isIOSApplicationOrPresentationPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftCoreDataLayerLeakUsage, ruleId: 'heuristics.ios.core-data.layer-leak.ast', code: 'HEURISTICS_IOS_CORE_DATA_LAYER_LEAK_AST', message: 'AST heuristic detected Core Data APIs leaking into application/presentation code.' },
|
|
633
|
+
{ platform: 'ios', pathCheck: isIOSApplicationOrPresentationPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftSwiftDataLayerLeakUsage, ruleId: 'heuristics.ios.swiftdata.layer-leak.ast', code: 'HEURISTICS_IOS_SWIFTDATA_LAYER_LEAK_AST', message: 'AST heuristic detected SwiftData APIs leaking into application/presentation code.' },
|
|
633
634
|
{ platform: 'ios', pathCheck: isIOSApplicationOrPresentationPath, excludePaths: [isSwiftTestPath], detect: TextIOS.hasSwiftNSManagedObjectStateLeakUsage, ruleId: 'heuristics.ios.core-data.nsmanagedobject-state-leak.ast', code: 'HEURISTICS_IOS_CORE_DATA_NSMANAGEDOBJECT_STATE_LEAK_AST', message: 'AST heuristic detected NSManagedObject leaking into SwiftUI state or a ViewModel.' },
|
|
634
635
|
|
|
635
636
|
// Android
|
|
@@ -3,7 +3,7 @@ import test from 'node:test';
|
|
|
3
3
|
import { iosRules } from './ios';
|
|
4
4
|
|
|
5
5
|
test('iosRules define reglas heurísticas locked para plataforma ios', () => {
|
|
6
|
-
assert.equal(iosRules.length,
|
|
6
|
+
assert.equal(iosRules.length, 43);
|
|
7
7
|
|
|
8
8
|
const ids = iosRules.map((rule) => rule.id);
|
|
9
9
|
assert.deepEqual(ids, [
|
|
@@ -48,6 +48,7 @@ test('iosRules define reglas heurísticas locked para plataforma ios', () => {
|
|
|
48
48
|
'heuristics.ios.core-data.nsmanagedobject-boundary.ast',
|
|
49
49
|
'heuristics.ios.core-data.nsmanagedobject-async-boundary.ast',
|
|
50
50
|
'heuristics.ios.core-data.layer-leak.ast',
|
|
51
|
+
'heuristics.ios.swiftdata.layer-leak.ast',
|
|
51
52
|
'heuristics.ios.core-data.nsmanagedobject-state-leak.ast',
|
|
52
53
|
]);
|
|
53
54
|
|
|
@@ -137,6 +138,10 @@ test('iosRules define reglas heurísticas locked para plataforma ios', () => {
|
|
|
137
138
|
byId.get('heuristics.ios.core-data.layer-leak.ast')?.then.code,
|
|
138
139
|
'HEURISTICS_IOS_CORE_DATA_LAYER_LEAK_AST'
|
|
139
140
|
);
|
|
141
|
+
assert.equal(
|
|
142
|
+
byId.get('heuristics.ios.swiftdata.layer-leak.ast')?.then.code,
|
|
143
|
+
'HEURISTICS_IOS_SWIFTDATA_LAYER_LEAK_AST'
|
|
144
|
+
);
|
|
140
145
|
assert.equal(
|
|
141
146
|
byId.get('heuristics.ios.core-data.nsmanagedobject-state-leak.ast')?.then.code,
|
|
142
147
|
'HEURISTICS_IOS_CORE_DATA_NSMANAGEDOBJECT_STATE_LEAK_AST'
|
|
@@ -743,6 +743,24 @@ export const iosRules: RuleSet = [
|
|
|
743
743
|
code: 'HEURISTICS_IOS_CORE_DATA_LAYER_LEAK_AST',
|
|
744
744
|
},
|
|
745
745
|
},
|
|
746
|
+
{
|
|
747
|
+
id: 'heuristics.ios.swiftdata.layer-leak.ast',
|
|
748
|
+
description: 'Detects SwiftData APIs leaking into iOS application or presentation layers.',
|
|
749
|
+
severity: 'WARN',
|
|
750
|
+
platform: 'ios',
|
|
751
|
+
locked: true,
|
|
752
|
+
when: {
|
|
753
|
+
kind: 'Heuristic',
|
|
754
|
+
where: {
|
|
755
|
+
ruleId: 'heuristics.ios.swiftdata.layer-leak.ast',
|
|
756
|
+
},
|
|
757
|
+
},
|
|
758
|
+
then: {
|
|
759
|
+
kind: 'Finding',
|
|
760
|
+
message: 'AST heuristic detected SwiftData APIs leaking into application/presentation code.',
|
|
761
|
+
code: 'HEURISTICS_IOS_SWIFTDATA_LAYER_LEAK_AST',
|
|
762
|
+
},
|
|
763
|
+
},
|
|
746
764
|
{
|
|
747
765
|
id: 'heuristics.ios.core-data.nsmanagedobject-state-leak.ast',
|
|
748
766
|
description: 'Detects NSManagedObject leaking into SwiftUI state or ViewModel state.',
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
# Core Data Expert
|
|
1
|
+
# Core Data + SwiftData Expert
|
|
2
2
|
|
|
3
|
-
Use this skill when auditing or implementing Core Data code that must remain safe across contexts, layers, and async boundaries.
|
|
3
|
+
Use this skill when auditing or implementing Core Data or SwiftData code that must remain safe across contexts, layers, and async boundaries.
|
|
4
4
|
|
|
5
5
|
## Focus areas
|
|
6
6
|
|
|
7
7
|
- ✅ Prefer `NSManagedObjectID` or mapped DTO/domain models over passing `NSManagedObject` across boundaries.
|
|
8
8
|
- ✅ Avoid returning or accepting `NSManagedObject` in async APIs that cross actor or context boundaries.
|
|
9
9
|
- ✅ Keep Core Data orchestration inside infrastructure or repository layers instead of presentation or application code.
|
|
10
|
+
- ✅ Keep SwiftData orchestration (`ModelContext`, `ModelContainer`, `@Query`, `@Model`) inside infrastructure or repository layers instead of application or presentation code in enterprise Clean Architecture.
|
|
10
11
|
- ✅ Make context ownership explicit and keep merge boundaries controlled.
|
|
11
12
|
- ✅ Treat managed objects as context-scoped references, not as portable domain entities.
|
|
12
13
|
|
|
@@ -21,4 +22,5 @@ Use this skill when auditing or implementing Core Data code that must remain saf
|
|
|
21
22
|
- ❌ Passing `NSManagedObject` through service, use-case, or presentation boundaries.
|
|
22
23
|
- ❌ Async APIs that return `NSManagedObject` directly.
|
|
23
24
|
- ❌ Using `CoreData`, `@FetchRequest`, `managedObjectContext`, or persistence containers directly in application/presentation code.
|
|
25
|
+
- ❌ Using SwiftData contexts, containers, queries, or persistence models directly in application or presentation code when the repo requires Clean Architecture boundaries.
|
|
24
26
|
- ❌ Leaking context-scoped managed objects into SwiftUI state or view models.
|
package/docs/rule-packs/ios.md
CHANGED
|
@@ -49,4 +49,4 @@
|
|
|
49
49
|
- No XCTest-only `XCTestCase` suites that are directly modernizable to `import Testing` + `@Test`, and no mixed `XCTestCase`/`Testing` suites without explicit compatibility reason
|
|
50
50
|
- No `String(format:)` and no `UIScreen.main.bounds` in SwiftUI presentation/layout paths
|
|
51
51
|
- No `ForEach(...indices...)`, no user-facing `contains()` filters instead of `localizedStandardContains()`, and no avoidable `GeometryReader` / `fontWeight(.bold)` patterns in modern SwiftUI paths
|
|
52
|
-
- No Core Data APIs in iOS `Application` / `Presentation` paths, and no `NSManagedObject` escaping into SwiftUI state or ViewModels
|
|
52
|
+
- No Core Data or SwiftData APIs in iOS `Application` / `Presentation` paths, and no `NSManagedObject` escaping into SwiftUI state or ViewModels
|
|
@@ -22,7 +22,7 @@ Artefacto contractual de `phase10-avdlee-parity-closure`.
|
|
|
22
22
|
| `swift-concurrency` | `ios-concurrency-guidelines` | `skills.ios.no-dispatchqueue`, `skills.ios.no-dispatchgroup`, `skills.ios.no-dispatchsemaphore`, `skills.ios.no-operation-queue`, `skills.ios.no-task-detached`, `skills.ios.no-unchecked-sendable`, `skills.ios.no-preconcurrency`, `skills.ios.no-nonisolated-unsafe`, `skills.ios.no-assume-isolated` | `integrations/config/__tests__/iosAvdleeParity.test.ts`, `core/facts/detectors/text/ios.test.ts`, `core/facts/__tests__/extractHeuristicFacts.test.ts`, `core/rules/presets/heuristics/ios.test.ts`, `integrations/config/__tests__/skillsDetectorRegistry.test.ts`, `integrations/config/__tests__/skillsMarkdownRules.test.ts` | `skills.sources.json`, `skills.lock.json`, `integrations/config/skillsCompilerTemplates.ts`, `integrations/config/skillsDetectorRegistry.ts`, `integrations/evidence/buildEvidence.ts` |
|
|
23
23
|
| `swiftui-expert-skill` | `ios-swiftui-expert-guidelines` | `skills.ios.no-observable-object`, `skills.ios.no-legacy-swiftui-observable-wrapper`, `skills.ios.no-passed-value-state-wrapper`, `skills.ios.no-navigation-view`, `skills.ios.no-foreground-color`, `skills.ios.no-corner-radius`, `skills.ios.no-tab-item`, `skills.ios.no-on-tap-gesture`, `skills.ios.no-string-format`, `skills.ios.no-foreach-indices`, `skills.ios.no-contains-user-filter`, `skills.ios.no-geometryreader`, `skills.ios.no-font-weight-bold`, `skills.ios.no-scrollview-shows-indicators`, `skills.ios.no-sheet-is-presented`, `skills.ios.no-legacy-onchange`, `skills.ios.no-uiscreen-main-bounds` | `integrations/config/__tests__/iosAvdleeParity.test.ts`, `core/facts/detectors/text/ios.test.ts`, `core/facts/detectors/text/iosSwiftUiModernizationSnapshot.test.ts`, `core/facts/__tests__/extractHeuristicFacts.test.ts`, `core/rules/presets/heuristics/ios.test.ts`, `integrations/config/__tests__/skillsDetectorRegistry.test.ts`, `integrations/config/__tests__/skillsMarkdownRules.test.ts` | `skills.sources.json`, `skills.lock.json`, `assets/rule-packs/ios-swiftui-modernization-v1.json`, `assets/rule-packs/ios-swiftui-modernization-v2.json`, `integrations/config/skillsCompilerTemplates.ts`, `integrations/config/skillsDetectorRegistry.ts`, `integrations/evidence/buildEvidence.ts` |
|
|
24
24
|
| `swift-testing-expert` | `ios-swift-testing-guidelines` | `skills.ios.prefer-swift-testing`, `skills.ios.no-xctassert`, `skills.ios.no-xctunwrap`, `skills.ios.no-wait-for-expectations`, `skills.ios.no-legacy-expectation-description`, `skills.ios.no-mixed-testing-frameworks` | `integrations/config/__tests__/iosAvdleeParity.test.ts`, `core/facts/detectors/text/ios.test.ts`, `core/facts/__tests__/extractHeuristicFacts.test.ts`, `core/rules/presets/heuristics/ios.test.ts`, `integrations/config/__tests__/skillsDetectorRegistry.test.ts`, `integrations/config/__tests__/skillsMarkdownRules.test.ts` | `skills.sources.json`, `skills.lock.json`, `integrations/config/skillsCompilerTemplates.ts`, `integrations/config/skillsDetectorRegistry.ts`, `integrations/evidence/buildEvidence.ts` |
|
|
25
|
-
| `core-data-expert` | `ios-core-data-guidelines` | `skills.ios.no-nsmanagedobject-boundary`, `skills.ios.no-nsmanagedobject-async-boundary`, `skills.ios.no-core-data-layer-leak`, `skills.ios.no-nsmanagedobject-state-leak` | `integrations/config/__tests__/iosAvdleeParity.test.ts`, `core/facts/detectors/text/ios.test.ts`, `core/facts/__tests__/extractHeuristicFacts.test.ts`, `core/rules/presets/heuristics/ios.test.ts`, `integrations/config/__tests__/skillsDetectorRegistry.test.ts`, `integrations/config/__tests__/skillsMarkdownRules.test.ts` | `skills.sources.json`, `skills.lock.json`, `integrations/config/skillsCompilerTemplates.ts`, `integrations/config/skillsDetectorRegistry.ts`, `integrations/evidence/buildEvidence.ts` |
|
|
25
|
+
| `core-data-expert` | `ios-core-data-guidelines` | `skills.ios.no-nsmanagedobject-boundary`, `skills.ios.no-nsmanagedobject-async-boundary`, `skills.ios.no-core-data-layer-leak`, `skills.ios.no-nsmanagedobject-state-leak`, `skills.ios.no-swiftdata-layer-leak` | `integrations/config/__tests__/iosAvdleeParity.test.ts`, `core/facts/detectors/text/ios.test.ts`, `core/facts/__tests__/extractHeuristicFacts.test.ts`, `core/rules/presets/heuristics/ios.test.ts`, `integrations/config/__tests__/skillsDetectorRegistry.test.ts`, `integrations/config/__tests__/skillsMarkdownRules.test.ts` | `skills.sources.json`, `skills.lock.json`, `integrations/config/skillsCompilerTemplates.ts`, `integrations/config/skillsDetectorRegistry.ts`, `integrations/evidence/buildEvidence.ts` |
|
|
26
26
|
|
|
27
27
|
## Skill absorbida por snapshot
|
|
28
28
|
|
|
@@ -143,6 +143,9 @@ const registryByRuleId: Record<string, SkillsDetectorBinding> = {
|
|
|
143
143
|
'skills.ios.no-core-data-layer-leak': heuristicDetector('ios.core-data.layer-leak', [
|
|
144
144
|
'heuristics.ios.core-data.layer-leak.ast',
|
|
145
145
|
]),
|
|
146
|
+
'skills.ios.no-swiftdata-layer-leak': heuristicDetector('ios.swiftdata.layer-leak', [
|
|
147
|
+
'heuristics.ios.swiftdata.layer-leak.ast',
|
|
148
|
+
]),
|
|
146
149
|
'skills.ios.no-nsmanagedobject-state-leak': heuristicDetector(
|
|
147
150
|
'ios.core-data.nsmanagedobject-state-leak',
|
|
148
151
|
['heuristics.ios.core-data.nsmanagedobject-state-leak.ast']
|
|
@@ -117,6 +117,9 @@ const tryApplyPolicyAutofix = (params: {
|
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
const preWriteStage = params.report.stages.PRE_WRITE;
|
|
120
|
+
const preCommitStage = params.report.stages.PRE_COMMIT;
|
|
121
|
+
const prePushStage = params.report.stages.PRE_PUSH;
|
|
122
|
+
const ciStage = params.report.stages.CI;
|
|
120
123
|
const signatures = {
|
|
121
124
|
PRE_WRITE: createPolicyAsCodeSignature({
|
|
122
125
|
stage: 'PRE_COMMIT',
|
|
@@ -125,9 +128,27 @@ const tryApplyPolicyAutofix = (params: {
|
|
|
125
128
|
hash: preWriteStage.hash,
|
|
126
129
|
version: '1.0',
|
|
127
130
|
}),
|
|
128
|
-
PRE_COMMIT:
|
|
129
|
-
|
|
130
|
-
|
|
131
|
+
PRE_COMMIT: createPolicyAsCodeSignature({
|
|
132
|
+
stage: 'PRE_COMMIT',
|
|
133
|
+
source: toContractSource(preCommitStage.source),
|
|
134
|
+
bundle: preCommitStage.bundle,
|
|
135
|
+
hash: preCommitStage.hash,
|
|
136
|
+
version: '1.0',
|
|
137
|
+
}),
|
|
138
|
+
PRE_PUSH: createPolicyAsCodeSignature({
|
|
139
|
+
stage: 'PRE_PUSH',
|
|
140
|
+
source: toContractSource(prePushStage.source),
|
|
141
|
+
bundle: prePushStage.bundle,
|
|
142
|
+
hash: prePushStage.hash,
|
|
143
|
+
version: '1.0',
|
|
144
|
+
}),
|
|
145
|
+
CI: createPolicyAsCodeSignature({
|
|
146
|
+
stage: 'CI',
|
|
147
|
+
source: toContractSource(ciStage.source),
|
|
148
|
+
bundle: ciStage.bundle,
|
|
149
|
+
hash: ciStage.hash,
|
|
150
|
+
version: '1.0',
|
|
151
|
+
}),
|
|
131
152
|
};
|
|
132
153
|
if (!signatures.PRE_COMMIT || !signatures.PRE_PUSH || !signatures.CI) {
|
|
133
154
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pumuki",
|
|
3
|
-
"version": "6.3.
|
|
3
|
+
"version": "6.3.176",
|
|
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": {
|
package/skills.lock.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": "1.0",
|
|
3
3
|
"compilerVersion": "1.0.0",
|
|
4
|
-
"generatedAt": "2026-05-
|
|
4
|
+
"generatedAt": "2026-05-12T19:46:23.268Z",
|
|
5
5
|
"bundles": [
|
|
6
6
|
{
|
|
7
7
|
"name": "android-guidelines",
|
|
@@ -5644,8 +5644,20 @@
|
|
|
5644
5644
|
"name": "ios-core-data-guidelines",
|
|
5645
5645
|
"version": "1.0.0",
|
|
5646
5646
|
"source": "file:vendor/skills/core-data-expert/SKILL.md",
|
|
5647
|
-
"hash": "
|
|
5647
|
+
"hash": "d91f2cad6499310a4299b39593d47f40a507299a0562c21bc64aad9b5d27c66f",
|
|
5648
5648
|
"rules": [
|
|
5649
|
+
{
|
|
5650
|
+
"id": "skills.ios.guideline.ios-core-data.keep-swiftdata-orchestration-modelcontext-modelcontainer-query-model-i",
|
|
5651
|
+
"description": "Keep SwiftData orchestration (ModelContext, ModelContainer, @Query, @Model) inside infrastructure or repository layers instead of application or presentation code in enterprise Clean Architecture.",
|
|
5652
|
+
"severity": "WARN",
|
|
5653
|
+
"platform": "ios",
|
|
5654
|
+
"sourceSkill": "ios-core-data-guidelines",
|
|
5655
|
+
"sourcePath": "vendor/skills/core-data-expert/SKILL.md",
|
|
5656
|
+
"confidence": "MEDIUM",
|
|
5657
|
+
"locked": true,
|
|
5658
|
+
"evaluationMode": "DECLARATIVE",
|
|
5659
|
+
"origin": "core"
|
|
5660
|
+
},
|
|
5649
5661
|
{
|
|
5650
5662
|
"id": "skills.ios.guideline.ios-core-data.make-context-ownership-explicit-and-keep-merge-boundaries-controlled",
|
|
5651
5663
|
"description": "Make context ownership explicit and keep merge boundaries controlled.",
|
|
@@ -5694,6 +5706,18 @@
|
|
|
5694
5706
|
"evaluationMode": "DECLARATIVE",
|
|
5695
5707
|
"origin": "core"
|
|
5696
5708
|
},
|
|
5709
|
+
{
|
|
5710
|
+
"id": "skills.ios.guideline.ios-core-data.using-swiftdata-contexts-containers-queries-or-persistence-models-dire",
|
|
5711
|
+
"description": "Using SwiftData contexts, containers, queries, or persistence models directly in application or presentation code when the repo requires Clean Architecture boundaries.",
|
|
5712
|
+
"severity": "ERROR",
|
|
5713
|
+
"platform": "ios",
|
|
5714
|
+
"sourceSkill": "ios-core-data-guidelines",
|
|
5715
|
+
"sourcePath": "vendor/skills/core-data-expert/SKILL.md",
|
|
5716
|
+
"confidence": "HIGH",
|
|
5717
|
+
"locked": true,
|
|
5718
|
+
"evaluationMode": "DECLARATIVE",
|
|
5719
|
+
"origin": "core"
|
|
5720
|
+
},
|
|
5697
5721
|
{
|
|
5698
5722
|
"id": "skills.ios.no-core-data-layer-leak",
|
|
5699
5723
|
"description": "Keep Core Data orchestration inside infrastructure or repository layers; avoid Core Data APIs in application or presentation code.",
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
# Core Data Expert
|
|
1
|
+
# Core Data + SwiftData Expert
|
|
2
2
|
|
|
3
|
-
Use this skill when auditing or implementing Core Data code that must remain safe across contexts, layers, and async boundaries.
|
|
3
|
+
Use this skill when auditing or implementing Core Data or SwiftData code that must remain safe across contexts, layers, and async boundaries.
|
|
4
4
|
|
|
5
5
|
## Focus areas
|
|
6
6
|
|
|
7
7
|
- ✅ Prefer `NSManagedObjectID` or mapped DTO/domain models over passing `NSManagedObject` across boundaries.
|
|
8
8
|
- ✅ Avoid returning or accepting `NSManagedObject` in async APIs that cross actor or context boundaries.
|
|
9
9
|
- ✅ Keep Core Data orchestration inside infrastructure or repository layers instead of presentation code.
|
|
10
|
+
- ✅ Keep SwiftData orchestration (`ModelContext`, `ModelContainer`, `@Query`, `@Model`) inside infrastructure or repository layers instead of application or presentation code in enterprise Clean Architecture.
|
|
10
11
|
- ✅ Make context ownership explicit and keep merge boundaries controlled.
|
|
11
12
|
- ✅ Treat managed objects as context-scoped references, not as portable domain entities.
|
|
12
13
|
|
|
@@ -21,3 +22,4 @@ Use this skill when auditing or implementing Core Data code that must remain saf
|
|
|
21
22
|
- ❌ Passing `NSManagedObject` through service, use-case, or presentation boundaries.
|
|
22
23
|
- ❌ Async APIs that return `NSManagedObject` directly.
|
|
23
24
|
- ❌ Leaking context-scoped managed objects into SwiftUI state or view models.
|
|
25
|
+
- ❌ Using SwiftData contexts, containers, queries, or persistence models directly in application or presentation code when the repo requires Clean Architecture boundaries.
|