agy-superpowers 5.2.1 → 5.2.3

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 (233) hide show
  1. package/README.md +47 -150
  2. package/package.json +1 -1
  3. package/template/agent/patches/skills-patches.md +23 -0
  4. package/template/agent/rules/scratch-scripts.md +37 -0
  5. package/template/agent/rules/superpowers.md +6 -50
  6. package/template/agent/skills/brainstorming/SKILL.md +4 -3
  7. package/template/agent/skills/brainstorming/visual-companion.md +2 -3
  8. package/template/agent/skills/finishing-a-development-branch/SKILL.md +11 -16
  9. package/template/agent/skills/subagent-driven-development/SKILL.md +16 -0
  10. package/template/agent/skills/subagent-driven-development/implementer-prompt.md +4 -3
  11. package/template/agent/skills/using-git-worktrees/SKILL.md +3 -2
  12. package/template/agent/skills/using-superpowers/SKILL.md +8 -6
  13. package/template/agent/skills/using-superpowers/references/copilot-tools.md +52 -0
  14. package/template/agent/skills/writing-plans/SKILL.md +5 -3
  15. package/template/agent/skills/writing-skills/SKILL.md +1 -1
  16. package/template/agent/superpowers-version.json +2 -2
  17. package/template/agent/tmp/agent-config-backup.yml +9 -0
  18. package/template/agent/skills/ai-integrated-product/SKILL.md +0 -57
  19. package/template/agent/skills/analytics-setup/SKILL.md +0 -51
  20. package/template/agent/skills/api-design/SKILL.md +0 -193
  21. package/template/agent/skills/app-store-optimizer/SKILL.md +0 -127
  22. package/template/agent/skills/auth-and-identity/SKILL.md +0 -167
  23. package/template/agent/skills/backend-developer/SKILL.md +0 -148
  24. package/template/agent/skills/bootstrapper-finance/SKILL.md +0 -55
  25. package/template/agent/skills/chrome-extension-developer/SKILL.md +0 -53
  26. package/template/agent/skills/community-manager/SKILL.md +0 -115
  27. package/template/agent/skills/content-marketer/SKILL.md +0 -111
  28. package/template/agent/skills/conversion-optimizer/SKILL.md +0 -142
  29. package/template/agent/skills/cto-architect/SKILL.md +0 -133
  30. package/template/agent/skills/customer-success-manager/SKILL.md +0 -126
  31. package/template/agent/skills/data-analyst/SKILL.md +0 -147
  32. package/template/agent/skills/devops-engineer/SKILL.md +0 -117
  33. package/template/agent/skills/email-infrastructure/SKILL.md +0 -164
  34. package/template/agent/skills/game-design/SKILL.md +0 -194
  35. package/template/agent/skills/game-developer/SKILL.md +0 -175
  36. package/template/agent/skills/growth-hacker/SKILL.md +0 -122
  37. package/template/agent/skills/idea-validator/SKILL.md +0 -55
  38. package/template/agent/skills/indie-legal/SKILL.md +0 -53
  39. package/template/agent/skills/influencer-marketer/SKILL.md +0 -141
  40. package/template/agent/skills/landing-page-builder/SKILL.md +0 -59
  41. package/template/agent/skills/launch-strategist/SKILL.md +0 -62
  42. package/template/agent/skills/market-researcher/SKILL.md +0 -53
  43. package/template/agent/skills/micro-saas-builder/SKILL.md +0 -56
  44. package/template/agent/skills/monetization-strategist/SKILL.md +0 -119
  45. package/template/agent/skills/paid-acquisition-specialist/SKILL.md +0 -119
  46. package/template/agent/skills/pricing-psychologist/SKILL.md +0 -58
  47. package/template/agent/skills/real-time-features/SKILL.md +0 -194
  48. package/template/agent/skills/retention-specialist/SKILL.md +0 -123
  49. package/template/agent/skills/rust-developer/SKILL.md +0 -281
  50. package/template/agent/skills/rust-developer/references/rust-rules/_sections.md +0 -231
  51. package/template/agent/skills/rust-developer/references/rust-rules/anti-clone-excessive.md +0 -124
  52. package/template/agent/skills/rust-developer/references/rust-rules/anti-collect-intermediate.md +0 -131
  53. package/template/agent/skills/rust-developer/references/rust-rules/anti-empty-catch.md +0 -132
  54. package/template/agent/skills/rust-developer/references/rust-rules/anti-expect-lazy.md +0 -95
  55. package/template/agent/skills/rust-developer/references/rust-rules/anti-format-hot-path.md +0 -141
  56. package/template/agent/skills/rust-developer/references/rust-rules/anti-index-over-iter.md +0 -125
  57. package/template/agent/skills/rust-developer/references/rust-rules/anti-lock-across-await.md +0 -127
  58. package/template/agent/skills/rust-developer/references/rust-rules/anti-over-abstraction.md +0 -120
  59. package/template/agent/skills/rust-developer/references/rust-rules/anti-panic-expected.md +0 -131
  60. package/template/agent/skills/rust-developer/references/rust-rules/anti-premature-optimize.md +0 -156
  61. package/template/agent/skills/rust-developer/references/rust-rules/anti-string-for-str.md +0 -122
  62. package/template/agent/skills/rust-developer/references/rust-rules/anti-stringly-typed.md +0 -167
  63. package/template/agent/skills/rust-developer/references/rust-rules/anti-type-erasure.md +0 -134
  64. package/template/agent/skills/rust-developer/references/rust-rules/anti-unwrap-abuse.md +0 -143
  65. package/template/agent/skills/rust-developer/references/rust-rules/anti-vec-for-slice.md +0 -121
  66. package/template/agent/skills/rust-developer/references/rust-rules/api-builder-must-use.md +0 -143
  67. package/template/agent/skills/rust-developer/references/rust-rules/api-builder-pattern.md +0 -187
  68. package/template/agent/skills/rust-developer/references/rust-rules/api-common-traits.md +0 -165
  69. package/template/agent/skills/rust-developer/references/rust-rules/api-default-impl.md +0 -177
  70. package/template/agent/skills/rust-developer/references/rust-rules/api-extension-trait.md +0 -163
  71. package/template/agent/skills/rust-developer/references/rust-rules/api-from-not-into.md +0 -146
  72. package/template/agent/skills/rust-developer/references/rust-rules/api-impl-asref.md +0 -142
  73. package/template/agent/skills/rust-developer/references/rust-rules/api-impl-into.md +0 -160
  74. package/template/agent/skills/rust-developer/references/rust-rules/api-must-use.md +0 -125
  75. package/template/agent/skills/rust-developer/references/rust-rules/api-newtype-safety.md +0 -162
  76. package/template/agent/skills/rust-developer/references/rust-rules/api-non-exhaustive.md +0 -177
  77. package/template/agent/skills/rust-developer/references/rust-rules/api-parse-dont-validate.md +0 -184
  78. package/template/agent/skills/rust-developer/references/rust-rules/api-sealed-trait.md +0 -168
  79. package/template/agent/skills/rust-developer/references/rust-rules/api-serde-optional.md +0 -182
  80. package/template/agent/skills/rust-developer/references/rust-rules/api-typestate.md +0 -199
  81. package/template/agent/skills/rust-developer/references/rust-rules/async-bounded-channel.md +0 -175
  82. package/template/agent/skills/rust-developer/references/rust-rules/async-broadcast-pubsub.md +0 -185
  83. package/template/agent/skills/rust-developer/references/rust-rules/async-cancellation-token.md +0 -203
  84. package/template/agent/skills/rust-developer/references/rust-rules/async-clone-before-await.md +0 -171
  85. package/template/agent/skills/rust-developer/references/rust-rules/async-join-parallel.md +0 -158
  86. package/template/agent/skills/rust-developer/references/rust-rules/async-joinset-structured.md +0 -195
  87. package/template/agent/skills/rust-developer/references/rust-rules/async-mpsc-queue.md +0 -171
  88. package/template/agent/skills/rust-developer/references/rust-rules/async-no-lock-await.md +0 -156
  89. package/template/agent/skills/rust-developer/references/rust-rules/async-oneshot-response.md +0 -191
  90. package/template/agent/skills/rust-developer/references/rust-rules/async-select-racing.md +0 -198
  91. package/template/agent/skills/rust-developer/references/rust-rules/async-spawn-blocking.md +0 -154
  92. package/template/agent/skills/rust-developer/references/rust-rules/async-tokio-fs.md +0 -167
  93. package/template/agent/skills/rust-developer/references/rust-rules/async-tokio-runtime.md +0 -169
  94. package/template/agent/skills/rust-developer/references/rust-rules/async-try-join.md +0 -172
  95. package/template/agent/skills/rust-developer/references/rust-rules/async-watch-latest.md +0 -189
  96. package/template/agent/skills/rust-developer/references/rust-rules/doc-all-public.md +0 -113
  97. package/template/agent/skills/rust-developer/references/rust-rules/doc-cargo-metadata.md +0 -147
  98. package/template/agent/skills/rust-developer/references/rust-rules/doc-errors-section.md +0 -122
  99. package/template/agent/skills/rust-developer/references/rust-rules/doc-examples-section.md +0 -161
  100. package/template/agent/skills/rust-developer/references/rust-rules/doc-hidden-setup.md +0 -149
  101. package/template/agent/skills/rust-developer/references/rust-rules/doc-intra-links.md +0 -138
  102. package/template/agent/skills/rust-developer/references/rust-rules/doc-link-types.md +0 -169
  103. package/template/agent/skills/rust-developer/references/rust-rules/doc-module-inner.md +0 -116
  104. package/template/agent/skills/rust-developer/references/rust-rules/doc-panics-section.md +0 -128
  105. package/template/agent/skills/rust-developer/references/rust-rules/doc-question-mark.md +0 -136
  106. package/template/agent/skills/rust-developer/references/rust-rules/doc-safety-section.md +0 -131
  107. package/template/agent/skills/rust-developer/references/rust-rules/err-anyhow-app.md +0 -179
  108. package/template/agent/skills/rust-developer/references/rust-rules/err-context-chain.md +0 -144
  109. package/template/agent/skills/rust-developer/references/rust-rules/err-custom-type.md +0 -152
  110. package/template/agent/skills/rust-developer/references/rust-rules/err-doc-errors.md +0 -145
  111. package/template/agent/skills/rust-developer/references/rust-rules/err-expect-bugs-only.md +0 -133
  112. package/template/agent/skills/rust-developer/references/rust-rules/err-from-impl.md +0 -152
  113. package/template/agent/skills/rust-developer/references/rust-rules/err-lowercase-msg.md +0 -124
  114. package/template/agent/skills/rust-developer/references/rust-rules/err-no-unwrap-prod.md +0 -115
  115. package/template/agent/skills/rust-developer/references/rust-rules/err-question-mark.md +0 -151
  116. package/template/agent/skills/rust-developer/references/rust-rules/err-result-over-panic.md +0 -130
  117. package/template/agent/skills/rust-developer/references/rust-rules/err-source-chain.md +0 -155
  118. package/template/agent/skills/rust-developer/references/rust-rules/err-thiserror-lib.md +0 -171
  119. package/template/agent/skills/rust-developer/references/rust-rules/lint-cargo-metadata.md +0 -138
  120. package/template/agent/skills/rust-developer/references/rust-rules/lint-deny-correctness.md +0 -107
  121. package/template/agent/skills/rust-developer/references/rust-rules/lint-missing-docs.md +0 -154
  122. package/template/agent/skills/rust-developer/references/rust-rules/lint-pedantic-selective.md +0 -118
  123. package/template/agent/skills/rust-developer/references/rust-rules/lint-rustfmt-check.md +0 -157
  124. package/template/agent/skills/rust-developer/references/rust-rules/lint-unsafe-doc.md +0 -133
  125. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-complexity.md +0 -131
  126. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-perf.md +0 -136
  127. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-style.md +0 -135
  128. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-suspicious.md +0 -122
  129. package/template/agent/skills/rust-developer/references/rust-rules/lint-workspace-lints.md +0 -172
  130. package/template/agent/skills/rust-developer/references/rust-rules/mem-arena-allocator.md +0 -168
  131. package/template/agent/skills/rust-developer/references/rust-rules/mem-arrayvec.md +0 -142
  132. package/template/agent/skills/rust-developer/references/rust-rules/mem-assert-type-size.md +0 -168
  133. package/template/agent/skills/rust-developer/references/rust-rules/mem-avoid-format.md +0 -147
  134. package/template/agent/skills/rust-developer/references/rust-rules/mem-box-large-variant.md +0 -158
  135. package/template/agent/skills/rust-developer/references/rust-rules/mem-boxed-slice.md +0 -139
  136. package/template/agent/skills/rust-developer/references/rust-rules/mem-clone-from.md +0 -147
  137. package/template/agent/skills/rust-developer/references/rust-rules/mem-compact-string.md +0 -149
  138. package/template/agent/skills/rust-developer/references/rust-rules/mem-reuse-collections.md +0 -174
  139. package/template/agent/skills/rust-developer/references/rust-rules/mem-smaller-integers.md +0 -159
  140. package/template/agent/skills/rust-developer/references/rust-rules/mem-smallvec.md +0 -138
  141. package/template/agent/skills/rust-developer/references/rust-rules/mem-thinvec.md +0 -142
  142. package/template/agent/skills/rust-developer/references/rust-rules/mem-with-capacity.md +0 -156
  143. package/template/agent/skills/rust-developer/references/rust-rules/mem-write-over-format.md +0 -172
  144. package/template/agent/skills/rust-developer/references/rust-rules/mem-zero-copy.md +0 -164
  145. package/template/agent/skills/rust-developer/references/rust-rules/name-acronym-word.md +0 -99
  146. package/template/agent/skills/rust-developer/references/rust-rules/name-as-free.md +0 -104
  147. package/template/agent/skills/rust-developer/references/rust-rules/name-consts-screaming.md +0 -94
  148. package/template/agent/skills/rust-developer/references/rust-rules/name-crate-no-rs.md +0 -78
  149. package/template/agent/skills/rust-developer/references/rust-rules/name-funcs-snake.md +0 -76
  150. package/template/agent/skills/rust-developer/references/rust-rules/name-into-ownership.md +0 -123
  151. package/template/agent/skills/rust-developer/references/rust-rules/name-is-has-bool.md +0 -127
  152. package/template/agent/skills/rust-developer/references/rust-rules/name-iter-convention.md +0 -129
  153. package/template/agent/skills/rust-developer/references/rust-rules/name-iter-method.md +0 -131
  154. package/template/agent/skills/rust-developer/references/rust-rules/name-iter-type-match.md +0 -142
  155. package/template/agent/skills/rust-developer/references/rust-rules/name-lifetime-short.md +0 -86
  156. package/template/agent/skills/rust-developer/references/rust-rules/name-no-get-prefix.md +0 -154
  157. package/template/agent/skills/rust-developer/references/rust-rules/name-to-expensive.md +0 -118
  158. package/template/agent/skills/rust-developer/references/rust-rules/name-type-param-single.md +0 -92
  159. package/template/agent/skills/rust-developer/references/rust-rules/name-types-camel.md +0 -65
  160. package/template/agent/skills/rust-developer/references/rust-rules/name-variants-camel.md +0 -101
  161. package/template/agent/skills/rust-developer/references/rust-rules/opt-bounds-check.md +0 -161
  162. package/template/agent/skills/rust-developer/references/rust-rules/opt-cache-friendly.md +0 -187
  163. package/template/agent/skills/rust-developer/references/rust-rules/opt-codegen-units.md +0 -142
  164. package/template/agent/skills/rust-developer/references/rust-rules/opt-cold-unlikely.md +0 -152
  165. package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-always-rare.md +0 -141
  166. package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-never-cold.md +0 -181
  167. package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-small.md +0 -160
  168. package/template/agent/skills/rust-developer/references/rust-rules/opt-likely-hint.md +0 -171
  169. package/template/agent/skills/rust-developer/references/rust-rules/opt-lto-release.md +0 -130
  170. package/template/agent/skills/rust-developer/references/rust-rules/opt-pgo-profile.md +0 -167
  171. package/template/agent/skills/rust-developer/references/rust-rules/opt-simd-portable.md +0 -144
  172. package/template/agent/skills/rust-developer/references/rust-rules/opt-target-cpu.md +0 -154
  173. package/template/agent/skills/rust-developer/references/rust-rules/own-arc-shared.md +0 -141
  174. package/template/agent/skills/rust-developer/references/rust-rules/own-borrow-over-clone.md +0 -95
  175. package/template/agent/skills/rust-developer/references/rust-rules/own-clone-explicit.md +0 -135
  176. package/template/agent/skills/rust-developer/references/rust-rules/own-copy-small.md +0 -124
  177. package/template/agent/skills/rust-developer/references/rust-rules/own-cow-conditional.md +0 -135
  178. package/template/agent/skills/rust-developer/references/rust-rules/own-lifetime-elision.md +0 -134
  179. package/template/agent/skills/rust-developer/references/rust-rules/own-move-large.md +0 -134
  180. package/template/agent/skills/rust-developer/references/rust-rules/own-mutex-interior.md +0 -105
  181. package/template/agent/skills/rust-developer/references/rust-rules/own-rc-single-thread.md +0 -65
  182. package/template/agent/skills/rust-developer/references/rust-rules/own-refcell-interior.md +0 -97
  183. package/template/agent/skills/rust-developer/references/rust-rules/own-rwlock-readers.md +0 -122
  184. package/template/agent/skills/rust-developer/references/rust-rules/own-slice-over-vec.md +0 -119
  185. package/template/agent/skills/rust-developer/references/rust-rules/perf-black-box-bench.md +0 -153
  186. package/template/agent/skills/rust-developer/references/rust-rules/perf-chain-avoid.md +0 -136
  187. package/template/agent/skills/rust-developer/references/rust-rules/perf-collect-into.md +0 -133
  188. package/template/agent/skills/rust-developer/references/rust-rules/perf-collect-once.md +0 -120
  189. package/template/agent/skills/rust-developer/references/rust-rules/perf-drain-reuse.md +0 -137
  190. package/template/agent/skills/rust-developer/references/rust-rules/perf-entry-api.md +0 -134
  191. package/template/agent/skills/rust-developer/references/rust-rules/perf-extend-batch.md +0 -150
  192. package/template/agent/skills/rust-developer/references/rust-rules/perf-iter-lazy.md +0 -123
  193. package/template/agent/skills/rust-developer/references/rust-rules/perf-iter-over-index.md +0 -113
  194. package/template/agent/skills/rust-developer/references/rust-rules/perf-profile-first.md +0 -175
  195. package/template/agent/skills/rust-developer/references/rust-rules/perf-release-profile.md +0 -149
  196. package/template/agent/skills/rust-developer/references/rust-rules/proj-bin-dir.md +0 -142
  197. package/template/agent/skills/rust-developer/references/rust-rules/proj-flat-small.md +0 -133
  198. package/template/agent/skills/rust-developer/references/rust-rules/proj-lib-main-split.md +0 -148
  199. package/template/agent/skills/rust-developer/references/rust-rules/proj-mod-by-feature.md +0 -130
  200. package/template/agent/skills/rust-developer/references/rust-rules/proj-mod-rs-dir.md +0 -120
  201. package/template/agent/skills/rust-developer/references/rust-rules/proj-prelude-module.md +0 -155
  202. package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-crate-internal.md +0 -139
  203. package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-super-parent.md +0 -135
  204. package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-use-reexport.md +0 -162
  205. package/template/agent/skills/rust-developer/references/rust-rules/proj-workspace-deps.md +0 -186
  206. package/template/agent/skills/rust-developer/references/rust-rules/proj-workspace-large.md +0 -162
  207. package/template/agent/skills/rust-developer/references/rust-rules/test-arrange-act-assert.md +0 -160
  208. package/template/agent/skills/rust-developer/references/rust-rules/test-cfg-test-module.md +0 -151
  209. package/template/agent/skills/rust-developer/references/rust-rules/test-criterion-bench.md +0 -171
  210. package/template/agent/skills/rust-developer/references/rust-rules/test-descriptive-names.md +0 -142
  211. package/template/agent/skills/rust-developer/references/rust-rules/test-doctest-examples.md +0 -168
  212. package/template/agent/skills/rust-developer/references/rust-rules/test-fixture-raii.md +0 -151
  213. package/template/agent/skills/rust-developer/references/rust-rules/test-integration-dir.md +0 -144
  214. package/template/agent/skills/rust-developer/references/rust-rules/test-mock-traits.md +0 -189
  215. package/template/agent/skills/rust-developer/references/rust-rules/test-mockall-mocking.md +0 -226
  216. package/template/agent/skills/rust-developer/references/rust-rules/test-proptest-properties.md +0 -161
  217. package/template/agent/skills/rust-developer/references/rust-rules/test-should-panic.md +0 -130
  218. package/template/agent/skills/rust-developer/references/rust-rules/test-tokio-async.md +0 -154
  219. package/template/agent/skills/rust-developer/references/rust-rules/test-use-super.md +0 -127
  220. package/template/agent/skills/rust-developer/references/rust-rules/type-enum-states.md +0 -154
  221. package/template/agent/skills/rust-developer/references/rust-rules/type-generic-bounds.md +0 -142
  222. package/template/agent/skills/rust-developer/references/rust-rules/type-never-diverge.md +0 -146
  223. package/template/agent/skills/rust-developer/references/rust-rules/type-newtype-ids.md +0 -160
  224. package/template/agent/skills/rust-developer/references/rust-rules/type-newtype-validated.md +0 -159
  225. package/template/agent/skills/rust-developer/references/rust-rules/type-no-stringly.md +0 -144
  226. package/template/agent/skills/rust-developer/references/rust-rules/type-option-nullable.md +0 -137
  227. package/template/agent/skills/rust-developer/references/rust-rules/type-phantom-marker.md +0 -188
  228. package/template/agent/skills/rust-developer/references/rust-rules/type-repr-transparent.md +0 -143
  229. package/template/agent/skills/rust-developer/references/rust-rules/type-result-fallible.md +0 -131
  230. package/template/agent/skills/saas-architect/SKILL.md +0 -139
  231. package/template/agent/skills/security-engineer/SKILL.md +0 -133
  232. package/template/agent/skills/seo-specialist/SKILL.md +0 -130
  233. package/template/agent/skills/solo-founder-ops/SKILL.md +0 -56
