@coralai/sps-cli 0.42.0 → 0.44.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.
Files changed (147) hide show
  1. package/README.md +59 -4
  2. package/dist/commands/consoleCommand.d.ts +2 -0
  3. package/dist/commands/consoleCommand.d.ts.map +1 -0
  4. package/dist/commands/consoleCommand.js +129 -0
  5. package/dist/commands/consoleCommand.js.map +1 -0
  6. package/dist/commands/projectInit.d.ts.map +1 -1
  7. package/dist/commands/projectInit.js +40 -53
  8. package/dist/commands/projectInit.js.map +1 -1
  9. package/dist/commands/setup.d.ts.map +1 -1
  10. package/dist/commands/setup.js +14 -2
  11. package/dist/commands/setup.js.map +1 -1
  12. package/dist/commands/skillCommand.d.ts +2 -0
  13. package/dist/commands/skillCommand.d.ts.map +1 -0
  14. package/dist/commands/skillCommand.js +235 -0
  15. package/dist/commands/skillCommand.js.map +1 -0
  16. package/dist/console-assets/assets/index-Bhd2f9AP.js +125 -0
  17. package/dist/console-assets/assets/index-bsAN2a12.css +1 -0
  18. package/dist/console-assets/index.html +16 -0
  19. package/dist/console-server/index.d.ts +29 -0
  20. package/dist/console-server/index.d.ts.map +1 -0
  21. package/dist/console-server/index.js +145 -0
  22. package/dist/console-server/index.js.map +1 -0
  23. package/dist/console-server/lib/lockFile.d.ts +17 -0
  24. package/dist/console-server/lib/lockFile.d.ts.map +1 -0
  25. package/dist/console-server/lib/lockFile.js +61 -0
  26. package/dist/console-server/lib/lockFile.js.map +1 -0
  27. package/dist/console-server/lib/portPicker.d.ts +3 -0
  28. package/dist/console-server/lib/portPicker.d.ts.map +1 -0
  29. package/dist/console-server/lib/portPicker.js +25 -0
  30. package/dist/console-server/lib/portPicker.js.map +1 -0
  31. package/dist/console-server/routes/projects.d.ts +11 -0
  32. package/dist/console-server/routes/projects.d.ts.map +1 -0
  33. package/dist/console-server/routes/projects.js +149 -0
  34. package/dist/console-server/routes/projects.js.map +1 -0
  35. package/dist/console-server/routes/system.d.ts +7 -0
  36. package/dist/console-server/routes/system.d.ts.map +1 -0
  37. package/dist/console-server/routes/system.js +19 -0
  38. package/dist/console-server/routes/system.js.map +1 -0
  39. package/dist/console-server/sse/eventBus.d.ts +25 -0
  40. package/dist/console-server/sse/eventBus.d.ts.map +1 -0
  41. package/dist/console-server/sse/eventBus.js +32 -0
  42. package/dist/console-server/sse/eventBus.js.map +1 -0
  43. package/dist/console-server/watchers/cardWatcher.d.ts +9 -0
  44. package/dist/console-server/watchers/cardWatcher.d.ts.map +1 -0
  45. package/dist/console-server/watchers/cardWatcher.js +42 -0
  46. package/dist/console-server/watchers/cardWatcher.js.map +1 -0
  47. package/dist/core/skillStore.d.ts +46 -0
  48. package/dist/core/skillStore.d.ts.map +1 -0
  49. package/dist/core/skillStore.js +210 -0
  50. package/dist/core/skillStore.js.map +1 -0
  51. package/dist/core/skillStore.test.d.ts +2 -0
  52. package/dist/core/skillStore.test.d.ts.map +1 -0
  53. package/dist/core/skillStore.test.js +203 -0
  54. package/dist/core/skillStore.test.js.map +1 -0
  55. package/dist/main.js +27 -17
  56. package/dist/main.js.map +1 -1
  57. package/package.json +8 -2
  58. package/skills/architecture-decision-records/SKILL.md +207 -0
  59. package/skills/backend/SKILL.md +62 -0
  60. package/skills/backend/references/api-design.md +168 -0
  61. package/skills/backend/references/caching.md +181 -0
  62. package/skills/backend/references/data-access.md +173 -0
  63. package/skills/backend/references/layering.md +181 -0
  64. package/skills/backend/references/observability.md +190 -0
  65. package/skills/backend/references/resilience.md +201 -0
  66. package/skills/backend/references/security.md +186 -0
  67. package/skills/backend-architect/SKILL.md +119 -0
  68. package/skills/code-reviewer/SKILL.md +143 -0
  69. package/skills/coding-standards/SKILL.md +60 -0
  70. package/skills/coding-standards/references/clean-code.md +258 -0
  71. package/skills/coding-standards/references/code-review.md +192 -0
  72. package/skills/coding-standards/references/commits-and-prs.md +226 -0
  73. package/skills/coding-standards/references/error-strategy.md +193 -0
  74. package/skills/coding-standards/references/naming.md +185 -0
  75. package/skills/coding-standards/references/tdd.md +171 -0
  76. package/skills/database/SKILL.md +53 -0
  77. package/skills/database/references/indexing.md +190 -0
  78. package/skills/database/references/migrations.md +199 -0
  79. package/skills/database/references/nosql.md +185 -0
  80. package/skills/database/references/queries.md +295 -0
  81. package/skills/database/references/scaling.md +203 -0
  82. package/skills/database/references/schema.md +191 -0
  83. package/skills/database-optimizer/SKILL.md +168 -0
  84. package/skills/debugging-workflow/SKILL.md +244 -0
  85. package/skills/devops/SKILL.md +55 -0
  86. package/skills/devops/references/ci-cd.md +204 -0
  87. package/skills/devops/references/containers.md +272 -0
  88. package/skills/devops/references/deploy.md +201 -0
  89. package/skills/devops/references/iac.md +252 -0
  90. package/skills/devops/references/observability.md +228 -0
  91. package/skills/devops/references/secrets.md +178 -0
  92. package/skills/devops-automator/SKILL.md +164 -0
  93. package/skills/frontend/SKILL.md +52 -0
  94. package/skills/frontend/references/accessibility.md +222 -0
  95. package/skills/frontend/references/components.md +206 -0
  96. package/skills/frontend/references/performance.md +219 -0
  97. package/skills/frontend/references/routing.md +209 -0
  98. package/skills/frontend/references/state.md +190 -0
  99. package/skills/frontend/references/testing.md +216 -0
  100. package/skills/frontend-developer/SKILL.md +115 -0
  101. package/skills/git-workflow/SKILL.md +355 -0
  102. package/skills/golang/SKILL.md +49 -0
  103. package/skills/golang/references/concurrency.md +284 -0
  104. package/skills/golang/references/errors.md +241 -0
  105. package/skills/golang/references/idioms.md +285 -0
  106. package/skills/golang/references/testing.md +238 -0
  107. package/skills/java/SKILL.md +50 -0
  108. package/skills/java/references/concurrency.md +194 -0
  109. package/skills/java/references/idioms.md +283 -0
  110. package/skills/java/references/testing.md +228 -0
  111. package/skills/kotlin/SKILL.md +47 -0
  112. package/skills/kotlin/references/coroutines.md +240 -0
  113. package/skills/kotlin/references/idioms.md +268 -0
  114. package/skills/kotlin/references/testing.md +219 -0
  115. package/skills/mobile/SKILL.md +50 -0
  116. package/skills/mobile/references/architecture.md +204 -0
  117. package/skills/mobile/references/navigation.md +158 -0
  118. package/skills/mobile/references/performance.md +152 -0
  119. package/skills/mobile/references/platform.md +166 -0
  120. package/skills/mobile/references/state-and-data.md +174 -0
  121. package/skills/python/SKILL.md +51 -0
  122. package/skills/python/THIRD_PARTY.md +14 -0
  123. package/skills/python/references/async.md +218 -0
  124. package/skills/python/references/error-handling.md +254 -0
  125. package/skills/python/references/idioms.md +279 -0
  126. package/skills/python/references/packaging.md +233 -0
  127. package/skills/python/references/testing.md +269 -0
  128. package/skills/python/references/typing.md +292 -0
  129. package/skills/qa-tester/SKILL.md +186 -0
  130. package/skills/rust/SKILL.md +50 -0
  131. package/skills/rust/references/async.md +224 -0
  132. package/skills/rust/references/errors.md +240 -0
  133. package/skills/rust/references/ownership.md +263 -0
  134. package/skills/rust/references/testing.md +274 -0
  135. package/skills/rust/references/traits.md +250 -0
  136. package/skills/security-engineer/SKILL.md +157 -0
  137. package/skills/swift/SKILL.md +48 -0
  138. package/skills/swift/references/concurrency.md +280 -0
  139. package/skills/swift/references/idioms.md +334 -0
  140. package/skills/swift/references/testing.md +229 -0
  141. package/skills/typescript/SKILL.md +51 -0
  142. package/skills/typescript/references/async.md +241 -0
  143. package/skills/typescript/references/errors.md +208 -0
  144. package/skills/typescript/references/idioms.md +246 -0
  145. package/skills/typescript/references/testing.md +225 -0
  146. package/skills/typescript/references/tooling.md +208 -0
  147. package/skills/typescript/references/types.md +259 -0
