@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,143 @@
1
+ ---
2
+ name: code-reviewer
3
+ description: Persona skill — review code like a senior engineer. Prioritize correctness, security, clarity over taste. Overlay on top of language + end skills. For the checklist detail, see `coding-standards/references/code-review.md`.
4
+ origin: agency-agents-fork + original (https://github.com/msitarzewski/agency-agents, MIT)
5
+ ---
6
+
7
+ # Code Reviewer
8
+
9
+ Review with intention. This is a **mindset overlay** — for the structured checklist, see [`coding-standards/references/code-review.md`](../coding-standards/references/code-review.md).
10
+
11
+ ## When to load
12
+
13
+ - Reviewing a PR (yours or someone else's)
14
+ - Writing a self-review checklist before opening a PR
15
+ - Training a more junior reviewer (what to look for, in what order)
16
+
17
+ ## The posture
18
+
19
+ 1. **Correctness before style.** Lint is a machine's job. Humans find logic bugs, missing edges, bad abstractions.
20
+ 2. **Simplicity is a feature.** Fewer moving parts = fewer bugs. Prefer the shorter correct solution.
21
+ 3. **Review the diff, think about the system.** A clean diff that makes the system messier is a net negative.
22
+ 4. **Comment to teach, not to score.** The author reads every comment. "This is wrong" gets worked around; "here's why X breaks when Y happens" teaches.
23
+ 5. **Approve or block — decide.** "LGTM but…" is indecision. Say yes or no.
24
+ 6. **Respond quickly, even partially.** "Looking at this now, initial thoughts below" beats silence.
25
+ 7. **Trust but verify.** Author says "tested locally"; the diff must still support that claim with a test or a clear manual-test description.
26
+
27
+ ## Priority order (top first)
28
+
29
+ Walk through in this order. Spend minutes on each upper item before considering the next.
30
+
31
+ 1. **Understand the change.** What problem does this solve? Is this the right fix or a symptom patch? Is there a simpler approach?
32
+ 2. **Correctness.** Happy path + edges: empty / duplicate / concurrent / partial failure. Race conditions. Order-of-operations.
33
+ 3. **Security.** Input validation at boundary. SQL / command / template injection. Auth/authz check. Secret handling.
34
+ 4. **Tests.** Does a test exist that would fail without this fix? Edge cases covered? Flaky patterns?
35
+ 5. **Data / migrations.** Backward compatible with running code during deploy? Backfill safe on large tables? Reversible?
36
+ 6. **Observability.** Enough log / metric to diagnose a failure? New alerts needed?
37
+ 7. **Layering.** Business logic stays out of adapters. Framework types stay out of the domain.
38
+ 8. **Style.** Names, formatting, dead code. Last.
39
+
40
+ If the formatter and linter disagree with the code, the PR shouldn't have reached you. Don't spend review time on what tooling catches.
41
+
42
+ ## Comment vocabulary
43
+
44
+ Small, predictable prefixes so the author knows what blocks.
45
+
46
+ | Prefix | Meaning | Action |
47
+ |---|---|---|
48
+ | `Blocker:` | Must fix before merge | Don't approve |
49
+ | `Question:` | I don't understand | Ask |
50
+ | `Suggestion:` | Consider, non-blocking | Approve anyway |
51
+ | `Nit:` | Style / taste | Approve |
52
+ | `Praise:` | This is good | Approve (and mean it) |
53
+
54
+ If you only left `Nit:` / `Suggestion:`, **approve**. Don't hold up a PR for taste.
55
+
56
+ ## Good review comments
57
+
58
+ ```
59
+ Blocker: This 500s when `roles` is empty (line 43 assumes at least one role).
60
+ Can you add a test with an empty roles list?
61
+
62
+ Question: Why retry on 401? That looks like a permanent auth failure, not transient.
63
+
64
+ Suggestion: Pull this parse block into a helper — it's duplicated in orders.py:33.
65
+
66
+ Praise: Nice refactor. Untangled what I've been worried about for months.
67
+
68
+ Nit: `usr` → `user`.
69
+ ```
70
+
71
+ ## Bad review comments
72
+
73
+ ```
74
+ "This is weird." ← not actionable
75
+ "Why would you do it this way?" ← confrontational; say what you'd prefer
76
+ "I would have done X." ← if X is better, ask for X
77
+ "FYI, there's a library for this." ← link, justify, or drop
78
+ Long digressions about architecture ← file a separate issue
79
+ ```
80
+
81
+ ## What you check no matter what
82
+
83
+ - **"What happens when X is null / empty / wrong type?"** — trace each input.
84
+ - **"What's the failure response visible to the user / caller?"** — status code, error shape, logs.
85
+ - **"What's new in prod that wasn't there before?"** — new dep, new env var, new migration, new cron.
86
+ - **"Is anything silently caught?"** — every `catch` clause, grep for bare `except:` / `catch (e) {}`.
87
+ - **"Does this introduce a new coupling?"** — new import between modules that shouldn't know each other.
88
+
89
+ ## What you let go
90
+
91
+ - **Personal stylistic preferences.** If the code follows the team's convention, even if you wouldn't write it that way, that's fine.
92
+ - **Perfection over shipping.** A good-enough change now beats a perfect one in three weeks.
93
+ - **Every abstraction could be prettier.** So could yours.
94
+
95
+ ## Red flags to always flag
96
+
97
+ - `TODO` / `FIXME` with no owner or date.
98
+ - Commented-out code.
99
+ - Tests with no assertions (or a single `assertTrue(true)`).
100
+ - `console.log` / `print` left in.
101
+ - Catch-all exception handlers that don't log or re-raise.
102
+ - Hard-coded secrets / IPs / URLs.
103
+ - New dependencies not justified in the PR description.
104
+ - Huge diffs that mix refactor and behaviour change.
105
+ - `any` / `dynamic` / `interface{}` in typed code without comment.
106
+ - Changes to shared utilities without review from those utilities' owners.
107
+
108
+ ## Size discipline
109
+
110
+ | Diff size | What to do |
111
+ |---|---|
112
+ | < 100 lines | Thorough review |
113
+ | 100–400 | Careful review |
114
+ | 400–1000 | Skim; ask to split |
115
+ | 1000+ | Send back: split this |
116
+
117
+ A large PR that's rubber-stamped is worse than no review.
118
+
119
+ ## Review response time
120
+
121
+ - First response within one working day.
122
+ - Partial response early is better than silent perfect response.
123
+ - Blocking a PR for days with no reason is a failure of the reviewer.
124
+
125
+ ## When to push for changes vs. accept
126
+
127
+ Push when:
128
+ - Correctness / security concern.
129
+ - Architecture drift that compounds (a new bad pattern that will be copied).
130
+ - Tests missing for a non-trivial change.
131
+
132
+ Accept when:
133
+ - Small stylistic preferences.
134
+ - "I would have done it differently" (without concrete "better" reason).
135
+ - Refactor opportunities not on the change's path.
136
+
137
+ Follow up separately for the accept cases. Don't use PR review as the lever for every idea you've ever had.
138
+
139
+ ## Pair with
140
+
141
+ - [`coding-standards`](../coding-standards/SKILL.md) — principles and checklists.
142
+ - The relevant language skill for the language being reviewed.
143
+ - [`backend`](../backend/SKILL.md) / [`frontend`](../frontend/SKILL.md) — the domain of what's being reviewed.
@@ -0,0 +1,60 @@
1
+ ---
2
+ name: coding-standards
3
+ description: Cross-language engineering principles — TDD, naming, error strategy, code review, commits/PRs, clean code. Load alongside any language / end skill. Principles only; language-specific syntax lives in the language skill.
4
+ origin: ecc-fork + original (https://github.com/affaan-m/everything-claude-code, MIT)
5
+ ---
6
+
7
+ # Coding Standards
8
+
9
+ Language- and stack-neutral engineering principles. Covers the "what" and "why"; language skills cover the "how".
10
+
11
+ ## When to load
12
+
13
+ - Any coding task (load this + a language skill + an end skill)
14
+ - Code review
15
+ - Writing tests
16
+ - Opening a PR
17
+ - Deciding where error handling / retries / logging live
18
+
19
+ ## Hierarchy of rules
20
+
21
+ 1. **Correctness** — the code does what's intended
22
+ 2. **Readability** — the next person (or you, six months later) can follow it
23
+ 3. **Testability** — behavior is verifiable without the universe
24
+ 4. **Simplicity** — least code and least abstraction that meet 1–3
25
+ 5. **Performance** — only after 1–4 are met
26
+
27
+ In that order. A fast bug is worse than a slow correct answer.
28
+
29
+ ## Core commitments
30
+
31
+ - **Tests first** for anything non-trivial. Write a failing test, make it pass, refactor.
32
+ - **Specific exceptions only.** Never `except:` bare. Never swallow without logging.
33
+ - **Name things for intent, not implementation.** `users_over_18` > `filtered_list_2`.
34
+ - **Small functions that do one thing.** If you can't say what it does in one sentence, split it.
35
+ - **No comments that restate the code.** Comments explain the *why*, never the *what*.
36
+ - **No speculative abstractions.** Two similar snippets: duplicate. Three: consider abstracting.
37
+ - **PRs under 400 lines of diff.** Anything larger, split.
38
+
39
+ ## How to use references
40
+
41
+ | Reference | When to load |
42
+ |---|---|
43
+ | [`references/tdd.md`](references/tdd.md) | Starting a feature, writing tests, unclear what "done" means |
44
+ | [`references/naming.md`](references/naming.md) | Naming a function, variable, module, endpoint, feature flag |
45
+ | [`references/error-strategy.md`](references/error-strategy.md) | Deciding whether to raise, return a result, log, or swallow |
46
+ | [`references/code-review.md`](references/code-review.md) | Reviewing a PR (yours or someone else's) |
47
+ | [`references/commits-and-prs.md`](references/commits-and-prs.md) | Writing a commit message; opening / sizing a PR |
48
+ | [`references/clean-code.md`](references/clean-code.md) | Function shape, DRY vs WET, comments, dead code, magic numbers |
49
+
50
+ ## Forbidden patterns (auto-reject)
51
+
52
+ - Commented-out code committed to main
53
+ - `TODO` without an owner or date
54
+ - Tests that don't actually assert anything
55
+ - Mutable global state for business logic
56
+ - Dead code kept "just in case"
57
+ - Magic numbers / strings without named constants
58
+ - Catch-all error handlers without re-raise or specific recovery
59
+ - Abstractions that have exactly one implementation
60
+ - PRs that mix a refactor with a feature change
@@ -0,0 +1,258 @@
1
+ # Clean Code
2
+
3
+ Function shape, DRY vs WET, comments, dead code, magic numbers. Language-neutral hygiene.
4
+
5
+ ## Functions
6
+
7
+ ### One thing
8
+
9
+ A function should do one thing, at one level of abstraction. If the function's name needs "and", split it.
10
+
11
+ ```
12
+ # ❌
13
+ def validate_and_save_user(user): ...
14
+
15
+ # ✅
16
+ def validate(user): ...
17
+ def save(user): ...
18
+
19
+ def register_user(user):
20
+ validate(user)
21
+ save(user)
22
+ ```
23
+
24
+ ### Small
25
+
26
+ Rough targets, not dogma:
27
+ - Functions ≤ 20 lines most of the time.
28
+ - If a function has three indentation levels, consider extracting.
29
+ - A function you can't see in one screen is a warning sign.
30
+
31
+ Exceptions: a switch-like dispatch that's naturally long is fine. A 200-line function because you kept adding cases is not.
32
+
33
+ ### Arguments — few
34
+
35
+ Zero is best. One is fine. Two is OK. Three is suspicious. Four is a refactor.
36
+
37
+ ```
38
+ # ❌
39
+ create_user(name, email, age, role, active, parent_id, billing_addr, shipping_addr, ...)
40
+
41
+ # ✅ — group related args
42
+ create_user(identity, profile, permissions)
43
+ ```
44
+
45
+ Boolean flags doubly so:
46
+
47
+ ```
48
+ # ❌
49
+ render_page(user, is_admin, is_preview, skip_cache)
50
+
51
+ # ✅ — flags mean you're doing two things in one function
52
+ render_page_for_admin(user, options)
53
+ render_preview_page(user)
54
+ ```
55
+
56
+ ### Return one type
57
+
58
+ If a function can return a `User`, or `None`, or a string error code, pick one contract. Use `Optional` or a result type for "success or not found". Don't overload the return to mean three different things.
59
+
60
+ ### Pure where possible
61
+
62
+ Pure = same input produces same output, no side effects. Pure code is trivial to test and reason about. Push side effects (I/O, state mutation, logging) to the edges.
63
+
64
+ ```
65
+ # core: pure
66
+ def calculate_price(items, promo): ...
67
+
68
+ # edge: side effects
69
+ def checkout(items, promo):
70
+ price = calculate_price(items, promo)
71
+ payment = charge(price)
72
+ db.save_order(items, price, payment.id)
73
+ eventBus.publish(OrderPlaced(...))
74
+ ```
75
+
76
+ ## DRY vs WET — know the ratio
77
+
78
+ | Situation | Do |
79
+ |---|---|
80
+ | Two similar snippets | **Duplicate**. Too early to know the shape. |
81
+ | Three similar snippets | Consider abstracting — if the shape is clear. |
82
+ | Four+ similar snippets | Abstract; you've learned what varies. |
83
+
84
+ Bad abstractions cost more than duplication. A wrong shape locks every caller into a detour forever.
85
+
86
+ Rule: abstract when the shape is obvious, not when the count reaches a number.
87
+
88
+ ## Comments
89
+
90
+ Default: don't write one. If you do, explain *why*, never *what*.
91
+
92
+ ```
93
+ # ❌ noise
94
+ i += 1 # increment i
95
+
96
+ def save(user):
97
+ # saves a user
98
+ db.insert(user)
99
+
100
+ # ✅ non-obvious why
101
+ # Upstream API returns 503 for ~500ms during leader election;
102
+ # retry window tuned from their SRE post, not ours.
103
+ sleep(0.6)
104
+
105
+ # HACK: patch until [TICKET-481] lifts the 100-col DB constraint.
106
+ name = name[:100]
107
+ ```
108
+
109
+ Delete comments that:
110
+ - Restate the code (`# loop over items`)
111
+ - Restate the function name (`# validates input`)
112
+ - Are out of date (the code changed; the comment didn't)
113
+ - Reference past states (`# was previously doing X`)
114
+
115
+ Git remembers history. Code is the present tense.
116
+
117
+ ### Docstrings
118
+
119
+ For public functions/classes. Describe contract, not implementation.
120
+
121
+ ```
122
+ # ✅
123
+ """Return the canonical URL for this resource, or None if it isn't published."""
124
+
125
+ # ❌
126
+ """This function takes a resource and returns its URL by looking up the slug in the DB."""
127
+ ```
128
+
129
+ One sentence is often enough. Longer docstrings: inputs, outputs, errors, side effects.
130
+
131
+ ## Dead code — delete it
132
+
133
+ If a function, class, or branch is unreachable, remove it. "Just in case" is not a reason to keep dead code.
134
+
135
+ - Unused imports → remove
136
+ - Commented-out code → remove (git has it)
137
+ - `if False:` branches → remove
138
+ - `TODO` from two years ago → remove or fix
139
+
140
+ Dead code rots. It confuses readers, breaks grep, and occasionally gets re-animated with stale assumptions.
141
+
142
+ ## Magic numbers and strings
143
+
144
+ Named constants when the value has meaning. Literals are fine when they're self-explanatory.
145
+
146
+ ```
147
+ # ✅ named — intent is clear
148
+ MAX_LOGIN_ATTEMPTS = 5
149
+ DEFAULT_PAGE_SIZE = 20
150
+ HTTP_OK = 200
151
+
152
+ # ✅ literal — self-explanatory in context
153
+ str[:10]
154
+ for i in range(3): ...
155
+ x * 2
156
+
157
+ # ❌ magic
158
+ if user.attempts > 5: ...
159
+ if status == "pa": # what's "pa"?
160
+ ```
161
+
162
+ ## Early return over nested conditions
163
+
164
+ Flatter reads better than deeply nested `if`s.
165
+
166
+ ```
167
+ # ❌ pyramid of doom
168
+ def process(user):
169
+ if user is not None:
170
+ if user.is_active:
171
+ if user.has_permission():
172
+ if user.payment_method_valid():
173
+ return do_thing(user)
174
+ return None
175
+
176
+ # ✅ guard clauses, early returns
177
+ def process(user):
178
+ if user is None: return None
179
+ if not user.is_active: return None
180
+ if not user.has_permission(): return None
181
+ if not user.payment_method_valid(): return None
182
+ return do_thing(user)
183
+ ```
184
+
185
+ ## Avoid mutable global state
186
+
187
+ Global mutables are action at a distance. A test sets a flag → unrelated tests fail.
188
+
189
+ ```
190
+ # ❌
191
+ _CURRENT_USER = None
192
+
193
+ def set_user(u): global _CURRENT_USER; _CURRENT_USER = u
194
+ def current(): return _CURRENT_USER
195
+
196
+ # ✅ pass explicitly, or use a request-scoped context
197
+ def handler(req, user):
198
+ current_user = resolve_user(req)
199
+ ...
200
+ ```
201
+
202
+ Request-scoped context objects are fine (HTTP request context, trace context). Globals for business data are not.
203
+
204
+ ## Avoid clever one-liners
205
+
206
+ If a line needs 30 seconds to parse, it costs every future reader 30 seconds.
207
+
208
+ ```
209
+ # ❌
210
+ return [next((v for v in xs if p(v, k)), default) for k in sorted({f(x) for x in data} - skip)]
211
+
212
+ # ✅
213
+ keys = {f(x) for x in data} - skip
214
+ out = []
215
+ for k in sorted(keys):
216
+ match = next((v for v in xs if p(v, k)), default)
217
+ out.append(match)
218
+ return out
219
+ ```
220
+
221
+ Density ≠ clarity. A loop you can read in one pass beats a comprehension you have to puzzle out.
222
+
223
+ ## Prefer immutability
224
+
225
+ Where the language supports it, prefer immutable values.
226
+
227
+ - Makes reasoning local (a value can't change out from under you)
228
+ - Safer in concurrent code
229
+ - Better cache keys, better log entries
230
+
231
+ Use mutation for internal data structures when performance matters. Don't propagate mutation to the public API.
232
+
233
+ ## Feature flags — clean up
234
+
235
+ Flags are temporary. Long-lived flags become part of the product accidentally.
236
+
237
+ ```
238
+ # a few weeks after launch
239
+ if feature_enabled("partial_shipments"):
240
+ ...
241
+
242
+ # six months later: rollout is done. Inline. Delete the flag.
243
+ ```
244
+
245
+ Track flag age. Delete dead flags. A flag that's been "on for everyone" for three months is technical debt.
246
+
247
+ ## Anti-patterns
248
+
249
+ | Anti-pattern | Fix |
250
+ |---|---|
251
+ | 200-line function | Extract; each piece named for intent |
252
+ | Mixing abstraction levels (business rule + DB call + HTTP call) | Layer: see backend/layering |
253
+ | Flag arguments (`do(x, is_special=True)`) | Split into two functions |
254
+ | "Utils" modules | Split by domain; utils becomes a dumping ground |
255
+ | Deep nesting | Guard clauses, early returns |
256
+ | Duplicated constants across files | Promote to a shared constants module |
257
+ | Commented-out code "in case we need it" | Delete; git has it |
258
+ | Over-abstracted single-use interface | Delete the interface; use the concrete type |
@@ -0,0 +1,192 @@
1
+ # Code Review
2
+
3
+ How to review. How to be reviewed. A checklist that works regardless of language.
4
+
5
+ ## What review is for
6
+
7
+ In order of importance:
8
+
9
+ 1. **Catching defects** — correctness bugs, security issues, data loss paths
10
+ 2. **Sharing knowledge** — both directions; reviewer learns too
11
+ 3. **Maintaining consistency** — convention drift, naming, layering
12
+ 4. **Coaching** — especially for junior → senior flow
13
+ 5. **Rubber-stamping** — never the goal, though sometimes the outcome
14
+
15
+ Review is NOT:
16
+ - A style argument you could have automated (use a formatter)
17
+ - A place to re-litigate architecture decisions already made
18
+ - An opportunity to impose personal preferences as requirements
19
+
20
+ ## Reviewer checklist
21
+
22
+ Go through in this order. Don't start with nits.
23
+
24
+ ### 1. Understand the change
25
+
26
+ - What problem does this solve? (Read the PR description; if it's empty, push back.)
27
+ - Is this the right fix, or is it treating a symptom?
28
+ - Is there a simpler approach that also works?
29
+
30
+ ### 2. Correctness
31
+
32
+ - Does it handle the happy path?
33
+ - What about the edges: empty inputs, duplicates, concurrency, partial failures?
34
+ - What happens on error? Is the error propagation / handling at the right layer?
35
+ - Are there new race conditions? Deadlocks? Order-of-operations assumptions?
36
+
37
+ ### 3. Security
38
+
39
+ - Any user input that isn't validated at the boundary?
40
+ - Any SQL / command / template construction from strings?
41
+ - Any auth/authz check missing? Any leak of existence / enumeration?
42
+ - Any new secret / credential in code or config?
43
+
44
+ ### 4. Tests
45
+
46
+ - Is there a test for the change? (No test on non-trivial change = push back.)
47
+ - Does the test actually fail without the fix? (Reviewer can mentally check this.)
48
+ - Are edge cases tested, not just happy path?
49
+ - Any flaky patterns: sleeps, network calls, order dependencies?
50
+
51
+ ### 5. Data and migrations
52
+
53
+ - Schema change: is it backward compatible with the running code during deploy?
54
+ - Backfill strategy: safe on large tables? rate-limited?
55
+ - Is this reversible? If not, is the forward-only plan documented?
56
+
57
+ ### 6. Observability
58
+
59
+ - Does the new code log errors with enough context (request id, user id)?
60
+ - Are new metrics / dashboards needed? Alerts?
61
+ - Can an oncall diagnose a failure from what's logged?
62
+
63
+ ### 7. Layering & design
64
+
65
+ - Does business logic stay out of adapters? Do adapters stay out of the domain?
66
+ - Any new leakage: framework types into domain, DB rows into API responses?
67
+ - Any abstraction that has exactly one implementation? (Likely premature.)
68
+
69
+ ### 8. Style (last)
70
+
71
+ - Formatter run? Linter clean?
72
+ - Names clear?
73
+ - Any comments that should be removed / added?
74
+
75
+ If the formatter and linter disagree with the code, the PR shouldn't have reached human review.
76
+
77
+ ## How to comment
78
+
79
+ Use a small vocabulary so the author knows what's blocking.
80
+
81
+ | Prefix | Meaning | Action |
82
+ |---|---|---|
83
+ | `Blocker:` | Must fix before merge | Don't approve |
84
+ | `Question:` | I don't understand; please explain | Ask |
85
+ | `Suggestion:` | Consider, non-blocking | Approve anyway |
86
+ | `Nit:` | Style / taste, truly optional | Approve |
87
+ | `Praise:` | This is good; say it | Approve (and mean it) |
88
+
89
+ If you only leave `Nit:` and `Suggestion:`, approve. Don't hold up a PR for taste.
90
+
91
+ ## Good comments
92
+
93
+ ```
94
+ Blocker: This will 500 when `user.roles` is empty (line 43 assumes at least one).
95
+ Can you add a test with an empty roles list?
96
+
97
+ Suggestion: Pull this 3-line parse block into a helper — it's duplicated in
98
+ handlers/orders.py too.
99
+
100
+ Question: Why are we retrying on 401? That looks like the credential is wrong,
101
+ not transient.
102
+
103
+ Nit: `usr` → `user`.
104
+ ```
105
+
106
+ ## Bad comments
107
+
108
+ ```
109
+ "This is weird." ← not actionable
110
+ "Why would you do it this way?" ← confrontational; say what you'd prefer
111
+ "I would have done X." ← if X is better, ask for X; otherwise irrelevant
112
+ "FYI, there's a library for this." ← link, justify, or drop it
113
+ Long digressions about architecture ← file a separate issue
114
+ ```
115
+
116
+ ## Reviewing size
117
+
118
+ | Diff size | Typical quality of review |
119
+ |---|---|
120
+ | < 100 lines | Thorough |
121
+ | 100–400 | Careful |
122
+ | 400–1000 | Skimmed; defects slip |
123
+ | > 1000 | Rubber stamp |
124
+
125
+ If the PR is > 400 lines and not refactor-only (e.g., rename), ask the author to split. Reviewers can't do their job on huge diffs.
126
+
127
+ ## Review speed
128
+
129
+ - Aim to first-respond within one working day.
130
+ - Incremental responses are fine: "looking at it now, initial thoughts below".
131
+ - Blocking a PR for days with no reason is a failure mode.
132
+
133
+ ## Being reviewed
134
+
135
+ Make the reviewer's job easy.
136
+
137
+ ### The PR description
138
+
139
+ ```
140
+ ## What
141
+ One-line summary of the change.
142
+
143
+ ## Why
144
+ Link to ticket / incident. Business / technical reason.
145
+
146
+ ## How
147
+ Brief description of the approach and why this approach.
148
+
149
+ ## Tests
150
+ What was added / run locally. Any manual verification.
151
+
152
+ ## Risks / rollout
153
+ Feature flag? Migration? Rollback plan?
154
+ ```
155
+
156
+ ### Split your PRs
157
+
158
+ - **Refactor** (no behavior change) and **feature** (behavior change) in separate PRs.
159
+ - **Rename** PRs are mechanical — reviewer should only need to confirm "nothing else changed".
160
+ - **Dependency bumps** separate from feature work.
161
+
162
+ ### Respond to all comments
163
+
164
+ - `Fixed.` (with the follow-up commit ref)
165
+ - `Good catch, added a test for that too.`
166
+ - `I see it differently — <reason>. Want to discuss on a call?`
167
+
168
+ Don't leave comments unanswered. "Ignored" on a review is how reviewers stop reviewing carefully.
169
+
170
+ ### Don't take it personally
171
+
172
+ Code is being reviewed, not you. "This is wrong" is about the line, not your worth. If a comment does feel personal, ask the reviewer offline — don't escalate in the PR.
173
+
174
+ ## Approving
175
+
176
+ - **Approve** when you'd be comfortable being paged at 3am because of this code.
177
+ - **Request changes** when there are blockers.
178
+ - **Comment** (neither approve nor block) when you've given feedback but someone more authoritative should approve.
179
+
180
+ Don't approve-and-block ("LGTM but…"). Decide.
181
+
182
+ ## Anti-patterns
183
+
184
+ | Anti-pattern | Why |
185
+ |---|---|
186
+ | Review-bombing with 50 nits | Exhausts the author; misses the real issue |
187
+ | Approving without reading | Wastes the review; defects sneak through |
188
+ | Re-litigating the design at review time | Should have been a design doc earlier |
189
+ | "Can you just rewrite this?" | If true, say specifically why; offer an example |
190
+ | Ignoring your own review comments later | Inconsistent; erodes trust |
191
+ | Big PR → "looks good" after 5 min | Not an actual review |
192
+ | Review as gate without shared standards | Reviewer's mood decides the outcome |