@humanbased/crosscheck 1.2.0-beta.80 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (301) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +388 -149
  3. package/README.zh.md +1 -1
  4. package/crosscheck.config.example.yml +2 -63
  5. package/dist/__tests__/codex.test.js +27 -14
  6. package/dist/__tests__/codex.test.js.map +1 -1
  7. package/dist/__tests__/comment-bodies.test.js +1 -49
  8. package/dist/__tests__/comment-bodies.test.js.map +1 -1
  9. package/dist/__tests__/conflict-resolve.test.js +1 -44
  10. package/dist/__tests__/conflict-resolve.test.js.map +1 -1
  11. package/dist/__tests__/fix.test.js +0 -33
  12. package/dist/__tests__/fix.test.js.map +1 -1
  13. package/dist/__tests__/onboard-preservation.test.js +0 -5
  14. package/dist/__tests__/onboard-preservation.test.js.map +1 -1
  15. package/dist/__tests__/optimize.test.js +0 -2
  16. package/dist/__tests__/optimize.test.js.map +1 -1
  17. package/dist/__tests__/repo-picker.test.js +1 -7
  18. package/dist/__tests__/repo-picker.test.js.map +1 -1
  19. package/dist/__tests__/review-comment-body.test.js +0 -35
  20. package/dist/__tests__/review-comment-body.test.js.map +1 -1
  21. package/dist/__tests__/review-models.test.js +3 -19
  22. package/dist/__tests__/review-models.test.js.map +1 -1
  23. package/dist/__tests__/runner.test.js +1 -29
  24. package/dist/__tests__/runner.test.js.map +1 -1
  25. package/dist/cli.js +0 -29
  26. package/dist/cli.js.map +1 -1
  27. package/dist/commands/onboard.d.ts +0 -11
  28. package/dist/commands/onboard.d.ts.map +1 -1
  29. package/dist/commands/onboard.js +2 -88
  30. package/dist/commands/onboard.js.map +1 -1
  31. package/dist/commands/review.d.ts.map +1 -1
  32. package/dist/commands/review.js +6 -65
  33. package/dist/commands/review.js.map +1 -1
  34. package/dist/commands/run.d.ts.map +1 -1
  35. package/dist/commands/run.js +3 -23
  36. package/dist/commands/run.js.map +1 -1
  37. package/dist/commands/status.d.ts.map +1 -1
  38. package/dist/commands/status.js +1 -53
  39. package/dist/commands/status.js.map +1 -1
  40. package/dist/commands/watch.d.ts.map +1 -1
  41. package/dist/commands/watch.js +6 -52
  42. package/dist/commands/watch.js.map +1 -1
  43. package/dist/config/loader.d.ts +1 -3
  44. package/dist/config/loader.d.ts.map +1 -1
  45. package/dist/config/loader.js +0 -13
  46. package/dist/config/loader.js.map +1 -1
  47. package/dist/config/review-model-tiers.json +3 -3
  48. package/dist/config/schema.d.ts +10 -254
  49. package/dist/config/schema.d.ts.map +1 -1
  50. package/dist/config/schema.js +2 -62
  51. package/dist/config/schema.js.map +1 -1
  52. package/dist/github/client.d.ts +1 -6
  53. package/dist/github/client.d.ts.map +1 -1
  54. package/dist/github/client.js +7 -15
  55. package/dist/github/client.js.map +1 -1
  56. package/dist/issues/ticket-ref.d.ts.map +1 -1
  57. package/dist/issues/ticket-ref.js +5 -6
  58. package/dist/issues/ticket-ref.js.map +1 -1
  59. package/dist/lib/clone.d.ts +0 -1
  60. package/dist/lib/clone.d.ts.map +1 -1
  61. package/dist/lib/clone.js +10 -32
  62. package/dist/lib/clone.js.map +1 -1
  63. package/dist/lib/comment-bodies.d.ts +0 -35
  64. package/dist/lib/comment-bodies.d.ts.map +1 -1
  65. package/dist/lib/comment-bodies.js +9 -43
  66. package/dist/lib/comment-bodies.js.map +1 -1
  67. package/dist/lib/repo-picker.d.ts +0 -3
  68. package/dist/lib/repo-picker.d.ts.map +1 -1
  69. package/dist/lib/repo-picker.js +9 -45
  70. package/dist/lib/repo-picker.js.map +1 -1
  71. package/dist/lib/review-models.d.ts +2 -15
  72. package/dist/lib/review-models.d.ts.map +1 -1
  73. package/dist/lib/review-models.js +6 -26
  74. package/dist/lib/review-models.js.map +1 -1
  75. package/dist/lib/runner.d.ts +0 -12
  76. package/dist/lib/runner.d.ts.map +1 -1
  77. package/dist/lib/runner.js +42 -186
  78. package/dist/lib/runner.js.map +1 -1
  79. package/dist/lib/workflow.d.ts +0 -9
  80. package/dist/lib/workflow.d.ts.map +1 -1
  81. package/dist/lib/workflow.js +0 -20
  82. package/dist/lib/workflow.js.map +1 -1
  83. package/dist/reviewers/claude.d.ts +1 -4
  84. package/dist/reviewers/claude.d.ts.map +1 -1
  85. package/dist/reviewers/claude.js +7 -39
  86. package/dist/reviewers/claude.js.map +1 -1
  87. package/dist/reviewers/codex.d.ts +1 -3
  88. package/dist/reviewers/codex.d.ts.map +1 -1
  89. package/dist/reviewers/codex.js +70 -76
  90. package/dist/reviewers/codex.js.map +1 -1
  91. package/dist/reviewers/conflict-resolve.d.ts +1 -3
  92. package/dist/reviewers/conflict-resolve.d.ts.map +1 -1
  93. package/dist/reviewers/conflict-resolve.js +6 -21
  94. package/dist/reviewers/conflict-resolve.js.map +1 -1
  95. package/dist/reviewers/fix.d.ts +2 -5
  96. package/dist/reviewers/fix.d.ts.map +1 -1
  97. package/dist/reviewers/fix.js +10 -26
  98. package/dist/reviewers/fix.js.map +1 -1
  99. package/get-started.md +4 -139
  100. package/package.json +3 -4
  101. package/assets/icon-256.png +0 -0
  102. package/assets/linear-comment.svg +0 -18
  103. package/assets/linear-onboard.svg +0 -30
  104. package/assets/linear-status.svg +0 -23
  105. package/assets/linear-test.svg +0 -34
  106. package/assets/skills/code-review/.crosscheck-skill.json +0 -9
  107. package/assets/skills/code-review/LICENSE +0 -21
  108. package/assets/skills/code-review/SKILL.md +0 -89
  109. package/assets/skills/code-review/agents/openai.yaml +0 -3
  110. package/assets/skills/code-review-skill/.crosscheck-skill.json +0 -9
  111. package/assets/skills/code-review-skill/LICENSE +0 -21
  112. package/assets/skills/code-review-skill/SKILL.md +0 -231
  113. package/assets/skills/code-review-skill/assets/pr-review-template.md +0 -137
  114. package/assets/skills/code-review-skill/assets/review-checklist.md +0 -123
  115. package/assets/skills/code-review-skill/reference/angular.md +0 -768
  116. package/assets/skills/code-review-skill/reference/architecture-review-guide.md +0 -472
  117. package/assets/skills/code-review-skill/reference/c.md +0 -890
  118. package/assets/skills/code-review-skill/reference/code-quality-universal.md +0 -488
  119. package/assets/skills/code-review-skill/reference/code-review-best-practices.md +0 -136
  120. package/assets/skills/code-review-skill/reference/common-bugs-checklist.md +0 -286
  121. package/assets/skills/code-review-skill/reference/cpp.md +0 -893
  122. package/assets/skills/code-review-skill/reference/cross-cutting/async-concurrency-patterns.md +0 -515
  123. package/assets/skills/code-review-skill/reference/cross-cutting/error-handling-principles.md +0 -492
  124. package/assets/skills/code-review-skill/reference/cross-cutting/n-plus-one-queries.md +0 -309
  125. package/assets/skills/code-review-skill/reference/cross-cutting/sql-injection-prevention.md +0 -308
  126. package/assets/skills/code-review-skill/reference/cross-cutting/xss-prevention.md +0 -264
  127. package/assets/skills/code-review-skill/reference/csharp.md +0 -525
  128. package/assets/skills/code-review-skill/reference/css-less-sass.md +0 -661
  129. package/assets/skills/code-review-skill/reference/django.md +0 -985
  130. package/assets/skills/code-review-skill/reference/fastapi.md +0 -580
  131. package/assets/skills/code-review-skill/reference/go.md +0 -993
  132. package/assets/skills/code-review-skill/reference/java.md +0 -409
  133. package/assets/skills/code-review-skill/reference/java8.md +0 -586
  134. package/assets/skills/code-review-skill/reference/kotlin.md +0 -1018
  135. package/assets/skills/code-review-skill/reference/nestjs.md +0 -593
  136. package/assets/skills/code-review-skill/reference/performance-review-guide.md +0 -816
  137. package/assets/skills/code-review-skill/reference/php.md +0 -684
  138. package/assets/skills/code-review-skill/reference/python.md +0 -1073
  139. package/assets/skills/code-review-skill/reference/qt.md +0 -757
  140. package/assets/skills/code-review-skill/reference/react.md +0 -871
  141. package/assets/skills/code-review-skill/reference/ruby.md +0 -964
  142. package/assets/skills/code-review-skill/reference/rust.md +0 -846
  143. package/assets/skills/code-review-skill/reference/security-review-guide.md +0 -494
  144. package/assets/skills/code-review-skill/reference/svelte.md +0 -1064
  145. package/assets/skills/code-review-skill/reference/swift.md +0 -936
  146. package/assets/skills/code-review-skill/reference/typescript.md +0 -1016
  147. package/assets/skills/code-review-skill/reference/vue.md +0 -924
  148. package/assets/skills/code-review-skill/reference/zig.md +0 -440
  149. package/assets/skills/code-review-skill/scripts/pr-analyzer.py +0 -435
  150. package/assets/skills/code-review-skill/scripts/test_pr_analyzer.py +0 -380
  151. package/assets/skills/codebase-design/.crosscheck-skill.json +0 -9
  152. package/assets/skills/codebase-design/DEEPENING.md +0 -37
  153. package/assets/skills/codebase-design/DESIGN-IT-TWICE.md +0 -44
  154. package/assets/skills/codebase-design/LICENSE +0 -21
  155. package/assets/skills/codebase-design/SKILL.md +0 -114
  156. package/assets/skills/codebase-design/agents/openai.yaml +0 -3
  157. package/assets/skills/diagnosing-bugs/.crosscheck-skill.json +0 -9
  158. package/assets/skills/diagnosing-bugs/LICENSE +0 -21
  159. package/assets/skills/diagnosing-bugs/SKILL.md +0 -134
  160. package/assets/skills/diagnosing-bugs/agents/openai.yaml +0 -3
  161. package/assets/skills/diagnosing-bugs/scripts/hitl-loop.template.sh +0 -41
  162. package/dist/__tests__/can-write-verdict.test.d.ts +0 -2
  163. package/dist/__tests__/can-write-verdict.test.d.ts.map +0 -1
  164. package/dist/__tests__/can-write-verdict.test.js +0 -31
  165. package/dist/__tests__/can-write-verdict.test.js.map +0 -1
  166. package/dist/__tests__/linear-branding.test.d.ts +0 -2
  167. package/dist/__tests__/linear-branding.test.d.ts.map +0 -1
  168. package/dist/__tests__/linear-branding.test.js +0 -156
  169. package/dist/__tests__/linear-branding.test.js.map +0 -1
  170. package/dist/__tests__/linear-client.test.d.ts +0 -2
  171. package/dist/__tests__/linear-client.test.d.ts.map +0 -1
  172. package/dist/__tests__/linear-client.test.js +0 -120
  173. package/dist/__tests__/linear-client.test.js.map +0 -1
  174. package/dist/__tests__/linear-comment.test.d.ts +0 -2
  175. package/dist/__tests__/linear-comment.test.d.ts.map +0 -1
  176. package/dist/__tests__/linear-comment.test.js +0 -151
  177. package/dist/__tests__/linear-comment.test.js.map +0 -1
  178. package/dist/__tests__/linear-identity.test.d.ts +0 -2
  179. package/dist/__tests__/linear-identity.test.d.ts.map +0 -1
  180. package/dist/__tests__/linear-identity.test.js +0 -253
  181. package/dist/__tests__/linear-identity.test.js.map +0 -1
  182. package/dist/__tests__/linear-notify.test.d.ts +0 -2
  183. package/dist/__tests__/linear-notify.test.d.ts.map +0 -1
  184. package/dist/__tests__/linear-notify.test.js +0 -144
  185. package/dist/__tests__/linear-notify.test.js.map +0 -1
  186. package/dist/__tests__/linear-ref.test.d.ts +0 -2
  187. package/dist/__tests__/linear-ref.test.d.ts.map +0 -1
  188. package/dist/__tests__/linear-ref.test.js +0 -261
  189. package/dist/__tests__/linear-ref.test.js.map +0 -1
  190. package/dist/__tests__/linear-test-ref.test.d.ts +0 -2
  191. package/dist/__tests__/linear-test-ref.test.d.ts.map +0 -1
  192. package/dist/__tests__/linear-test-ref.test.js +0 -81
  193. package/dist/__tests__/linear-test-ref.test.js.map +0 -1
  194. package/dist/__tests__/linear-verify.test.d.ts +0 -2
  195. package/dist/__tests__/linear-verify.test.d.ts.map +0 -1
  196. package/dist/__tests__/linear-verify.test.js +0 -132
  197. package/dist/__tests__/linear-verify.test.js.map +0 -1
  198. package/dist/__tests__/linear-worker.test.d.ts +0 -2
  199. package/dist/__tests__/linear-worker.test.d.ts.map +0 -1
  200. package/dist/__tests__/linear-worker.test.js +0 -83
  201. package/dist/__tests__/linear-worker.test.js.map +0 -1
  202. package/dist/__tests__/linear-write-possible.test.d.ts +0 -2
  203. package/dist/__tests__/linear-write-possible.test.d.ts.map +0 -1
  204. package/dist/__tests__/linear-write-possible.test.js +0 -30
  205. package/dist/__tests__/linear-write-possible.test.js.map +0 -1
  206. package/dist/__tests__/repository-guidance.test.d.ts +0 -2
  207. package/dist/__tests__/repository-guidance.test.d.ts.map +0 -1
  208. package/dist/__tests__/repository-guidance.test.js +0 -107
  209. package/dist/__tests__/repository-guidance.test.js.map +0 -1
  210. package/dist/__tests__/review-strategy.test.d.ts +0 -2
  211. package/dist/__tests__/review-strategy.test.d.ts.map +0 -1
  212. package/dist/__tests__/review-strategy.test.js +0 -195
  213. package/dist/__tests__/review-strategy.test.js.map +0 -1
  214. package/dist/__tests__/skill-attribution.test.d.ts +0 -2
  215. package/dist/__tests__/skill-attribution.test.d.ts.map +0 -1
  216. package/dist/__tests__/skill-attribution.test.js +0 -53
  217. package/dist/__tests__/skill-attribution.test.js.map +0 -1
  218. package/dist/__tests__/skill-broker.test.d.ts +0 -2
  219. package/dist/__tests__/skill-broker.test.d.ts.map +0 -1
  220. package/dist/__tests__/skill-broker.test.js +0 -144
  221. package/dist/__tests__/skill-broker.test.js.map +0 -1
  222. package/dist/__tests__/skill-catalog.test.d.ts +0 -2
  223. package/dist/__tests__/skill-catalog.test.d.ts.map +0 -1
  224. package/dist/__tests__/skill-catalog.test.js +0 -40
  225. package/dist/__tests__/skill-catalog.test.js.map +0 -1
  226. package/dist/__tests__/skill-installer.test.d.ts +0 -2
  227. package/dist/__tests__/skill-installer.test.d.ts.map +0 -1
  228. package/dist/__tests__/skill-installer.test.js +0 -96
  229. package/dist/__tests__/skill-installer.test.js.map +0 -1
  230. package/dist/__tests__/skills-config.test.d.ts +0 -2
  231. package/dist/__tests__/skills-config.test.d.ts.map +0 -1
  232. package/dist/__tests__/skills-config.test.js +0 -12
  233. package/dist/__tests__/skills-config.test.js.map +0 -1
  234. package/dist/commands/linear-test.d.ts +0 -18
  235. package/dist/commands/linear-test.d.ts.map +0 -1
  236. package/dist/commands/linear-test.js +0 -130
  237. package/dist/commands/linear-test.js.map +0 -1
  238. package/dist/commands/skill.d.ts +0 -2
  239. package/dist/commands/skill.d.ts.map +0 -1
  240. package/dist/commands/skill.js +0 -16
  241. package/dist/commands/skill.js.map +0 -1
  242. package/dist/config/review-strategy.json +0 -202
  243. package/dist/lib/repository-guidance.d.ts +0 -2
  244. package/dist/lib/repository-guidance.d.ts.map +0 -1
  245. package/dist/lib/repository-guidance.js +0 -55
  246. package/dist/lib/repository-guidance.js.map +0 -1
  247. package/dist/lib/review-strategy.d.ts +0 -62
  248. package/dist/lib/review-strategy.d.ts.map +0 -1
  249. package/dist/lib/review-strategy.js +0 -235
  250. package/dist/lib/review-strategy.js.map +0 -1
  251. package/dist/linear/client.d.ts +0 -18
  252. package/dist/linear/client.d.ts.map +0 -1
  253. package/dist/linear/client.js +0 -67
  254. package/dist/linear/client.js.map +0 -1
  255. package/dist/linear/comment.d.ts +0 -20
  256. package/dist/linear/comment.d.ts.map +0 -1
  257. package/dist/linear/comment.js +0 -57
  258. package/dist/linear/comment.js.map +0 -1
  259. package/dist/linear/identity.d.ts +0 -59
  260. package/dist/linear/identity.d.ts.map +0 -1
  261. package/dist/linear/identity.js +0 -187
  262. package/dist/linear/identity.js.map +0 -1
  263. package/dist/linear/notify.d.ts +0 -35
  264. package/dist/linear/notify.d.ts.map +0 -1
  265. package/dist/linear/notify.js +0 -76
  266. package/dist/linear/notify.js.map +0 -1
  267. package/dist/linear/ref.d.ts +0 -13
  268. package/dist/linear/ref.d.ts.map +0 -1
  269. package/dist/linear/ref.js +0 -90
  270. package/dist/linear/ref.js.map +0 -1
  271. package/dist/linear/verify.d.ts +0 -26
  272. package/dist/linear/verify.d.ts.map +0 -1
  273. package/dist/linear/verify.js +0 -67
  274. package/dist/linear/verify.js.map +0 -1
  275. package/dist/skills/attribution.d.ts +0 -4
  276. package/dist/skills/attribution.d.ts.map +0 -1
  277. package/dist/skills/attribution.js +0 -14
  278. package/dist/skills/attribution.js.map +0 -1
  279. package/dist/skills/broker-server.d.ts +0 -2
  280. package/dist/skills/broker-server.d.ts.map +0 -1
  281. package/dist/skills/broker-server.js +0 -17
  282. package/dist/skills/broker-server.js.map +0 -1
  283. package/dist/skills/broker.d.ts +0 -42
  284. package/dist/skills/broker.d.ts.map +0 -1
  285. package/dist/skills/broker.js +0 -285
  286. package/dist/skills/broker.js.map +0 -1
  287. package/dist/skills/catalog.d.ts +0 -28
  288. package/dist/skills/catalog.d.ts.map +0 -1
  289. package/dist/skills/catalog.js +0 -104
  290. package/dist/skills/catalog.js.map +0 -1
  291. package/dist/skills/installer.d.ts +0 -10
  292. package/dist/skills/installer.d.ts.map +0 -1
  293. package/dist/skills/installer.js +0 -138
  294. package/dist/skills/installer.js.map +0 -1
  295. package/dist/skills/integrity.d.ts +0 -4
  296. package/dist/skills/integrity.d.ts.map +0 -1
  297. package/dist/skills/integrity.js +0 -36
  298. package/dist/skills/integrity.js.map +0 -1
  299. package/docs/dynamic-thoroughness.md +0 -286
  300. package/docs/linear-identity-contract.md +0 -139
  301. package/docs/linear-identity.md +0 -293