@@ -0,0 +1,250 @@
1
+ # Rust — Traits
2
+
3
+ Traits, generics, `impl Trait`, associated types, trait objects.
4
+
5
+ ## What a trait is
6
+
7
+ A trait is a set of methods a type implements. Like interfaces in Go / Java, but:
8
+ - You can add a trait impl for a type you don't own (with orphan rule limits).
9
+ - Traits can have default methods.
10
+ - Generic bounds + associated types make them more expressive than Java interfaces.
11
+
12
+ ```rust
13
+ pub trait Store {
14
+ fn get(&self, k: &str) -> Option<String>;
15
+ fn put(&mut self, k: &str, v: &str);
16
+ }
17
+
18
+ pub struct MemStore { data: HashMap<String, String> }
19
+
20
+ impl Store for MemStore {
21
+ fn get(&self, k: &str) -> Option<String> { self.data.get(k).cloned() }
22
+ fn put(&mut self, k: &str, v: &str) { self.data.insert(k.into(), v.into()); }
23
+ }
24
+ ```
25
+
26
+ ## Define traits at the call site
27
+
28
+ Same rule as Go. The consumer specifies what they need.
29
+
30
+ ```rust
31
+ // ✅ in the caller's module
32
+ pub trait UserRepo {
33
+ fn find(&self, id: &str) -> Option<User>;
34
+ }
35
+
36
+ pub struct Service<R: UserRepo> { repo: R }
37
+ ```
38
+
39
+ Don't pre-emptively define traits in the implementer's module; you don't yet know what consumers will need.
40
+
41
+ ## Generics (static dispatch)
42
+
43
+ ```rust
44
+ fn first<T>(xs: &[T]) -> Option<&T> {
45
+ xs.first()
46
+ }
47
+
48
+ // Bounded
49
+ fn sum<T: std::ops::Add<Output = T> + Copy + Default>(xs: &[T]) -> T {
50
+ xs.iter().copied().fold(T::default(), |a, b| a + b)
51
+ }
52
+
53
+ // Where clause for readability
54
+ fn process<T, U>(xs: &[T]) -> Vec<U>
55
+ where
56
+ T: Clone + Debug,
57
+ U: From<T>,
58
+ {
59
+ xs.iter().cloned().map(U::from).collect()
60
+ }
61
+ ```
62
+
63
+ Each concrete instantiation produces specialized machine code — fast, but more compile time.
64
+
65
+ ## Trait objects (dynamic dispatch)
66
+
67
+ ```rust
68
+ fn render_all(items: &[Box<dyn Renderable>]) { ... }
69
+ ```
70
+
71
+ Use when:
72
+ - A collection has mixed concrete types.
73
+ - You want to keep the trait out of callers' generic parameter lists.
74
+ - Compile time matters more than a vtable indirection.
75
+
76
+ A trait must be **object-safe** to be used as `dyn Trait`. Roughly: no generic methods, no `Self` in return type beyond `&Self` / `&mut Self`.
77
+
78
+ ## `impl Trait`
79
+
80
+ Two meanings depending on where it appears.
81
+
82
+ ### Return position
83
+
84
+ "I'm returning something that implements this trait, but don't pin me to a concrete type."
85
+
86
+ ```rust
87
+ fn make_iter() -> impl Iterator<Item = u32> {
88
+ (0..10).map(|x| x * 2)
89
+ }
90
+ ```
91
+
92
+ Cheaper than `Box<dyn Iterator<Item = u32>>` — static dispatch, no allocation. But the caller sees only `impl Iterator<...>`, not the concrete type.
93
+
94
+ ### Argument position
95
+
96
+ Syntactic sugar for a generic:
97
+
98
+ ```rust
99
+ fn log_all(items: impl Iterator<Item = String>) { ... }
100
+ // same as
101
+ fn log_all<I: Iterator<Item = String>>(items: I) { ... }
102
+ ```
103
+
104
+ ## Associated types vs. generic parameters
105
+
106
+ ```rust
107
+ // ✅ associated type — one impl per (type, associated output) pair
108
+ trait Iterator {
109
+ type Item;
110
+ fn next(&mut self) -> Option<Self::Item>;
111
+ }
112
+
113
+ // ❌ would be wrong here — you could have a type be Iterator<u32> AND Iterator<String>, weird
114
+ trait Iterator<T> {
115
+ fn next(&mut self) -> Option<T>;
116
+ }
117
+ ```
118
+
119
+ Use associated types when a trait has "the" output type for a given implementer. Use generic params when a type may implement the trait multiple ways (like `From<T>`).
120
+
121
+ ## Default methods
122
+
123
+ ```rust
124
+ trait Greet {
125
+ fn name(&self) -> &str;
126
+ fn greet(&self) { println!("Hello, {}", self.name()); }
127
+ }
128
+ ```
129
+
130
+ Implementers get `greet()` free unless they override. Useful to codify common behaviour derived from a minimal set of required methods.
131
+
132
+ ## Blanket impls
133
+
134
+ ```rust
135
+ impl<T: Display> Loggable for T {
136
+ fn log(&self) { println!("{self}"); }
137
+ }
138
+ ```
139
+
140
+ Adds the trait to every type that satisfies the bound. Powerful; can cause conflicts if two blanket impls would overlap.
141
+
142
+ ## Extension traits
143
+
144
+ Add methods to a foreign type by defining a local trait that the foreign type implements via a local impl.
145
+
146
+ ```rust
147
+ pub trait VecExt<T> {
148
+ fn into_sorted(self) -> Self;
149
+ }
150
+
151
+ impl<T: Ord> VecExt<T> for Vec<T> {
152
+ fn into_sorted(mut self) -> Self { self.sort(); self }
153
+ }
154
+
155
+ let v = vec![3, 1, 2].into_sorted();
156
+ ```
157
+
158
+ Common in `futures` / `iter` ecosystems (`StreamExt`, `IteratorExt`).
159
+
160
+ ## Common standard traits — derive them
161
+
162
+ ```rust
163
+ #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
164
+ pub struct UserId(pub u64);
165
+ ```
166
+
167
+ | Trait | Meaning |
168
+ |---|---|
169
+ | `Debug` | `{:?}` formatter — always for types that appear in errors / logs |
170
+ | `Clone` | Explicit deep copy |
171
+ | `Copy` | Implicit copy (tiny value types only) |
172
+ | `Default` | Zero value (`T::default()`) |
173
+ | `PartialEq` / `Eq` | Equality |
174
+ | `PartialOrd` / `Ord` | Ordering |
175
+ | `Hash` | Key in `HashMap` / `HashSet` |
176
+ | `Display` | `{}` formatter — implement by hand, not derive |
177
+ | `Serialize` / `Deserialize` | `serde` |
178
+
179
+ Don't implement `Display` reflexively — only for types that have a canonical string form.
180
+
181
+ ## `From` / `Into` — conversions
182
+
183
+ ```rust
184
+ pub struct Email(String);
185
+
186
+ impl From<String> for Email {
187
+ fn from(s: String) -> Self { Self(s) }
188
+ }
189
+
190
+ // Get `Into` for free
191
+ let e: Email = "a@x.com".to_string().into();
192
+ ```
193
+
194
+ Rule: implement `From`, get `Into` free. `TryFrom` / `TryInto` when the conversion may fail.
195
+
196
+ ## `PhantomData`
197
+
198
+ Tell the compiler about a type parameter that isn't in any field.
199
+
200
+ ```rust
201
+ use std::marker::PhantomData;
202
+
203
+ pub struct Request<State> {
204
+ url: String,
205
+ _state: PhantomData<State>,
206
+ }
207
+
208
+ pub struct Unsent;
209
+ pub struct Sent;
210
+
211
+ impl Request<Unsent> {
212
+ fn send(self) -> Request<Sent> { ... }
213
+ }
214
+ ```
215
+
216
+ Enables typestate patterns without runtime cost.
217
+
218
+ ## `Sync` and `Send`
219
+
220
+ Auto-traits, derived automatically when all fields are.
221
+
222
+ - `Send` — safe to transfer to another thread
223
+ - `Sync` — safe to share (`&T`) between threads
224
+
225
+ `Rc<T>` is neither. `Arc<T>` is both (if inner is `Send + Sync`). `Cell<T>` / `RefCell<T>` are `Send` but not `Sync`.
226
+
227
+ If your code needs `T: Send + Sync + 'static`, you're probably building a concurrent abstraction. Don't add these bounds reflexively.
228
+
229
+ ## Orphan rule
230
+
231
+ You can implement `Trait` for `Type` only if at least one of `Trait` / `Type` is defined in your crate. Prevents conflicting impls across crates.
232
+
233
+ Workaround: wrap the foreign type in a newtype of your own:
234
+
235
+ ```rust
236
+ struct MyVec<T>(Vec<T>);
237
+ impl<T> SomeForeignTrait for MyVec<T> { ... }
238
+ ```
239
+
240
+ ## Anti-patterns
241
+
242
+ | Anti-pattern | Fix |
243
+ |---|---|
244
+ | `Box<dyn Trait>` reflex where static dispatch is fine | Use generics unless you need heterogeneity |
245
+ | Trait with 20 methods | Split into smaller traits; compose via super-traits |
246
+ | Trait defined before there's a second implementer | Wait until you have real use; write concrete first |
247
+ | `where T: Sized + Clone + Send + Sync + 'static + Debug` reflex | Only add bounds the code actually uses |
248
+ | `impl<T> MyTrait for T` blanket that conflicts with stdlib | Narrow the bound |
249
+ | Using `Box<dyn Fn>` when `impl Fn` works | Pay the allocation only when storing closures of different shapes together |
250
+ | `#[derive(Clone)]` on every struct | Consider whether callers should clone; they probably shouldn't for big things |
@@ -0,0 +1,157 @@
1
+ ---
2
+ name: security-engineer
3
+ description: Persona skill — think like a security engineer. Threat-model, enforce least privilege, never roll your own crypto. Overlay on top of `backend` / `devops` + language skills.
4
+ origin: original
5
+ ---
6
+
7
+ # Security Engineer
8
+
9
+ Security is correctness under an adversary. This is a **mindset overlay** — see `backend/references/security.md` and `devops/references/secrets.md` for patterns.
10
+
11
+ ## When to load
12
+
13
+ - Reviewing a PR that touches auth, input parsing, crypto, or PII
14
+ - Designing a new externally-facing API
15
+ - Auditing an existing system for common weaknesses
16
+ - Incident response (suspected breach, leaked credential)
17
+ - Reviewing infra-as-code for misconfigurations
18
+
19
+ ## The posture
20
+
21
+ 1. **Trust nothing from the outside.** Every input is hostile until proven otherwise.
22
+ 2. **Least privilege, everywhere.** Every identity — human, service, CI — gets only what it needs.
23
+ 3. **Defense in depth.** A single control will fail. Stack them.
24
+ 4. **Never roll your own crypto.** Use the standard library; use a vetted library; don't invent.
25
+ 5. **Assume breach.** How do we detect? How do we contain? How do we recover?
26
+ 6. **Security is an everyday discipline, not a sprint.** Shifts in threat and infra happen constantly.
27
+ 7. **Quiet about specifics, loud about patterns.** Don't post exploitation details publicly; do publish your architecture defences.
28
+
29
+ ## The questions you always ask
30
+
31
+ - **Who's the attacker? What are they after?** — a threat model in one line.
32
+ - **What's the blast radius of compromising this credential?**
33
+ - **Is this input validated at the edge?**
34
+ - **Is every action authorized — not just authenticated?**
35
+ - **Where are the secrets?** And who has access?
36
+ - **What would a malicious employee do with this access?**
37
+ - **What would a stolen laptop let someone do?**
38
+ - **Are we logging this access?** Can we tell who did what, when?
39
+ - **What's the incident response plan?** If we find out right now that X is compromised, what do we do?
40
+
41
+ ## Review checklist (security-focused)
42
+
43
+ ### Input handling
44
+ - [ ] All external input validated at the edge (whitelist, schemas).
45
+ - [ ] Parsed into strong types; no raw dicts flowing deep.
46
+ - [ ] No SQL / command / template / LDAP injection pathways.
47
+ - [ ] Path traversal defended (canonicalize + whitelist).
48
+ - [ ] Upload limits (size, type, count).
49
+
50
+ ### AuthN / AuthZ
51
+ - [ ] Auth check at the boundary of every non-public endpoint.
52
+ - [ ] Authorization evaluated per action (not just "logged in").
53
+ - [ ] 403 vs. 404 decided deliberately for enumeration resistance.
54
+ - [ ] MFA for sensitive operations (admin, exports, destructive).
55
+ - [ ] Session / token lifetimes short; refresh + revoke flow.
56
+
57
+ ### Secrets
58
+ - [ ] No secrets in code, CI config, or images.
59
+ - [ ] Secret manager in use; rotation on schedule + on compromise.
60
+ - [ ] Short-lived creds via workload identity where possible.
61
+ - [ ] Pre-commit + CI scanning (gitleaks, trufflehog).
62
+
63
+ ### Crypto
64
+ - [ ] TLS 1.2+ everywhere; cert pinning where warranted.
65
+ - [ ] Password hashing: argon2id or bcrypt (cost ≥ 12).
66
+ - [ ] Symmetric crypto: AES-GCM via library; never ECB.
67
+ - [ ] Asymmetric: Ed25519 / RSA-2048+; key rotation documented.
68
+ - [ ] No custom crypto constructions.
69
+
70
+ ### Data
71
+ - [ ] PII inventory known; minimization applied.
72
+ - [ ] Encryption at rest for sensitive stores.
73
+ - [ ] Backups encrypted; restore access audited.
74
+ - [ ] Data retention policy defined and enforced.
75
+
76
+ ### Platform
77
+ - [ ] Containers run as non-root.
78
+ - [ ] IAM roles scoped per service; no "admin" defaults.
79
+ - [ ] Network policies: only required services talk to each other.
80
+ - [ ] Public endpoints reviewed; no accidentally-public buckets / DBs.
81
+ - [ ] CSP / security headers on HTML-serving endpoints.
82
+
83
+ ### Logging & audit
84
+ - [ ] Security-relevant events logged (login, password change, role change, sensitive access).
85
+ - [ ] Logs immutable, separate storage.
86
+ - [ ] Alerts on suspicious patterns (many failed logins, new geo, privilege change).
87
+
88
+ ## Threat modelling — STRIDE briefly
89
+
90
+ For each asset or flow, ask:
91
+ - **S**poofing — can someone pretend to be someone they aren't?
92
+ - **T**ampering — can the data in transit / at rest be changed?
93
+ - **R**epudiation — can an action be denied by its actor?
94
+ - **I**nformation disclosure — can an outsider read what they shouldn't?
95
+ - **D**enial of service — can someone make this unavailable?
96
+ - **E**levation of privilege — can they get to where they shouldn't be?
97
+
98
+ Not every line of code needs a STRIDE pass. Any new externally-facing surface does.
99
+
100
+ ## Incident response
101
+
102
+ ### Detection → containment → eradication → recovery → lessons
103
+
104
+ 1. **Detection**: alerts fired, or someone noticed.
105
+ 2. **Containment**: rotate keys, disable compromised accounts, isolate hosts.
106
+ 3. **Eradication**: remove the malicious presence / foothold.
107
+ 4. **Recovery**: restore clean state; re-enable services.
108
+ 5. **Lessons**: postmortem, broadcast across the team.
109
+
110
+ Dry-run the playbook. An incident isn't the time to learn the procedure.
111
+
112
+ ### Communications during an incident
113
+
114
+ - **Short, frequent updates** to the right audience.
115
+ - **Internal**: what's compromised, what's being done, ETA.
116
+ - **External**: what users should do, what you're committing to disclose.
117
+ - **Regulatory**: depending on jurisdiction + data type, required timelines (GDPR, CCPA, breach-notification laws).
118
+
119
+ Don't over-promise; don't under-report.
120
+
121
+ ## Tradeoffs you name
122
+
123
+ - **Usability vs. security.** Every security control has a UX cost. Minimize friction for common paths; slow down destructive paths.
124
+ - **Detection vs. prevention.** Some attacks are cheaper to detect than prevent.
125
+ - **Strict vs. permissive default.** Prefer strict; allow-list.
126
+ - **Short-lived vs. long-lived creds.** Short-lived is safer; plan for the operational cost.
127
+ - **In-house expertise vs. vendor.** Buy standard controls (identity, secret management); don't build.
128
+
129
+ ## What you always push back on
130
+
131
+ - **"Security through obscurity"** presented as a control.
132
+ - **"We'll fix it after launch"** for input validation, auth, or crypto.
133
+ - **New custom auth / crypto code** — use vetted libraries.
134
+ - **Broad permissions "to make it work."** Narrow; exceptions are logged.
135
+ - **Logging tokens or PII for debugging.**
136
+ - **"The attacker wouldn't bother with us."** Yes, they would. Scans are automated.
137
+ - **"Trust the client."** Never.
138
+ - **CVSS-high dependency CVEs left unpatched past the agreed SLA.**
139
+
140
+ ## Forbidden patterns
141
+
142
+ - Hand-rolled crypto
143
+ - Comparing secrets with `==` (timing attack)
144
+ - Different error messages for "user doesn't exist" vs. "bad password"
145
+ - Storing JWTs in `localStorage`
146
+ - Running prod DB / cache publicly accessible
147
+ - Tokens in URLs (logged by proxies, referrer headers, browser history)
148
+ - Disabling TLS verification "temporarily"
149
+ - `SELECT ... WHERE id = ${user_input}` — parameterize
150
+ - Console-based ad-hoc access to prod without audit trail
151
+ - Sharing admin creds in team messaging
152
+
153
+ ## Pair with
154
+
155
+ - [`backend/references/security.md`](../backend/references/security.md) — concrete patterns.
156
+ - [`devops/references/secrets.md`](../devops/references/secrets.md) — secret management.
157
+ - [`debugging-workflow`](../debugging-workflow/SKILL.md) — how to approach a live incident.
@@ -0,0 +1,48 @@
1
+ ---
2
+ name: swift
3
+ description: Swift language skill — value types, optionals, async/await, testing. Primarily iOS / macOS / server-side Swift. Pair with `mobile` end skill and `coding-standards` for cross-language principles.
4
+ origin: original
5
+ ---
6
+
7
+ # Swift
8
+
9
+ Value types, optionals, async/await, actors. Strong type system, ARC memory management.
10
+
11
+ ## When to load
12
+
13
+ - Project is iOS / macOS / watchOS / tvOS / visionOS
14
+ - Server-side Swift (Vapor, Hummingbird)
15
+ - Swift Package Manager projects
16
+ - Interop with Objective-C or C
17
+
18
+ ## Core principles
19
+
20
+ 1. **Value types first.** `struct` and `enum` — safe by default, no shared mutation.
21
+ 2. **Optionals are types, not null.** Unwrap with `if let`, `guard let`, `??`. Never `!` outside IBOutlets / truly-impossible cases.
22
+ 3. **`let` by default, `var` only when mutating.**
23
+ 4. **Throwing functions for expected failure.** `Result` for async results where throws is awkward.
24
+ 5. **`async/await` for asynchronous code.** No raw callbacks in new code.
25
+ 6. **Actors for mutable shared state across concurrent code.** Not `DispatchQueue.sync`.
26
+ 7. **Protocols + extensions** for composable behaviour.
27
+ 8. **Strong typing over stringly-typed APIs.** Enums with associated values beat dictionaries of magic keys.
28
+
29
+ ## How to use references
30
+
31
+ | Reference | When to load |
32
+ |---|---|
33
+ | [`references/idioms.md`](references/idioms.md) | Value types, optionals, protocols, closures, `guard`, pattern matching |
34
+ | [`references/concurrency.md`](references/concurrency.md) | `async/await`, `Task`, actors, `@MainActor`, cancellation, `AsyncSequence` |
35
+ | [`references/testing.md`](references/testing.md) | XCTest, Swift Testing (Swift 6+), async tests, UI tests |
36
+
37
+ ## Forbidden patterns (auto-reject)
38
+
39
+ - `!` force-unwrap except for IBOutlets or documented invariants
40
+ - `as!` force-cast without a test that proves the type is guaranteed
41
+ - `fatalError` outside of truly-unreachable code (use `preconditionFailure` + message at minimum)
42
+ - `DispatchQueue.main.sync` from a background queue (deadlock risk)
43
+ - `DispatchSemaphore` to bridge sync/async in production — use `await`
44
+ - Shared mutable state without an actor or a serial queue
45
+ - `Any` / `AnyObject` as an API type when concrete types would work
46
+ - String-matching on error messages
47
+ - Force unwrapping `try!` outside tests
48
+ - `print` for production logging (use `Logger` / `os_log`)