@@ -1,133 +0,0 @@
1
- # err-expect-bugs-only
2
-
3
- > Use `expect()` only for invariants that indicate bugs, not user errors
4
-
5
- ## Why It Matters
6
-
7
- `expect()` is better than `unwrap()` because it provides context, but it still panics. Reserve it for situations where failure indicates a bug in your code—a violated invariant, not a user error or external failure. The message should explain why the invariant should hold, helping future developers understand and fix the bug.
8
-
9
- ## Bad
10
-
11
- ```rust
12
- // User input can legitimately fail - don't expect
13
- fn parse_user_input(input: &str) -> Config {
14
- serde_json::from_str(input)
15
- .expect("Invalid JSON") // User error, not a bug!
16
- }
17
-
18
- // Network can fail - don't expect
19
- fn fetch_data(url: &str) -> Data {
20
- reqwest::get(url)
21
- .expect("Network request failed") // External failure!
22
- .json()
23
- .expect("Invalid response")
24
- }
25
-
26
- // File might not exist - don't expect
27
- fn load_config() -> Config {
28
- let content = fs::read_to_string("config.json")
29
- .expect("Config file missing"); // Environment issue!
30
- }
31
- ```
32
-
33
- ## Good
34
-
35
- ```rust
36
- // Invariant: after insert, key exists
37
- fn cache_and_get(&mut self, key: String, value: Value) -> &Value {
38
- self.cache.insert(key.clone(), value);
39
- self.cache.get(&key)
40
- .expect("BUG: key must exist immediately after insert")
41
- }
42
-
43
- // Invariant: regex is compile-time constant
44
- fn create_parser() -> Regex {
45
- Regex::new(r"^\d{4}-\d{2}-\d{2}$")
46
- .expect("BUG: date regex is invalid - this is a compile-time constant")
47
- }
48
-
49
- // Invariant: already validated
50
- fn process_validated(data: ValidatedData) -> Result<Output, ProcessError> {
51
- let value = data.required_field
52
- .expect("BUG: ValidatedData guarantees required_field is Some");
53
- // ...
54
- }
55
-
56
- // Invariant: type system guarantees
57
- fn get_first<T>(vec: Vec<T>) -> T
58
- where
59
- Vec<T>: NonEmpty, // Hypothetical trait
60
- {
61
- vec.into_iter().next()
62
- .expect("BUG: NonEmpty Vec cannot be empty")
63
- }
64
- ```
65
-
66
- ## expect() Message Guidelines
67
-
68
- Messages should:
69
- 1. Start with "BUG:" or similar to indicate it's an invariant
70
- 2. Explain WHY the invariant should hold
71
- 3. Help developers fix the issue
72
-
73
- ```rust
74
- // ❌ Bad messages
75
- .expect("failed") // No context
76
- .expect("should not be None") // Doesn't explain why
77
- .expect("Invalid state") // Vague
78
-
79
- // ✅ Good messages
80
- .expect("BUG: HashMap entry exists after insert")
81
- .expect("BUG: validated input must parse - validation is broken")
82
- .expect("BUG: static regex compilation failed - regex syntax error in source")
83
- ```
84
-
85
- ## Pattern: Validate Once, expect() After
86
-
87
- ```rust
88
- struct ValidatedEmail(String);
89
-
90
- impl ValidatedEmail {
91
- pub fn new(email: &str) -> Result<Self, EmailError> {
92
- // Validation happens here, returns Result
93
- if !is_valid_email(email) {
94
- return Err(EmailError::Invalid);
95
- }
96
- Ok(ValidatedEmail(email.to_string()))
97
- }
98
-
99
- pub fn domain(&self) -> &str {
100
- // After validation, expect() is fine
101
- self.0.split('@').nth(1)
102
- .expect("BUG: ValidatedEmail must contain @")
103
- }
104
- }
105
- ```
106
-
107
- ## Alternatives When expect() Is Wrong
108
-
109
- ```rust
110
- // Don't: expect on user data
111
- let port: u16 = input.parse().expect("Invalid port");
112
-
113
- // Do: Return Result
114
- let port: u16 = input.parse().map_err(|_| ConfigError::InvalidPort)?;
115
-
116
- // Do: Provide default
117
- let port: u16 = input.parse().unwrap_or(8080);
118
-
119
- // Do: Handle explicitly
120
- let port: u16 = match input.parse() {
121
- Ok(p) => p,
122
- Err(_) => {
123
- log::warn!("Invalid port '{}', using default", input);
124
- 8080
125
- }
126
- };
127
- ```
128
-
129
- ## See Also
130
-
131
- - [err-no-unwrap-prod](./err-no-unwrap-prod.md) - Avoiding unwrap in production
132
- - [err-result-over-panic](./err-result-over-panic.md) - When to return Result
133
- - [api-parse-dont-validate](./api-parse-dont-validate.md) - Type-driven validation
@@ -1,152 +0,0 @@
1
- # err-from-impl
2
-
3
- > Implement `From<E>` for error conversions to enable `?` operator
4
-
5
- ## Why It Matters
6
-
7
- The `?` operator automatically converts errors using `From` trait. By implementing `From<SourceError> for YourError`, you enable seamless error propagation without explicit `.map_err()` calls. This makes error handling code cleaner and ensures consistent error wrapping throughout your codebase.
8
-
9
- ## Bad
10
-
11
- ```rust
12
- #[derive(Debug)]
13
- enum AppError {
14
- Io(std::io::Error),
15
- Parse(serde_json::Error),
16
- Database(diesel::result::Error),
17
- }
18
-
19
- fn load_config(path: &str) -> Result<Config, AppError> {
20
- let content = std::fs::read_to_string(path)
21
- .map_err(|e| AppError::Io(e))?; // Manual conversion everywhere
22
-
23
- let config: Config = serde_json::from_str(&content)
24
- .map_err(|e| AppError::Parse(e))?; // Repeated boilerplate
25
-
26
- save_to_db(&config)
27
- .map_err(|e| AppError::Database(e))?; // Gets tedious
28
-
29
- Ok(config)
30
- }
31
- ```
32
-
33
- ## Good
34
-
35
- ```rust
36
- #[derive(Debug)]
37
- enum AppError {
38
- Io(std::io::Error),
39
- Parse(serde_json::Error),
40
- Database(diesel::result::Error),
41
- }
42
-
43
- // Implement From for each source error type
44
- impl From<std::io::Error> for AppError {
45
- fn from(err: std::io::Error) -> Self {
46
- AppError::Io(err)
47
- }
48
- }
49
-
50
- impl From<serde_json::Error> for AppError {
51
- fn from(err: serde_json::Error) -> Self {
52
- AppError::Parse(err)
53
- }
54
- }
55
-
56
- impl From<diesel::result::Error> for AppError {
57
- fn from(err: diesel::result::Error) -> Self {
58
- AppError::Database(err)
59
- }
60
- }
61
-
62
- fn load_config(path: &str) -> Result<Config, AppError> {
63
- let content = std::fs::read_to_string(path)?; // Auto-converts
64
- let config: Config = serde_json::from_str(&content)?; // Clean!
65
- save_to_db(&config)?;
66
- Ok(config)
67
- }
68
- ```
69
-
70
- ## Use thiserror for Automatic From
71
-
72
- ```rust
73
- use thiserror::Error;
74
-
75
- #[derive(Error, Debug)]
76
- enum AppError {
77
- #[error("IO error: {0}")]
78
- Io(#[from] std::io::Error), // Auto-generates From impl
79
-
80
- #[error("Parse error: {0}")]
81
- Parse(#[from] serde_json::Error), // #[from] does the work
82
-
83
- #[error("Database error: {0}")]
84
- Database(#[from] diesel::result::Error),
85
- }
86
-
87
- // Now ? just works
88
- fn load_config(path: &str) -> Result<Config, AppError> {
89
- let content = std::fs::read_to_string(path)?;
90
- let config: Config = serde_json::from_str(&content)?;
91
- save_to_db(&config)?;
92
- Ok(config)
93
- }
94
- ```
95
-
96
- ## From with Context
97
-
98
- Sometimes you need to add context during conversion:
99
-
100
- ```rust
101
- #[derive(Error, Debug)]
102
- enum ConfigError {
103
- #[error("Failed to read config from '{path}': {source}")]
104
- ReadFailed {
105
- path: String,
106
- #[source]
107
- source: std::io::Error,
108
- },
109
- }
110
-
111
- // Can't use #[from] when you need extra context
112
- fn load_config(path: &str) -> Result<Config, ConfigError> {
113
- let content = std::fs::read_to_string(path)
114
- .map_err(|source| ConfigError::ReadFailed {
115
- path: path.to_string(),
116
- source,
117
- })?;
118
- // ...
119
- }
120
-
121
- // Or use anyhow for ad-hoc context
122
- use anyhow::{Context, Result};
123
-
124
- fn load_config(path: &str) -> Result<Config> {
125
- let content = std::fs::read_to_string(path)
126
- .with_context(|| format!("Failed to read config from '{}'", path))?;
127
- // ...
128
- }
129
- ```
130
-
131
- ## Blanket From Implementations
132
-
133
- Be careful with blanket implementations:
134
-
135
- ```rust
136
- // ❌ Too broad - conflicts with other From impls
137
- impl<E: std::error::Error> From<E> for AppError {
138
- fn from(err: E) -> Self {
139
- AppError::Other(err.to_string())
140
- }
141
- }
142
-
143
- // ✅ Specific implementations
144
- impl From<std::io::Error> for AppError { ... }
145
- impl From<ParseIntError> for AppError { ... }
146
- ```
147
-
148
- ## See Also
149
-
150
- - [err-thiserror-lib](./err-thiserror-lib.md) - Using thiserror for libraries
151
- - [err-source-chain](./err-source-chain.md) - Preserving error chains
152
- - [err-question-mark](./err-question-mark.md) - The ? operator
@@ -1,124 +0,0 @@
1
- # err-lowercase-msg
2
-
3
- > Start error messages lowercase, no trailing punctuation
4
-
5
- ## Why It Matters
6
-
7
- Error messages are often chained, logged, or displayed with additional context. Consistent formatting—lowercase start, no trailing period—allows clean composition: "failed to load config: invalid JSON: unexpected token". Mixed case and punctuation create awkward output: "Failed to load config.: Invalid JSON.: Unexpected token.".
8
-
9
- ## Bad
10
-
11
- ```rust
12
- use thiserror::Error;
13
-
14
- #[derive(Error, Debug)]
15
- enum ConfigError {
16
- #[error("Failed to read config file.")] // Capital F, trailing period
17
- ReadFailed(#[from] std::io::Error),
18
-
19
- #[error("Invalid JSON format!")] // Capital I, exclamation
20
- ParseFailed(#[from] serde_json::Error),
21
-
22
- #[error("The requested key was not found")] // Reads like a sentence
23
- KeyNotFound(String),
24
- }
25
-
26
- // Chained output: "Config load error: Failed to read config file.: No such file"
27
- // Awkward capitalization and punctuation
28
- ```
29
-
30
- ## Good
31
-
32
- ```rust
33
- use thiserror::Error;
34
-
35
- #[derive(Error, Debug)]
36
- enum ConfigError {
37
- #[error("failed to read config file")] // lowercase, no period
38
- ReadFailed(#[from] std::io::Error),
39
-
40
- #[error("invalid JSON format")] // lowercase, no period
41
- ParseFailed(#[from] serde_json::Error),
42
-
43
- #[error("key not found: {0}")] // lowercase, data at end
44
- KeyNotFound(String),
45
- }
46
-
47
- // Chained output: "config load error: failed to read config file: no such file"
48
- // Clean, consistent
49
- ```
50
-
51
- ## Rust Standard Library Convention
52
-
53
- The standard library follows this convention:
54
-
55
- ```rust
56
- // std::io::Error messages
57
- "entity not found"
58
- "permission denied"
59
- "connection refused"
60
-
61
- // std::num::ParseIntError
62
- "invalid digit found in string"
63
-
64
- // std::str::Utf8Error
65
- "invalid utf-8 sequence"
66
- ```
67
-
68
- ## Formatting Guidelines
69
-
70
- | Do | Don't |
71
- |----|-------|
72
- | `"failed to parse config"` | `"Failed to parse config."` |
73
- | `"invalid input: expected number"` | `"Invalid input - expected a number!"` |
74
- | `"connection timed out after {0}s"` | `"Connection Timed Out After {0} seconds."` |
75
- | `"key '{0}' not found"` | `"Key Not Found: {0}"` |
76
-
77
- ## Context Addition Pattern
78
-
79
- ```rust
80
- use anyhow::{Context, Result};
81
-
82
- fn load_user(id: u64) -> Result<User> {
83
- let data = fetch(id)
84
- .with_context(|| format!("failed to fetch user {}", id))?;
85
-
86
- parse_user(data)
87
- .with_context(|| "failed to parse user data")?
88
- }
89
-
90
- // Output: "failed to fetch user 42: connection refused"
91
- // All lowercase, clean chain
92
- ```
93
-
94
- ## Display vs Debug
95
-
96
- ```rust
97
- #[derive(Error, Debug)]
98
- #[error("invalid configuration")] // Display: for users/logs
99
- pub struct ConfigError {
100
- path: PathBuf,
101
- source: io::Error,
102
- }
103
-
104
- // Debug output (for developers) can have more detail
105
- // Display output (for users) should be clean
106
- ```
107
-
108
- ## When to Use Capitals
109
-
110
- ```rust
111
- // Proper nouns / acronyms keep their case
112
- #[error("invalid JSON syntax")] // JSON is an acronym
113
- #[error("OAuth token expired")] // OAuth is a proper noun
114
- #[error("HTTP request failed")] // HTTP is an acronym
115
-
116
- // Error codes can be uppercase
117
- #[error("error code E0001: invalid input")]
118
- ```
119
-
120
- ## See Also
121
-
122
- - [err-thiserror-lib](./err-thiserror-lib.md) - Error definition with thiserror
123
- - [err-context-chain](./err-context-chain.md) - Adding context to errors
124
- - [doc-examples-section](./doc-examples-section.md) - Documentation conventions
@@ -1,115 +0,0 @@
1
- # err-no-unwrap-prod
2
-
3
- > Avoid `unwrap()` in production code; use `?`, `expect()`, or handle errors
4
-
5
- ## Why It Matters
6
-
7
- `unwrap()` panics on `None` or `Err` without any context about what went wrong. In production, this creates cryptic crash messages that are hard to debug. Either propagate errors with `?`, use `expect()` with a message explaining the invariant, or handle the error explicitly.
8
-
9
- ## Bad
10
-
11
- ```rust
12
- fn process_request(req: Request) -> Response {
13
- let user_id = req.headers.get("X-User-Id").unwrap(); // Why did it fail?
14
- let user = database.find_user(user_id).unwrap(); // Which operation?
15
- let data = user.preferences.get("theme").unwrap(); // No context
16
-
17
- Response::new(data)
18
- }
19
-
20
- // Crash message: "called `Option::unwrap()` on a `None` value"
21
- // Where? Why? No idea.
22
- ```
23
-
24
- ## Good
25
-
26
- ```rust
27
- // Option 1: Propagate with ?
28
- fn process_request(req: Request) -> Result<Response, AppError> {
29
- let user_id = req.headers
30
- .get("X-User-Id")
31
- .ok_or(AppError::MissingHeader("X-User-Id"))?;
32
-
33
- let user = database.find_user(user_id)?;
34
-
35
- let data = user.preferences
36
- .get("theme")
37
- .ok_or(AppError::MissingPreference("theme"))?;
38
-
39
- Ok(Response::new(data))
40
- }
41
-
42
- // Option 2: expect() for invariants (not user input)
43
- fn get_config_value(&self, key: &str) -> &str {
44
- self.config
45
- .get(key)
46
- .expect("BUG: required config key missing after validation")
47
- }
48
-
49
- // Option 3: Provide defaults
50
- fn get_theme(user: &User) -> &str {
51
- user.preferences
52
- .get("theme")
53
- .unwrap_or(&"default")
54
- }
55
-
56
- // Option 4: Match for complex handling
57
- fn process_optional(value: Option<Data>) -> ProcessedData {
58
- match value {
59
- Some(data) => process(data),
60
- None => {
61
- log::warn!("No data provided, using fallback");
62
- ProcessedData::default()
63
- }
64
- }
65
- }
66
- ```
67
-
68
- ## `expect()` vs `unwrap()`
69
-
70
- ```rust
71
- // Bad: no context
72
- let port = config.get("port").unwrap();
73
-
74
- // Better: explains the invariant
75
- let port = config.get("port")
76
- .expect("config must contain 'port' after validation");
77
-
78
- // Best: propagate if it's not truly an invariant
79
- let port = config.get("port")
80
- .ok_or_else(|| ConfigError::MissingKey("port"))?;
81
- ```
82
-
83
- ## Alternatives to unwrap()
84
-
85
- | Situation | Use Instead |
86
- |-----------|-------------|
87
- | Can propagate error | `?` operator |
88
- | Has sensible default | `unwrap_or()`, `unwrap_or_default()` |
89
- | Default requires computation | `unwrap_or_else(\|\| ...)` |
90
- | Internal invariant | `expect("explanation")` |
91
- | Need to handle both cases | `match` or `if let` |
92
-
93
- ## Clippy Lints
94
-
95
- ```toml
96
- # Cargo.toml
97
- [lints.clippy]
98
- unwrap_used = "warn" # Warn on unwrap()
99
- expect_used = "warn" # Also warn on expect() (stricter)
100
- ```
101
-
102
- ```rust
103
- // Allow in specific places where it's justified
104
- #[allow(clippy::unwrap_used)]
105
- fn definitely_safe() {
106
- // Unwrap is safe here because...
107
- let x = Some(5).unwrap();
108
- }
109
- ```
110
-
111
- ## See Also
112
-
113
- - [err-result-over-panic](./err-result-over-panic.md) - Return Result instead of panicking
114
- - [err-expect-bugs-only](./err-expect-bugs-only.md) - When expect() is appropriate
115
- - [anti-unwrap-abuse](./anti-unwrap-abuse.md) - Patterns for avoiding unwrap
@@ -1,151 +0,0 @@
1
- # err-question-mark
2
-
3
- > Use `?` operator for clean propagation
4
-
5
- ## Why It Matters
6
-
7
- The `?` operator is Rust's idiomatic way to propagate errors. It's concise, readable, and automatically converts between compatible error types using `From`. It replaces verbose `match` or `unwrap()` calls.
8
-
9
- ## Bad
10
-
11
- ```rust
12
- // Verbose match-based error handling
13
- fn load_config() -> Result<Config, Error> {
14
- let content = match std::fs::read_to_string("config.toml") {
15
- Ok(c) => c,
16
- Err(e) => return Err(Error::Io(e)),
17
- };
18
-
19
- let config = match toml::from_str(&content) {
20
- Ok(c) => c,
21
- Err(e) => return Err(Error::Parse(e)),
22
- };
23
-
24
- Ok(config)
25
- }
26
-
27
- // Or worse - using unwrap
28
- fn load_config_bad() -> Config {
29
- let content = std::fs::read_to_string("config.toml").unwrap();
30
- toml::from_str(&content).unwrap()
31
- }
32
- ```
33
-
34
- ## Good
35
-
36
- ```rust
37
- fn load_config() -> Result<Config, Error> {
38
- let content = std::fs::read_to_string("config.toml")?;
39
- let config = toml::from_str(&content)?;
40
- Ok(config)
41
- }
42
-
43
- // Even more concise
44
- fn load_config() -> Result<Config, Error> {
45
- Ok(toml::from_str(&std::fs::read_to_string("config.toml")?)?)
46
- }
47
- ```
48
-
49
- ## How ? Works
50
-
51
- ```rust
52
- // This:
53
- let x = expr?;
54
-
55
- // Expands roughly to:
56
- let x = match expr {
57
- Ok(val) => val,
58
- Err(err) => return Err(From::from(err)),
59
- };
60
- ```
61
-
62
- ## Combining with Context
63
-
64
- ```rust
65
- use anyhow::{Context, Result};
66
-
67
- fn load_user(id: u64) -> Result<User> {
68
- let path = format!("users/{}.json", id);
69
-
70
- let content = std::fs::read_to_string(&path)
71
- .with_context(|| format!("failed to read user file: {}", path))?;
72
-
73
- let user: User = serde_json::from_str(&content)
74
- .context("failed to parse user JSON")?;
75
-
76
- Ok(user)
77
- }
78
- ```
79
-
80
- ## ? with Option
81
-
82
- ```rust
83
- fn get_first_word(text: &str) -> Option<&str> {
84
- let first_line = text.lines().next()?;
85
- let first_word = first_line.split_whitespace().next()?;
86
- Some(first_word)
87
- }
88
-
89
- // Convert Option to Result
90
- fn get_required_config(key: &str) -> Result<String, Error> {
91
- config.get(key)
92
- .cloned()
93
- .ok_or_else(|| Error::MissingConfig(key.to_string()))
94
- }
95
- ```
96
-
97
- ## Error Type Conversion
98
-
99
- ```rust
100
- use thiserror::Error;
101
-
102
- #[derive(Error, Debug)]
103
- enum MyError {
104
- #[error("io error")]
105
- Io(#[from] std::io::Error), // Auto From impl
106
-
107
- #[error("parse error")]
108
- Parse(#[from] serde_json::Error), // Auto From impl
109
- }
110
-
111
- fn process() -> Result<(), MyError> {
112
- // ? automatically converts io::Error to MyError via From
113
- let content = std::fs::read_to_string("file.txt")?;
114
-
115
- // ? automatically converts serde_json::Error to MyError
116
- let data: Data = serde_json::from_str(&content)?;
117
-
118
- Ok(())
119
- }
120
- ```
121
-
122
- ## In main()
123
-
124
- ```rust
125
- // Option 1: Return Result from main
126
- fn main() -> Result<(), Box<dyn std::error::Error>> {
127
- let config = load_config()?;
128
- run_app(config)?;
129
- Ok(())
130
- }
131
-
132
- // Option 2: Handle in main, exit on error
133
- fn main() {
134
- if let Err(e) = run() {
135
- eprintln!("Error: {:#}", e);
136
- std::process::exit(1);
137
- }
138
- }
139
-
140
- fn run() -> anyhow::Result<()> {
141
- let config = load_config()?;
142
- run_app(config)?;
143
- Ok(())
144
- }
145
- ```
146
-
147
- ## See Also
148
-
149
- - [err-context-chain](err-context-chain.md) - Add context with .context()
150
- - [err-from-impl](err-from-impl.md) - Use #[from] for automatic conversion
151
- - [err-anyhow-app](err-anyhow-app.md) - Use anyhow for applications