@@ -1,440 +0,0 @@
1
- # Zig Code Review Guide
2
-
3
- > Code review guidelines for Zig focusing on explicit memory ownership, error unions, defer/errdefer cleanup, comptime usage, safety-checked operations, C interop, and tests.
4
-
5
- ## Table of Contents
6
-
7
- - [Memory & Allocators](#memory--allocators)
8
- - [Errors & Cleanup](#errors--cleanup)
9
- - [Pointers, Slices & Optionals](#pointers-slices--optionals)
10
- - [Comptime & Generics](#comptime--generics)
11
- - [Safety, Undefined Behavior & Casts](#safety-undefined-behavior--casts)
12
- - [C Interop](#c-interop)
13
- - [Testing](#testing)
14
- - [Style & API Design](#style--api-design)
15
- - [Review Checklist](#review-checklist)
16
- - [References](#references)
17
-
18
- ---
19
-
20
- ## Memory & Allocators
21
-
22
- ### Make Allocator Ownership Explicit
23
-
24
- Zig code should make allocation policy visible. Libraries should usually accept an `std.mem.Allocator` from the caller rather than creating a global allocator internally.
25
-
26
- ```zig
27
- const std = @import("std");
28
-
29
- // ❌ Bad: hides allocation policy and lifetime from callers.
30
- fn readNamesBad() ![][]const u8 {
31
- var gpa = std.heap.DebugAllocator(.{}){};
32
- const allocator = gpa.allocator();
33
- return try allocator.alloc([]const u8, 10);
34
- }
35
-
36
- // ✅ Good: caller chooses allocator and owns the returned memory.
37
- fn readNames(allocator: std.mem.Allocator) ![][]const u8 {
38
- return try allocator.alloc([]const u8, 10);
39
- }
40
- ```
41
-
42
- Review questions:
43
- - Does the caller know who owns allocated memory?
44
- - Does the API document whether returned slices must be freed?
45
- - Is the allocator parameter passed through instead of replaced by an internal global allocator?
46
-
47
- ### Pair Allocations With Cleanup
48
-
49
- Every allocation path should have a visible cleanup path. Look for missing `defer`, missing `errdefer`, and containers that are initialized but never deinitialized.
50
-
51
- ```zig
52
- const std = @import("std");
53
-
54
- fn collectBad(allocator: std.mem.Allocator) ![]u8 {
55
- // ❌ Bad: returns a slice whose backing memory is freed as the function exits.
56
- var bad_list: std.ArrayListUnmanaged(u8) = .empty;
57
- defer bad_list.deinit(allocator);
58
- try bad_list.append(allocator, 'a');
59
- return bad_list.items;
60
- }
61
-
62
- fn collect(allocator: std.mem.Allocator) ![]u8 {
63
- // ✅ Good: `errdefer` cleans up only on failure; success transfers ownership.
64
- var list: std.ArrayListUnmanaged(u8) = .empty;
65
- errdefer list.deinit(allocator);
66
-
67
- try list.append(allocator, 'a');
68
- try list.append(allocator, 'b');
69
- return try list.toOwnedSlice(allocator);
70
- }
71
- ```
72
-
73
- Review questions:
74
- - Is cleanup registered immediately after acquisition?
75
- - Is `errdefer` used when ownership transfers only on success?
76
- - Are `deinit` calls paired with all container initializations?
77
-
78
- ### Choose Allocators Deliberately
79
-
80
- Allocator choice is part of the design. A review should flag broad use of a debug/general-purpose allocator where a fixed buffer, arena, page allocator, or caller-provided allocator better matches the lifetime.
81
-
82
- ```zig
83
- // ❌ Bad: allocation lifetime is scattered across many individual frees.
84
- const user = try allocator.create(User);
85
- const events = try allocator.alloc(Event, event_count);
86
-
87
- // ✅ Good: request/frame-scoped allocations are freed together.
88
- var arena = std.heap.ArenaAllocator.init(parent_allocator);
89
- defer arena.deinit();
90
- const allocator = arena.allocator();
91
- ```
92
-
93
- Review questions:
94
- - Are arena allocations freed at a clear lifetime boundary?
95
- - Is a test using `std.testing.allocator` to catch leaks?
96
- - Is a library avoiding policy decisions that belong to its caller?
97
-
98
- ---
99
-
100
- ## Errors & Cleanup
101
-
102
- ### Keep Error Sets Useful
103
-
104
- Avoid flattening meaningful errors into `anyerror` unless the boundary genuinely needs it. Specific error sets improve API contracts and make callers handle expected failures.
105
-
106
- ```zig
107
- // ❌ Bad: erases the expected parse failures behind `anyerror`.
108
- fn parseDigitAny(input: []const u8) anyerror!u8 {
109
- if (input.len == 0) return error.EmptyInput;
110
- if (input[0] < '0' or input[0] > '9') return error.InvalidDigit;
111
- return input[0] - '0';
112
- }
113
-
114
- // ✅ Good: names the domain failures that callers should handle.
115
- const ParseError = error{
116
- EmptyInput,
117
- InvalidDigit,
118
- };
119
-
120
- fn parseDigit(input: []const u8) ParseError!u8 {
121
- if (input.len == 0) return error.EmptyInput;
122
- if (input[0] < '0' or input[0] > '9') return error.InvalidDigit;
123
- return input[0] - '0';
124
- }
125
- ```
126
-
127
- Review questions:
128
- - Are expected domain failures named explicitly?
129
- - Is `anyerror` only used at integration boundaries?
130
- - Does the caller preserve context when converting errors?
131
-
132
- ### Use `try`, `catch`, and `errdefer` Intentionally
133
-
134
- Blind `catch unreachable` is a code smell unless the invariant is mechanically guaranteed. Prefer propagating errors with `try`, converting them at boundaries, or adding a comment for unreachable invariants.
135
-
136
- ```zig
137
- // ❌ Bad: hides a real allocation failure.
138
- const buffer_bad = allocator.alloc(u8, size) catch unreachable;
139
-
140
- // ✅ Good: caller can handle OutOfMemory.
141
- const buffer = try allocator.alloc(u8, size);
142
- ```
143
-
144
- Review questions:
145
- - Does `catch unreachable` mask I/O, allocation, parsing, or user-input errors?
146
- - Are errors converted close to a boundary where the abstraction changes?
147
- - Does `errdefer` undo partial state changes on failure?
148
-
149
- ---
150
-
151
- ## Pointers, Slices & Optionals
152
-
153
- ### Prefer Slices Over Pointer Plus Length
154
-
155
- Slices carry pointer and length together, improving bounds checking and API clarity. Raw pointer plus length should be reserved for FFI or very low-level code.
156
-
157
- ```zig
158
- // ❌ Bad: easy to mismatch pointer and length.
159
- fn checksumRaw(ptr: [*]const u8, len: usize) u32 {
160
- var sum: u32 = 0;
161
- for (ptr[0..len]) |byte| sum += byte;
162
- return sum;
163
- }
164
-
165
- // ✅ Good: one value represents the buffer.
166
- fn checksum(bytes: []const u8) u32 {
167
- var sum: u32 = 0;
168
- for (bytes) |byte| sum += byte;
169
- return sum;
170
- }
171
- ```
172
-
173
- Review questions:
174
- - Can a raw pointer API become a slice API?
175
- - Is nullability modeled with `?T` instead of sentinel values?
176
- - Are pointer lifetimes clear after returning from a function?
177
-
178
- ### Avoid Returning Pointers to Stack Data
179
-
180
- Review returned slices and pointers carefully. Zig makes many lifetime issues visible, but reviewers should still check that returned data outlives the function.
181
-
182
- ```zig
183
- // ❌ Bad: returned slice points to stack memory.
184
- fn labelStack() []const u8 {
185
- var buf: [16]u8 = undefined;
186
- _ = &buf;
187
- return buf[0..];
188
- }
189
-
190
- // ✅ Good: caller owns the allocated result and can free it.
191
- fn label(allocator: std.mem.Allocator) ![]u8 {
192
- return try allocator.dupe(u8, "ready");
193
- }
194
- ```
195
-
196
- Review questions:
197
- - Does returned memory come from the caller, allocator, static storage, or a stable owner?
198
- - Does a slice escape after its backing buffer is mutated or freed?
199
- - Is aliasing intentional and documented for mutable slices?
200
-
201
- ---
202
-
203
- ## Comptime & Generics
204
-
205
- ### Keep Comptime Work Bounded and Readable
206
-
207
- `comptime` is powerful, but complex compile-time code can make error messages and build times worse. Prefer small generic helpers with clear type contracts.
208
-
209
- ```zig
210
- fn RingBuffer(comptime T: type, comptime capacity: usize) type {
211
- // ✅ Good: invalid generic parameters fail with an actionable message.
212
- if (capacity == 0) @compileError("capacity must be greater than zero");
213
-
214
- return struct {
215
- items: [capacity]T = undefined,
216
- len: usize = 0,
217
- };
218
- }
219
- ```
220
-
221
- Review questions:
222
- - Does `comptime` enforce a real invariant?
223
- - Are compile errors explicit and actionable?
224
- - Is reflection code isolated from ordinary runtime logic?
225
-
226
- ### Avoid Overly Broad `anytype`
227
-
228
- `anytype` can make APIs flexible, but it can also hide required capabilities. Add comptime checks or prefer concrete interfaces when possible.
229
-
230
- ```zig
231
- // ✅ Good: the required writer capability is obvious at the call site.
232
- fn writeAll(writer: anytype, bytes: []const u8) !void {
233
- try writer.writeAll(bytes);
234
- }
235
- ```
236
-
237
- Review questions:
238
- - Is the required shape of `anytype` clear from the function body or docs?
239
- - Would a concrete type or smaller helper be easier to review?
240
- - Are compile errors understandable when the wrong type is passed?
241
-
242
- ---
243
-
244
- ## Safety, Undefined Behavior & Casts
245
-
246
- ### Treat `undefined`, `unreachable`, and Casts as Review Hotspots
247
-
248
- Zig exposes low-level control directly. Review every `undefined`, `unreachable`, `@ptrCast`, `@alignCast`, `@intCast`, and pointer/int conversion.
249
-
250
- ```zig
251
- // ❌ Bad: assumes data layout, byte order, length, and alignment without proof.
252
- const header: *const Header = @ptrCast(@alignCast(bytes.ptr));
253
-
254
- // ✅ Good: parse fields explicitly and check length before reading.
255
- if (bytes.len < 4) return error.ShortInput;
256
- const magic = std.mem.readInt(u16, bytes[0..2], .little);
257
- const flags = std.mem.readInt(u16, bytes[2..4], .little);
258
- ```
259
-
260
- Review questions:
261
- - Is `undefined` overwritten before being read?
262
- - Is `unreachable` only used for impossible states, with a nearby explanation when non-obvious?
263
- - Are casts preceded by checks for layout, range, alignment, size, byte order, and nullability?
264
-
265
- ### Prefer Checked Arithmetic Unless Wrapping Is Intentional
266
-
267
- Wrapping operators such as `+%` and `-%` are useful, but they should communicate a deliberate modular arithmetic choice.
268
-
269
- ```zig
270
- // ❌ Bad: wrapping silences overflow that should expose a logic bug.
271
- index = index +% 1;
272
-
273
- // ✅ Good: checked arithmetic traps on unexpected overflow.
274
- sum += byte;
275
-
276
- // ✅ Good: wrapping is intentional for modular hash behavior.
277
- hash = hash *% 16777619;
278
- hash = hash +% byte;
279
- ```
280
-
281
- Review questions:
282
- - Is wrapping arithmetic required by an algorithm?
283
- - Would overflow indicate invalid input or a bug?
284
- - Are integer width changes explicit and tested around boundaries?
285
-
286
- ---
287
-
288
- ## C Interop
289
-
290
- ### Contain C Boundaries
291
-
292
- Keep `@cImport`, C pointer handling, and ABI assumptions close to a wrapper layer. Convert C data into Zig types before it spreads through the codebase.
293
-
294
- ```zig
295
- const std = @import("std");
296
-
297
- // ❌ Bad: uses C strlen when no external C boundary is needed.
298
- fn strlenC(input: [*:0]const u8) usize {
299
- const c = @cImport({
300
- @cInclude("string.h");
301
- });
302
-
303
- return c.strlen(input);
304
- }
305
-
306
- // ✅ Good: use Zig's sentinel-aware standard library helper.
307
- fn strlenZ(input: [*:0]const u8) usize {
308
- return std.mem.len(input);
309
- }
310
- ```
311
-
312
- Review questions:
313
- - Are C pointers represented with the correct Zig pointer type?
314
- - Are sentinel-terminated strings modeled as sentinel pointers or slices?
315
- - Are ownership and cleanup rules from the C library documented?
316
- - Are C error codes converted into Zig error unions near the boundary?
317
-
318
- ---
319
-
320
- ## Testing
321
-
322
- ### Use `std.testing` Assertions and Leak Detection
323
-
324
- Tests that allocate should use `std.testing.allocator` where practical so leaks are reported by the test runner.
325
-
326
- ```zig
327
- const std = @import("std");
328
-
329
- test "collect returns owned memory on success" {
330
- const allocator = std.testing.allocator;
331
- const names = try collect(allocator);
332
- defer allocator.free(names);
333
-
334
- try std.testing.expectEqual(@as(usize, 2), names.len);
335
- }
336
-
337
- test "collect handles allocation failures cleanly" {
338
- var failing = std.testing.FailingAllocator.init(std.testing.allocator, .{
339
- .fail_index = 0,
340
- });
341
- try std.testing.expectError(error.OutOfMemory, collect(failing.allocator()));
342
- }
343
- ```
344
-
345
- Review questions:
346
- - Are allocation-heavy paths covered by tests?
347
- - Are error paths tested with `std.testing.expectError`?
348
- - Do tests cover boundary sizes such as empty input, one element, max capacity, and invalid encodings?
349
-
350
- ### Test Build Modes and Targets When Relevant
351
-
352
- Behavior can differ across safety modes, targets, and ABIs. For low-level code, ask whether the PR was tested with the intended target and optimization mode.
353
-
354
- Review questions:
355
- - Does code rely on debug-only safety checks?
356
- - Does packed/aligned/extern layout code have target-aware tests?
357
- - Are endian, pointer-width, and ABI assumptions tested or documented?
358
-
359
- ---
360
-
361
- ## Style & API Design
362
-
363
- ### Follow Zig Naming Conventions
364
-
365
- Use the official style guide as the baseline: `TitleCase` for types, `camelCase` for functions, and `snake_case` for variables. Avoid redundant words such as `Value`, `Data`, `Manager`, or `State` when the surrounding namespace already provides that meaning.
366
-
367
- ```zig
368
- // ❌ Bad: redundant namespace and vague type name.
369
- pub const json_bad = struct {
370
- pub const JsonValueManager = struct {};
371
- };
372
-
373
- // ✅ Good: name is meaningful in its fully-qualified namespace.
374
- pub const json = struct {
375
- pub const Value = union(enum) {};
376
- };
377
- ```
378
-
379
- Review questions:
380
- - Does the fully-qualified name read naturally?
381
- - Are file and directory names consistent with the style guide?
382
- - Are underscore-prefixed declarations avoided unless they come from an external convention?
383
- - Are public APIs documented with doc comments where helpful?
384
-
385
- ### Keep Public APIs Small
386
-
387
- Zig modules often expose declarations directly from files and structs. Review public declarations for accidental exports.
388
-
389
- Review questions:
390
- - Should this declaration be `pub`?
391
- - Is the public API stable enough to expose?
392
- - Are implementation details hidden behind a smaller surface?
393
-
394
- ---
395
-
396
- ## Review Checklist
397
-
398
- ### Memory & Lifetime
399
- - [ ] Allocator ownership is explicit.
400
- - [ ] Allocations have matching `free`, `deinit`, `defer`, or `errdefer`.
401
- - [ ] Returned slices and pointers outlive the function.
402
- - [ ] Arena or temporary allocations have a clear lifetime boundary.
403
-
404
- ### Errors & Cleanup
405
- - [ ] Expected failures use specific error sets where practical.
406
- - [ ] `catch unreachable` does not hide real runtime failures.
407
- - [ ] Partial initialization is rolled back with `errdefer`.
408
- - [ ] Error conversions happen at abstraction boundaries.
409
-
410
- ### Pointers & Safety
411
- - [ ] Raw pointers are justified; slices are used for ordinary buffers.
412
- - [ ] Casts check size, range, alignment, and nullability.
413
- - [ ] `undefined` is not read before initialization.
414
- - [ ] Wrapping arithmetic is intentional and tested.
415
-
416
- ### Comptime & API Design
417
- - [ ] `comptime` logic enforces useful invariants.
418
- - [ ] `anytype` usage has clear expectations.
419
- - [ ] Public declarations are intentional.
420
- - [ ] Names follow Zig style conventions.
421
-
422
- ### C Interop & Portability
423
- - [ ] C boundaries are isolated behind wrappers.
424
- - [ ] C ownership and cleanup rules are documented.
425
- - [ ] Target, endian, pointer-width, and ABI assumptions are tested or documented.
426
-
427
- ### Tests
428
- - [ ] Tests use `std.testing.allocator` for allocation-heavy code.
429
- - [ ] Error paths use `std.testing.expectError`.
430
- - [ ] Boundary cases are covered.
431
- - [ ] Relevant build modes and targets are considered.
432
-
433
- ---
434
-
435
- ## References
436
-
437
- - [Zig 0.16.0 Language Reference](https://ziglang.org/documentation/0.16.0/)
438
- - [Zig 0.16.0 Standard Library documentation](https://ziglang.org/documentation/0.16.0/std/)
439
- - [Zig 0.16.0 Style Guide](https://ziglang.org/documentation/0.16.0/#Style-Guide)
440
- - [Choosing an Allocator](https://ziglang.org/documentation/0.16.0/#Choosing-an-Allocator)