@mmerterden/multi-agent-pipeline 13.0.0 → 13.2.0
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 +111 -0
- package/package.json +1 -1
- package/pipeline/commands/multi-agent/dev/SKILL.md +21 -0
- package/pipeline/commands/multi-agent/dev-local/SKILL.md +21 -0
- package/pipeline/commands/multi-agent/ios-coding-standard/SKILL.md +257 -0
- package/pipeline/commands/multi-agent/sync/SKILL.md +4 -4
- package/pipeline/multi-agent-refs/component-dispatch.md +40 -7
- package/pipeline/multi-agent-refs/cross-cli-contract.md +3 -3
- package/pipeline/multi-agent-refs/phases/phase-0-init.md +29 -0
- package/pipeline/multi-agent-refs/phases/phase-1-analysis.md +24 -1
- package/pipeline/multi-agent-refs/phases/phase-3-dev.md +32 -0
- package/pipeline/multi-agent-refs/phases/phase-4-review.md +26 -0
- package/pipeline/scripts/phase0-exit-gate.mjs +185 -0
- package/pipeline/skills/shared/core/multi-agent-dev/SKILL.md +21 -0
- package/pipeline/skills/shared/core/multi-agent-dev-local/SKILL.md +21 -0
- package/pipeline/skills/shared/core/multi-agent-ios-coding-standard/SKILL.md +258 -0
- package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +4 -4
- package/pipeline/skills/shared/external/ios-coding-standard/SKILL.md +78 -0
- package/pipeline/skills/shared/external/ios-coding-standard/references/STANDARD.md +445 -0
- package/pipeline/skills/shared/external/ios-coding-standard/references/lint-local.sh +160 -0
- package/pipeline/skills/shared/external/ios-coding-standard/references/rules.yml +1163 -0
- package/pipeline/skills/shared/external/ios-coding-standard/references/swiftlint.draft.yml +371 -0
- package/pipeline/skills/shared/external/ios-simulator/SKILL.md +1 -1
- package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +1 -1
- package/pipeline/skills/shared/external/swiftlint/SKILL.md +1 -1
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
# SwiftLint configuration generated from rules.yml — LOCAL USE ONLY.
|
|
2
|
+
#
|
|
3
|
+
# By decision this is NOT part of the project: no committed .swiftlint.yml, no build phase, no
|
|
4
|
+
# CI job. Run it through ./lint-local.sh, which resolves the placeholders below and keeps the
|
|
5
|
+
# resolved config, the baseline and every report outside the repository.
|
|
6
|
+
#
|
|
7
|
+
# ./lint-local.sh Domains/<Module> --write-baseline # grandfather what exists today
|
|
8
|
+
# ./lint-local.sh Domains/<Module> --strict # then only new violations surface
|
|
9
|
+
#
|
|
10
|
+
# Because there is no CI gate, the ratchet is a habit rather than a wall: run it before opening
|
|
11
|
+
# a PR. That is weaker than a gate and the audit says so — adopting it project-wide stays an
|
|
12
|
+
# open decision, not a forgotten one.
|
|
13
|
+
#
|
|
14
|
+
# Every custom rule identifier IS its rules.yml ID, lowercased, so a CI failure points
|
|
15
|
+
# straight at the registry entry.
|
|
16
|
+
#
|
|
17
|
+
# Placeholders in ((double parens)) are resolved per module by the audit:
|
|
18
|
+
# ((SENSITIVE)) - alternation built from the module's sensitive-data inventory (Phase 2d)
|
|
19
|
+
# ((TRANSIENT)) - the subset the inventory marks required-transient
|
|
20
|
+
# ((SIBLINGS)) - the module registry's other feature module names
|
|
21
|
+
# ((LOGIC)) - the module's logic paths (Domain, Data, Presentation view models)
|
|
22
|
+
|
|
23
|
+
included: []
|
|
24
|
+
excluded:
|
|
25
|
+
- .build
|
|
26
|
+
- "**/Package.swift"
|
|
27
|
+
- Tests/**/*Snapshot*
|
|
28
|
+
- DerivedData
|
|
29
|
+
- "**/Generated"
|
|
30
|
+
- "**/*.generated.swift"
|
|
31
|
+
|
|
32
|
+
analyzer_rules:
|
|
33
|
+
- unused_declaration
|
|
34
|
+
- unused_import
|
|
35
|
+
|
|
36
|
+
opt_in_rules:
|
|
37
|
+
- file_header
|
|
38
|
+
- force_unwrapping
|
|
39
|
+
- implicitly_unwrapped_optional
|
|
40
|
+
# missing_docs is deliberately NOT enabled: this project's own rule is "no comment unless it
|
|
41
|
+
# earns its place", and a doc-per-public-declaration mandate manufactures exactly the
|
|
42
|
+
# restate-the-signature noise that rule exists to prevent.
|
|
43
|
+
- prefer_self_in_static_references
|
|
44
|
+
- empty_count
|
|
45
|
+
- first_where
|
|
46
|
+
- last_where
|
|
47
|
+
- redundant_nil_coalescing
|
|
48
|
+
- unowned_variable_capture
|
|
49
|
+
- weak_delegate
|
|
50
|
+
- private_outlet
|
|
51
|
+
- overridden_super_call
|
|
52
|
+
- prohibited_super_call
|
|
53
|
+
|
|
54
|
+
disabled_rules:
|
|
55
|
+
# WARN-02 owns TODO policy (untagged only); the built-in flags every TODO — pure noise.
|
|
56
|
+
- todo
|
|
57
|
+
- line_length
|
|
58
|
+
- trailing_comma
|
|
59
|
+
- opening_brace
|
|
60
|
+
- statement_position
|
|
61
|
+
# SwiftUI's own presentation API is `sheet(isPresented:onDismiss:) { content }` — a closure
|
|
62
|
+
# argument plus a trailing view builder. The rule fires on Apple's documented shape, so
|
|
63
|
+
# obeying it would make every sheet read worse than the framework intends.
|
|
64
|
+
- multiple_closures_with_trailing_closure
|
|
65
|
+
|
|
66
|
+
# READ-03
|
|
67
|
+
file_length:
|
|
68
|
+
warning: 400
|
|
69
|
+
error: 900
|
|
70
|
+
type_body_length:
|
|
71
|
+
warning: 350
|
|
72
|
+
error: 800
|
|
73
|
+
function_body_length:
|
|
74
|
+
warning: 40
|
|
75
|
+
error: 100
|
|
76
|
+
|
|
77
|
+
# READ-07 — the component names are bound to an external design mapping and cannot be
|
|
78
|
+
# shortened, so the ceiling reflects the codebase rather than SwiftLint's 40-char default.
|
|
79
|
+
type_name:
|
|
80
|
+
max_length:
|
|
81
|
+
warning: 62
|
|
82
|
+
error: 75
|
|
83
|
+
|
|
84
|
+
# STRUCT-01 — a pure constants namespace groups by nesting (`AppConstant.DeepLink.Path`);
|
|
85
|
+
# two levels is the depth that grouping needs, and nothing deeper is allowed.
|
|
86
|
+
nesting:
|
|
87
|
+
type_level: 2
|
|
88
|
+
|
|
89
|
+
identifier_name:
|
|
90
|
+
min_length: 2
|
|
91
|
+
excluded: [id, on, up, x, y]
|
|
92
|
+
cyclomatic_complexity:
|
|
93
|
+
warning: 10
|
|
94
|
+
|
|
95
|
+
# READ-09 — the built-in takes no per-rule `excluded`; Package.swift is excluded globally below
|
|
96
|
+
file_header:
|
|
97
|
+
# Author is the FULL git identity, department included — "NAME - <Department> Mudurlugu".
|
|
98
|
+
# A bare name is not enough: it does not say which team owns the file.
|
|
99
|
+
required_pattern: '\A//\n// .*\.swift\n// .*\n//(?:\n//.*)*?\n// Created by .+ - .+ on \d{2}\.\d{2}\.\d{4}\.\n//\n'
|
|
100
|
+
|
|
101
|
+
# VIS-04 — only the module's public surface must be documented
|
|
102
|
+
# An extension is a grouping, not an API — its members carry the docs. Requiring a comment on
|
|
103
|
+
# the `extension` line itself only produces restatements of the MARK above it. A memberwise
|
|
104
|
+
# init is likewise self-describing.
|
|
105
|
+
missing_docs:
|
|
106
|
+
warning: [public, open]
|
|
107
|
+
excludes_extensions: true
|
|
108
|
+
excludes_inherited_types: true
|
|
109
|
+
excludes_trivial_init: true
|
|
110
|
+
|
|
111
|
+
custom_rules:
|
|
112
|
+
|
|
113
|
+
# ── SEC ─────────────────────────────────────────────────────────────────
|
|
114
|
+
sec_01_no_plaintext_persistence:
|
|
115
|
+
name: "SEC-01 sensitive value in unprotected storage"
|
|
116
|
+
regex: '(UserDefaults|NSUbiquitousKeyValueStore)[^\n]*\b((SENSITIVE))\b'
|
|
117
|
+
message: "Sensitive data must not live in UserDefaults. Walk persistence_decision: transient -> memory only; survives restart -> Keychain with an explicit accessibility class."
|
|
118
|
+
severity: error
|
|
119
|
+
|
|
120
|
+
sec_01_no_over_persistence:
|
|
121
|
+
name: "SEC-01 transient value being persisted"
|
|
122
|
+
regex: '(credentialStore|keychain|UserDefaults|FileManager)[^\n]*\b((TRANSIENT))\b'
|
|
123
|
+
message: "This value is required-transient. Persisting it — Keychain included — creates a cleanup obligation with no owner. Hold it in the flow's model and drop it."
|
|
124
|
+
severity: error
|
|
125
|
+
|
|
126
|
+
sec_01_keychain_sync:
|
|
127
|
+
name: "SEC-01 keychain item allowed to sync"
|
|
128
|
+
regex: 'kSecAttrSynchronizable[^\n]*(kCFBooleanTrue|true)'
|
|
129
|
+
message: "Credential keychain items must not sync to iCloud."
|
|
130
|
+
severity: error
|
|
131
|
+
|
|
132
|
+
sec_01_keychain_accessibility_missing:
|
|
133
|
+
name: "SEC-01 keychain write without an accessibility class"
|
|
134
|
+
regex: 'kSecClassGenericPassword(?:(?!kSecAttrAccessible)[\s\S]){0,400}SecItemAdd'
|
|
135
|
+
message: "Declare kSecAttrAccessible explicitly — device-only unless there is a documented reason."
|
|
136
|
+
severity: error
|
|
137
|
+
|
|
138
|
+
sec_02_hardcoded_secret:
|
|
139
|
+
name: "SEC-02 hardcoded secret"
|
|
140
|
+
regex: '(?i)\b(api[_-]?key|secret|password|passphrase|bearer|private[_-]?key|client[_-]?secret)\b\s*[:=]\s*"[^"]{8,}"'
|
|
141
|
+
message: "Anything committed is already leaked. Inject configuration at build or runtime."
|
|
142
|
+
severity: error
|
|
143
|
+
|
|
144
|
+
sec_03_no_print:
|
|
145
|
+
name: "SEC-03 print()"
|
|
146
|
+
regex: '(?<![\w.])print\('
|
|
147
|
+
message: "Use the module's Logger. print() reaches the device log unredacted."
|
|
148
|
+
severity: error
|
|
149
|
+
|
|
150
|
+
sec_03_sensitive_in_log:
|
|
151
|
+
name: "SEC-03 sensitive value interpolated into a log"
|
|
152
|
+
regex: '(logger|log|os_log)[^\n]*\\\([^)]*\b((SENSITIVE))\b'
|
|
153
|
+
message: "Never log this class of value. If it must appear, hash or truncate it and mark the interpolation private."
|
|
154
|
+
severity: error
|
|
155
|
+
|
|
156
|
+
sec_03_public_interpolation:
|
|
157
|
+
name: "SEC-03 log interpolation forced public"
|
|
158
|
+
regex: 'privacy:\s*\.public'
|
|
159
|
+
message: "Public interpolation is opt-in per value and must be provably non-sensitive. Justify with a standard:exception marker."
|
|
160
|
+
severity: warning
|
|
161
|
+
|
|
162
|
+
sec_03_raw_body_log:
|
|
163
|
+
name: "SEC-03 raw request/response body logged"
|
|
164
|
+
regex: '(logger|log|os_log|debugPrint)[^\n]*\\\([^)]*\b(response|request|body|payload|data)\b\s*\)'
|
|
165
|
+
message: "Never log a raw request or response body."
|
|
166
|
+
severity: error
|
|
167
|
+
|
|
168
|
+
sec_04_insecure_scheme:
|
|
169
|
+
name: "SEC-04 http:// literal"
|
|
170
|
+
regex: '"http://(?!localhost|127\.0\.0\.1)'
|
|
171
|
+
message: "HTTPS only. An ATS exception needs a written reason and an expiry."
|
|
172
|
+
severity: error
|
|
173
|
+
excluded: ".*/Tests/.*"
|
|
174
|
+
|
|
175
|
+
sec_09_commented_out_compilation_condition:
|
|
176
|
+
name: "SEC-09 compilation condition commented out"
|
|
177
|
+
# [ \t]* not \s* — \s matches newlines, so "//" ending a file header plus a real
|
|
178
|
+
# "#if" two lines below would match as one commented-out directive.
|
|
179
|
+
regex: '^[ \t]*//[ \t]*#(if|endif|else)\b'
|
|
180
|
+
message: "A commented-out #if DEBUG is not a guard — the code inside it ships. Restore the directive or delete the code."
|
|
181
|
+
severity: error
|
|
182
|
+
|
|
183
|
+
# ── TEST ────────────────────────────────────────────────────────────────
|
|
184
|
+
test_01_environment_reached_for:
|
|
185
|
+
name: "TEST-01 environment reached for instead of injected"
|
|
186
|
+
regex: '\b(Date\(\)|UUID\(\)|Locale\.current|TimeZone\.current|Calendar\.current|\.random\(in:)'
|
|
187
|
+
message: "Inject time, randomness, identifiers and locale. A type that reaches for them is untestable by construction."
|
|
188
|
+
severity: warning
|
|
189
|
+
included: ((LOGIC))
|
|
190
|
+
|
|
191
|
+
test_03_singleton_in_logic:
|
|
192
|
+
name: "TEST-03 singleton access in the logic layer"
|
|
193
|
+
regex: '\b\w+\.shared\b'
|
|
194
|
+
message: "Resolve at the boundary (init / DI), not inline at the call site."
|
|
195
|
+
severity: warning
|
|
196
|
+
included: ((LOGIC))
|
|
197
|
+
|
|
198
|
+
test_05_unstructured_task:
|
|
199
|
+
name: "TEST-05 unstructured Task in logic"
|
|
200
|
+
regex: '(?<!await )\bTask\s*\{'
|
|
201
|
+
message: "An unowned task outlives its screen. Give it an owner and a cancellation story, or restructure."
|
|
202
|
+
severity: warning
|
|
203
|
+
included: ((LOGIC))
|
|
204
|
+
|
|
205
|
+
test_05_sleep_in_test:
|
|
206
|
+
name: "TEST-05 sleep in a test"
|
|
207
|
+
regex: '\b(Thread\.sleep|usleep)\(|(?<![.\w])sleep\('
|
|
208
|
+
message: "Use an expectation or an injected clock."
|
|
209
|
+
severity: error
|
|
210
|
+
|
|
211
|
+
# ── MOD ─────────────────────────────────────────────────────────────────
|
|
212
|
+
mod_01_no_sibling_import:
|
|
213
|
+
name: "MOD-01 feature module importing a sibling feature"
|
|
214
|
+
regex: '^import\s+((SIBLINGS))\b'
|
|
215
|
+
message: "A feature module never imports another feature module. Route it through the seam layer."
|
|
216
|
+
severity: error
|
|
217
|
+
|
|
218
|
+
# ── NAME ────────────────────────────────────────────────────────────────
|
|
219
|
+
name_01_output_handler:
|
|
220
|
+
name: "NAME-01 handler named output"
|
|
221
|
+
regex: '\b(var|let)\s+output\s*:|\boutput\s*:\s*\('
|
|
222
|
+
message: "The navigation handler has one name across the module."
|
|
223
|
+
severity: error
|
|
224
|
+
|
|
225
|
+
name_02_transport_in_presentation:
|
|
226
|
+
name: "NAME-02 transport type in the presentation layer"
|
|
227
|
+
regex: '\b\w+Dto\b'
|
|
228
|
+
message: "Transport suffixes stop at the data layer; map into our own model."
|
|
229
|
+
severity: error
|
|
230
|
+
included: ".*/Presentation/.*"
|
|
231
|
+
|
|
232
|
+
# ── VIS ─────────────────────────────────────────────────────────────────
|
|
233
|
+
vis_01_non_final_class:
|
|
234
|
+
name: "VIS-01 non-final class"
|
|
235
|
+
regex: '^\s*(public\s+|internal\s+|fileprivate\s+|private\s+)?class\s+(?!func)'
|
|
236
|
+
message: "Classes are final unless a real subclass exists in the module."
|
|
237
|
+
severity: warning
|
|
238
|
+
|
|
239
|
+
# ── CONC ────────────────────────────────────────────────────────────────
|
|
240
|
+
# Production code only. A test double is constructed inside one test and mutated by that
|
|
241
|
+
# test's single task, so the hatch carries no concurrency risk there — flagging every spy
|
|
242
|
+
# would bury the production hits that do matter.
|
|
243
|
+
conc_03_escape_hatch:
|
|
244
|
+
name: "CONC-03 concurrency escape hatch"
|
|
245
|
+
regex: '(@preconcurrency|nonisolated\(unsafe\)|@unchecked\s+Sendable)'
|
|
246
|
+
included: ".*/Sources/.*"
|
|
247
|
+
message: "Migration tool, not a design tool. Add a standard:exception marker with a removal condition — these are counted."
|
|
248
|
+
severity: warning
|
|
249
|
+
|
|
250
|
+
# SVC-07 — a repository protocol method names the service it calls. The legitimate
|
|
251
|
+
# exceptions (variants over one service, no endpoint yet) are meant to surface here and be
|
|
252
|
+
# answered with a standard:exception marker, not to be silently allowed by the pattern.
|
|
253
|
+
svc_07_service_named_method:
|
|
254
|
+
name: "SVC-07 repository method not named after its service"
|
|
255
|
+
regex: '^\s*func (?!send)[a-z]\w*\('
|
|
256
|
+
included: ".*RepositoryProtocol\\.swift"
|
|
257
|
+
message: "Name it `send<ServiceName>` (check-open-status -> sendCheckOpenStatus), or mark it standard:exception(SVC-07) with the reason."
|
|
258
|
+
severity: warning
|
|
259
|
+
|
|
260
|
+
# SVC-08 — arithmetic or a policy default inside a mapper. Optional lowering (`?? ""`,
|
|
261
|
+
# `?? false`, `?? []`, `?? nil`) is deliberately not matched; a literal number or a division is.
|
|
262
|
+
svc_08_rule_in_mapper:
|
|
263
|
+
name: "SVC-08 calculation or policy default inside a mapper"
|
|
264
|
+
regex: '(\s/\s*\d|\*\s*\d{2,}|\bmax\(|\bmin\(|\?\?\s*\d{2,}\b)'
|
|
265
|
+
included: ".*Mapper[^/]*\\.swift"
|
|
266
|
+
message: "A mapper moves values. Carry the wire value and do the arithmetic, clamp or default in the view model."
|
|
267
|
+
severity: warning
|
|
268
|
+
|
|
269
|
+
# READ-04b — a component file under Presentation/Components must carry a preview. Reported
|
|
270
|
+
# per file that declares a View and has no #Preview.
|
|
271
|
+
# READ-04b is NOT a swiftlint rule: a regex matches a LINE, and "this file has no #Preview"
|
|
272
|
+
# is a statement about the whole file. Matching `struct X: View {` under Components/ flags
|
|
273
|
+
# every component, previewed or not — 25 false positives on first run. The check lives in the
|
|
274
|
+
# standard's structural pass instead (component files vs files containing #Preview).
|
|
275
|
+
|
|
276
|
+
# PLAT-01 — raw SwiftUI presentation in a feature module. The app ships an OS-independent
|
|
277
|
+
# wrapper; the system API drifts with every iOS release (the iOS 26 partial-detent inset).
|
|
278
|
+
plat_01_raw_presentation:
|
|
279
|
+
name: "PLAT-01 raw system presentation instead of the app's sheet"
|
|
280
|
+
regex: '(?<![\w.])\.sheet\('
|
|
281
|
+
included: ".*/Sources/.*"
|
|
282
|
+
excluded_match_kinds: [comment, doccomment]
|
|
283
|
+
message: "Use the app's own sheet wrapper. System .sheet only for OS-owned surfaces (share, Siri, photo picker) — mark those standard:exception(PLAT-01)."
|
|
284
|
+
severity: warning
|
|
285
|
+
|
|
286
|
+
# PLAT-03 — an asset URL on someone else's host.
|
|
287
|
+
plat_03_third_party_asset_host:
|
|
288
|
+
name: "PLAT-03 asset URL on a third-party host"
|
|
289
|
+
regex: 'https?://(?!([\w.-]*\.)?(example\.com|cdn\.example\.com))[\w.-]+/[^"]*\.(png|jpg|jpeg|svg|webp|gif)'
|
|
290
|
+
excluded: ".*/Tests/.*"
|
|
291
|
+
message: "Assets come from the app's own CDN, and the URL belongs in the module's constants namespace."
|
|
292
|
+
severity: error
|
|
293
|
+
|
|
294
|
+
conc_04_legacy_concurrency:
|
|
295
|
+
name: "CONC-04 GCD layered onto async"
|
|
296
|
+
regex: '\b(DispatchQueue\.(main|global)|DispatchSemaphore|DispatchGroup)\b'
|
|
297
|
+
message: "One concurrency model. Structured concurrency already expresses this."
|
|
298
|
+
severity: warning
|
|
299
|
+
included: ((LOGIC))
|
|
300
|
+
|
|
301
|
+
# ── READ / SAFE ─────────────────────────────────────────────────────────
|
|
302
|
+
read_02_ai_attribution:
|
|
303
|
+
name: "READ-02 AI or tool attribution"
|
|
304
|
+
regex: '(?i)(generated by (claude|copilot|ai)|🤖 generated|co-authored-by:.*(claude|anthropic|copilot))'
|
|
305
|
+
message: "No AI or tool attribution in source, commits or PRs."
|
|
306
|
+
severity: error
|
|
307
|
+
|
|
308
|
+
read_08_raw_hex_color:
|
|
309
|
+
name: "READ-08 raw hex color"
|
|
310
|
+
regex: 'Color\(hex:\s*"|UIColor\(red:'
|
|
311
|
+
message: "Use the design token namespaces."
|
|
312
|
+
severity: error
|
|
313
|
+
|
|
314
|
+
read_08_raw_font:
|
|
315
|
+
name: "READ-08 raw font"
|
|
316
|
+
regex: '\.font\(\s*\.(system|custom)'
|
|
317
|
+
message: "Use the typography tokens."
|
|
318
|
+
severity: error
|
|
319
|
+
|
|
320
|
+
safe_02_ad_hoc_dateformatter:
|
|
321
|
+
name: "SAFE-02 ad-hoc DateFormatter on a service boundary"
|
|
322
|
+
regex: 'DateFormatter\((?:(?!timeZone)[\s\S]){0,300}?(request|Request|payload|dto|Dto)'
|
|
323
|
+
message: "A calendar day sent to a service shifts a day in the device timezone. Use the shared calendar-day helper."
|
|
324
|
+
severity: error
|
|
325
|
+
included: ".*/(Mapper|Data|Repository)/.*"
|
|
326
|
+
|
|
327
|
+
# ── A11Y ────────────────────────────────────────────────────────────────
|
|
328
|
+
a11y_05_absolute_edge:
|
|
329
|
+
name: "A11Y-05 left/right instead of leading/trailing"
|
|
330
|
+
regex: '\.(leftView|rightView)|alignment:\s*\.(left|right)\b|\.padding\(\.(left|right)'
|
|
331
|
+
message: "Use leading/trailing so RTL mirrors."
|
|
332
|
+
severity: error
|
|
333
|
+
|
|
334
|
+
# ── PERF ────────────────────────────────────────────────────────────────
|
|
335
|
+
perf_02_index_as_identity:
|
|
336
|
+
name: "PERF-02 index used as list identity"
|
|
337
|
+
regex: 'ForEach\([^)]*\.indices'
|
|
338
|
+
message: "Use a stable identity; index-as-id breaks diffing and reuse."
|
|
339
|
+
severity: warning
|
|
340
|
+
|
|
341
|
+
perf_04_formatter_per_render:
|
|
342
|
+
name: "PERF-04 formatter constructed per render"
|
|
343
|
+
regex: '(DateFormatter|NumberFormatter|RelativeDateTimeFormatter)\(\)'
|
|
344
|
+
message: "Hoist it out of the render path — construction is expensive and repeats every update."
|
|
345
|
+
severity: warning
|
|
346
|
+
included: ".*(View|Scene)\\.swift"
|
|
347
|
+
|
|
348
|
+
# ── DEPR / WARN ─────────────────────────────────────────────────────────
|
|
349
|
+
depr_02_deprecation_without_replacement:
|
|
350
|
+
name: "DEPR-02 deprecation without a stated replacement"
|
|
351
|
+
regex: '@available\([^)]*deprecated(?![^)]*message:)[^)]*\)'
|
|
352
|
+
message: "A deprecation without a replacement is a complaint, not a migration. Say what to use instead."
|
|
353
|
+
severity: error
|
|
354
|
+
|
|
355
|
+
depr_04_stale_availability_gate:
|
|
356
|
+
name: "DEPR-04 availability gate at or below the deployment target"
|
|
357
|
+
regex: '#available\(iOS 1[0-7](\.[0-9]+)?'
|
|
358
|
+
message: "Dead branch: the package already requires this version. Remove the gate."
|
|
359
|
+
severity: warning
|
|
360
|
+
|
|
361
|
+
warn_02_untagged_todo:
|
|
362
|
+
name: "WARN-02 TODO without an owner or ticket"
|
|
363
|
+
regex: '//\s*TODO(?!\[)'
|
|
364
|
+
message: "Tag it — // TODO[TICKET-123]: … — or it is a note to someone who has left."
|
|
365
|
+
severity: warning
|
|
366
|
+
|
|
367
|
+
warn_02_fixme:
|
|
368
|
+
name: "WARN-02 FIXME in source"
|
|
369
|
+
regex: '//\s*(FIXME|HACK|XXX)\b'
|
|
370
|
+
message: "Known-broken belongs in the tracker, not the source."
|
|
371
|
+
severity: warning
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: ios-simulator
|
|
3
|
-
description: "Manages iOS Simulator devices and tests app
|
|
3
|
+
description: "Manages iOS Simulator devices and tests app behaviour with xcrun simctl: device lifecycle, app install and launch, push notification and location simulation, privacy permission grants, deep links via openurl, status bar overrides, screenshot and video capture, os_log streaming, app container paths, and targetEnvironment(simulator) checks. Use when managing simulator devices, testing push without APNs, simulating GPS, resetting permissions, capturing screens from the command line, streaming device logs, or debugging simulator boot and CoreSimulator failures."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# iOS Simulator
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: swift-api-design-guidelines
|
|
3
|
-
description: "
|
|
3
|
+
description: "Swift API Design Guidelines: clarity at the point of use, naming for readability over brevity, argument labels and prepositional phrases, method vs property choice, mutating/nonmutating pairs, protocol naming, generic parameter names, and documentation comment conventions. Use when naming a type, method or parameter, deciding between a method and a property, writing doc comments, or reviewing an API surface for consistency with the standard library."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Swift API Design Guidelines
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: swiftlint
|
|
3
|
-
description: "Configures and enforces SwiftLint
|
|
3
|
+
description: "Configures and enforces SwiftLint via build tool plugins, run scripts and CI: .swiftlint.yml rule sets, analyzer rules, baselines, autocorrect, swiftlint:disable suppressions, reporter formats, strict and lenient modes, SwiftLintBuildToolPlugin, Xcode run script phases, and rollout strategies for an existing codebase. Use when setting up SwiftLint, configuring or suppressing rules, creating a baseline, choosing plugin vs run script, or wiring it into CI."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# SwiftLint
|