@use-the-fork/spindle 0.0.0-stage → 0.0.1

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 (245) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +3 -2
  3. package/build/Assets/Blueprints/Catalog.js +110 -0
  4. package/build/Assets/Blueprints/agents/general.agent.md +67 -0
  5. package/build/Assets/Blueprints/agents/sdd-code-reviewer.agent.md +62 -0
  6. package/build/Assets/Blueprints/agents/sdd-code-slop-reviewer.agent.md +59 -0
  7. package/build/Assets/Blueprints/agents/sdd-implementer.agent.md +77 -0
  8. package/build/Assets/Blueprints/agents/sdd-orchestrator.agent.md +42 -0
  9. package/build/Assets/Blueprints/agents/sdd-re-review.agent.md +57 -0
  10. package/build/Assets/Blueprints/agents/sdd-reviewer.agent.md +89 -0
  11. package/build/Assets/Blueprints/agents/sdd-task-reviewer.agent.md +54 -0
  12. package/build/Assets/Blueprints/agents/shared-codebase-analyzer.agent.md +151 -0
  13. package/build/Assets/Blueprints/agents/shared-codebase-locator.agent.md +130 -0
  14. package/build/Assets/Blueprints/agents/shared-codebase-pattern-finder.agent.md +247 -0
  15. package/build/Assets/Blueprints/agents/shared-explore.agent.md +53 -0
  16. package/build/Assets/Blueprints/agents/shared-r.agent.md +17 -0
  17. package/build/Assets/Blueprints/agents/shared-rw.agent.md +17 -0
  18. package/build/Assets/Blueprints/agents/shared-rwx.agent.md +17 -0
  19. package/build/Assets/Blueprints/agents/shared-web-search-researcher.agent.md +122 -0
  20. package/build/Assets/Blueprints/instructions/code-commenting.instructions.md +39 -0
  21. package/build/Assets/Blueprints/instructions/source-architecture.instructions.md +15 -0
  22. package/build/Assets/Blueprints/skills/asd-ste100/CREDITS.MD +1 -0
  23. package/build/Assets/Blueprints/skills/asd-ste100/SKILL.md +83 -0
  24. package/build/Assets/Blueprints/skills/asd-ste100/examples/before-after.md +107 -0
  25. package/build/Assets/Blueprints/skills/asd-ste100/references/writing-rules.md +65 -0
  26. package/build/Assets/Blueprints/skills/author-agent/SKILL.md +26 -0
  27. package/build/Assets/Blueprints/skills/author-design/SKILL.md +38 -0
  28. package/build/Assets/Blueprints/skills/author-instruction/SKILL.md +28 -0
  29. package/build/Assets/Blueprints/skills/author-skill/SKILL.md +26 -0
  30. package/build/Assets/Blueprints/skills/grill/SKILL.md +33 -0
  31. package/build/Assets/Blueprints/skills/grill-design/SKILL.md +41 -0
  32. package/build/Assets/Blueprints/skills/grill-with-docs/SKILL.md +14 -0
  33. package/build/Assets/Blueprints/skills/implement/SKILL.md +79 -0
  34. package/build/Assets/Blueprints/skills/implement-spec/SKILL.md +34 -0
  35. package/build/Assets/Blueprints/skills/improve-codebase-architecture/HTML-REPORT.md +129 -0
  36. package/build/Assets/Blueprints/skills/improve-codebase-architecture/SKILL.md +74 -0
  37. package/build/Assets/Blueprints/skills/int-code-review/SKILL.md +76 -0
  38. package/build/Assets/Blueprints/skills/int-code-slop-review/SKILL.md +238 -0
  39. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/_sections.md +36 -0
  40. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/_template.md +42 -0
  41. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/comments-closing-brace-labels.md +112 -0
  42. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/comments-empty-docblocks.md +132 -0
  43. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/comments-narration.md +118 -0
  44. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/comments-placeholder.md +130 -0
  45. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/defensive-generic-catch.md +153 -0
  46. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/defensive-impossible-null.md +157 -0
  47. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/defensive-missing-real.md +157 -0
  48. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/naming-generic-placeholders.md +120 -0
  49. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/naming-over-descriptive.md +108 -0
  50. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/naming-suffix-abuse.md +167 -0
  51. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/naming-type-in-name.md +100 -0
  52. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/over-eng-dependency-creep.md +114 -0
  53. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/over-eng-premature-interface.md +136 -0
  54. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/over-eng-single-method-class.md +161 -0
  55. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/over-eng-useless-wrapper.md +140 -0
  56. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/style-as-any-escape.md +127 -0
  57. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/style-debug-artifacts.md +144 -0
  58. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/style-hyper-consistent.md +84 -0
  59. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/style-no-hack-scars.md +113 -0
  60. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/style-trivial-boilerplate.md +191 -0
  61. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/test-doesnt-throw.md +132 -0
  62. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/test-mirror-implementation.md +125 -0
  63. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/test-mock-everything.md +148 -0
  64. package/build/Assets/Blueprints/skills/int-code-slop-review/rules/test-snapshot-abuse.md +131 -0
  65. package/build/Assets/Blueprints/skills/int-codebase-design/SKILL.md +116 -0
  66. package/build/Assets/Blueprints/skills/int-codebase-design/references/DEEPENING.md +37 -0
  67. package/build/Assets/Blueprints/skills/int-codebase-design/references/DESIGN-IT-TWICE.md +44 -0
  68. package/build/Assets/Blueprints/skills/int-domain-modeling/SKILL.md +78 -0
  69. package/build/Assets/Blueprints/skills/int-domain-modeling/references/ADR-FORMAT.md +47 -0
  70. package/build/Assets/Blueprints/skills/int-domain-modeling/references/GLOSSARY-FORMAT.md +60 -0
  71. package/build/Assets/Blueprints/skills/int-prototype/LOGIC.md +67 -0
  72. package/build/Assets/Blueprints/skills/int-prototype/SKILL.md +30 -0
  73. package/build/Assets/Blueprints/skills/int-prototype/UI.md +112 -0
  74. package/build/Assets/Blueprints/skills/int-retrospective/SKILL.md +88 -0
  75. package/build/Assets/Blueprints/skills/int-retrospective/assets/retrospective-prompt.md +38 -0
  76. package/build/Assets/Blueprints/skills/int-retrospective/references/assessment.md +56 -0
  77. package/build/Assets/Blueprints/skills/int-subagent-driven-dev/SKILL.md +64 -0
  78. package/build/Assets/Blueprints/skills/int-subagent-driven-dev/assets/implementer-prompt.md +40 -0
  79. package/build/Assets/Blueprints/skills/int-subagent-driven-dev/assets/reviewer-prompt.md +43 -0
  80. package/build/Assets/Blueprints/skills/int-subagent-driven-dev/references/aggregate-review.md +7 -0
  81. package/build/Assets/Blueprints/skills/int-subagent-driven-dev/references/corrective-rounds.md +72 -0
  82. package/build/Assets/Blueprints/skills/int-subagent-driven-dev/references/example-workflow.md +25 -0
  83. package/build/Assets/Blueprints/skills/int-subagent-driven-dev/references/full-spec.md +72 -0
  84. package/build/Assets/Blueprints/skills/int-subagent-driven-dev/references/implementer-corrections.md +9 -0
  85. package/build/Assets/Blueprints/skills/int-subagent-driven-dev/references/review-inputs.md +26 -0
  86. package/build/Assets/Blueprints/skills/int-subagent-driven-dev/references/verification-evidence.md +7 -0
  87. package/build/Assets/Blueprints/skills/int-test-driven-development/SKILL.md +51 -0
  88. package/build/Assets/Blueprints/skills/int-test-driven-development/references/mocking.md +31 -0
  89. package/build/Assets/Blueprints/skills/int-test-driven-development/references/tests.md +68 -0
  90. package/build/Assets/Blueprints/skills/int-testing-agent-guidance/SKILL.md +53 -0
  91. package/build/Assets/Blueprints/skills/int-verification-before-completion/SKILL.md +25 -0
  92. package/build/Assets/Blueprints/skills/int-writing-agents/SKILL.md +66 -0
  93. package/build/Assets/Blueprints/skills/int-writing-for-agents/SKILL.md +86 -0
  94. package/build/Assets/Blueprints/skills/int-writing-instruction/SKILL.md +57 -0
  95. package/build/Assets/Blueprints/skills/int-writing-skills/SKILL.md +129 -0
  96. package/build/Assets/Blueprints/skills/int-writing-skills/assets/interactive.md +83 -0
  97. package/build/Assets/Blueprints/skills/int-writing-skills/assets/reference.md +32 -0
  98. package/build/Assets/Blueprints/skills/int-writing-skills/references/arguments.md +50 -0
  99. package/build/Assets/Blueprints/skills/int-writing-skills/references/interactive-skills.md +53 -0
  100. package/build/Assets/Blueprints/skills/int-writing-skills/references/persuasion-principles.md +220 -0
  101. package/build/Assets/Blueprints/skills/int-writing-skills/references/reference-skills.md +20 -0
  102. package/build/Assets/Blueprints/skills/int-writing-skills/references/testing-skills.md +48 -0
  103. package/build/Assets/Blueprints/skills/retrospective/SKILL.md +16 -0
  104. package/build/Assets/Blueprints/skills/setup-project/SKILL.md +66 -0
  105. package/build/Assets/Blueprints/skills/to-spec/SKILL.md +53 -0
  106. package/build/Assets/Blueprints/skills/to-tickets/SKILL.md +49 -0
  107. package/build/Assets/Blueprints/skills/update-tooling/SKILL.md +86 -0
  108. package/build/Assets/Templates/Catalog.js +12 -0
  109. package/build/Assets/Templates/Catalog.ts +17 -0
  110. package/build/Assets/Templates/project/copilot-instructions.md +17 -0
  111. package/build/Assets/Templates/project/domain.md +51 -0
  112. package/build/Assets/Templates/project/ticket-tracker.md +33 -0
  113. package/build/Assets/Templates/sdd/design.md +25 -0
  114. package/build/Assets/Templates/sdd/spec.md +29 -0
  115. package/build/Assets/Templates/sdd/ticket.md +15 -0
  116. package/build/BlueprintManagement/BlueprintManagementServiceProvider.js +15 -0
  117. package/build/BlueprintManagement/Catalog/BlueprintCatalog.js +238 -0
  118. package/build/BlueprintManagement/Commands/BlueprintCommandOptions.js +9 -0
  119. package/build/BlueprintManagement/Commands/ConflictPolicy.js +6 -0
  120. package/build/BlueprintManagement/Commands/InitCommand.js +117 -0
  121. package/build/BlueprintManagement/Commands/Prompts.js +66 -0
  122. package/build/BlueprintManagement/Commands/UpdateCommand.js +86 -0
  123. package/build/BlueprintManagement/Handlers/Agents/AgentHandler.js +21 -0
  124. package/build/BlueprintManagement/Handlers/BlueprintHandlers.js +4 -0
  125. package/build/BlueprintManagement/Handlers/Instructions/InstructionHandler.js +21 -0
  126. package/build/BlueprintManagement/Handlers/Skills/SkillHandler.js +10 -0
  127. package/build/BlueprintManagement/Reconciliation/BlueprintCatalogPlanner.js +87 -0
  128. package/build/BlueprintManagement/Reconciliation/BlueprintRemovalCoordinator.js +78 -0
  129. package/build/BlueprintManagement/Services/BlueprintReconciliationService.js +391 -0
  130. package/build/BlueprintManagement/Services/InstallationService.js +54 -0
  131. package/build/BlueprintManagement/Support/BlueprintFiles.js +113 -0
  132. package/build/BlueprintManagement/Types/Blueprint.js +1 -0
  133. package/build/BlueprintManagement/Types/Installation.js +1 -0
  134. package/build/BlueprintManagement/Types/Reconciliation.js +1 -0
  135. package/build/BlueprintManagement/Versioning/BlueprintVersion.js +70 -0
  136. package/build/BlueprintManagement/Versioning/BlueprintVersioning.js +55 -0
  137. package/build/Commands/Command.js +3 -0
  138. package/build/Commands/CommandOptions.js +12 -0
  139. package/build/Config/Config.js +3 -0
  140. package/build/Foundation/Application.js +112 -0
  141. package/build/Foundation/ApplicationBuilder.js +23 -0
  142. package/build/Foundation/Bootstrap/Bootstrapper.js +2 -0
  143. package/build/Foundation/Bootstrap/DiscoverGitRoot.js +8 -0
  144. package/build/Foundation/Bootstrap/LoadConsoleArgs.js +47 -0
  145. package/build/Foundation/Bootstrap/LoadProjectConfiguration.js +144 -0
  146. package/build/Foundation/Bootstrap/RegisterProviders.js +12 -0
  147. package/build/Foundation/Bootstrap/RequireProjectConfiguration.js +14 -0
  148. package/build/Foundation/ConsoleInvocation.js +1 -0
  149. package/build/Foundation/Container.js +185 -0
  150. package/build/Foundation/FoundationServiceProvider.js +5 -0
  151. package/build/Foundation/Kernel.js +30 -0
  152. package/build/Foundation/Service.js +23 -0
  153. package/build/Foundation/ServiceProvider.js +12 -0
  154. package/build/Git/GitServiceProvider.js +8 -0
  155. package/build/Git/Services/GitService.js +26 -0
  156. package/build/Project/ProjectServiceProvider.js +8 -0
  157. package/build/Project/Services/ProjectService.js +124 -0
  158. package/build/SubagentDrivenDevelopment/Commands/ChecksRecordCommand.js +35 -0
  159. package/build/SubagentDrivenDevelopment/Commands/ChecksRequireCommand.js +33 -0
  160. package/build/SubagentDrivenDevelopment/Commands/ClaimCommand.js +23 -0
  161. package/build/SubagentDrivenDevelopment/Commands/CorrectCommand.js +37 -0
  162. package/build/SubagentDrivenDevelopment/Commands/CreateCommand.js +26 -0
  163. package/build/SubagentDrivenDevelopment/Commands/FindingCreateCommand.js +39 -0
  164. package/build/SubagentDrivenDevelopment/Commands/FindingUpdateCommand.js +36 -0
  165. package/build/SubagentDrivenDevelopment/Commands/FinishCommand.js +23 -0
  166. package/build/SubagentDrivenDevelopment/Commands/ImplementCommand.js +23 -0
  167. package/build/SubagentDrivenDevelopment/Commands/NextCommand.js +21 -0
  168. package/build/SubagentDrivenDevelopment/Commands/ReadyCommand.js +21 -0
  169. package/build/SubagentDrivenDevelopment/Commands/RequirementsDecideCommand.js +33 -0
  170. package/build/SubagentDrivenDevelopment/Commands/ResumeCommand.js +31 -0
  171. package/build/SubagentDrivenDevelopment/Commands/ReviewCommand.js +55 -0
  172. package/build/SubagentDrivenDevelopment/Commands/ReviewRequireCommand.js +12 -0
  173. package/build/SubagentDrivenDevelopment/Commands/StatusCommand.js +21 -0
  174. package/build/SubagentDrivenDevelopment/Commands/SubmitCommand.js +59 -0
  175. package/build/SubagentDrivenDevelopment/Commands/TicketCommentCommand.js +24 -0
  176. package/build/SubagentDrivenDevelopment/Commands/TicketCreateCommand.js +25 -0
  177. package/build/SubagentDrivenDevelopment/Commands/TicketUpdateCommand.js +31 -0
  178. package/build/SubagentDrivenDevelopment/Commands/groups.js +36 -0
  179. package/build/SubagentDrivenDevelopment/Evidence/GitEvidence.js +449 -0
  180. package/build/SubagentDrivenDevelopment/Evidence/ReportEvidence.js +80 -0
  181. package/build/SubagentDrivenDevelopment/Models/Assignments.js +1 -0
  182. package/build/SubagentDrivenDevelopment/Models/Evidence.js +1 -0
  183. package/build/SubagentDrivenDevelopment/Models/Findings.js +1 -0
  184. package/build/SubagentDrivenDevelopment/Models/Options.js +1 -0
  185. package/build/SubagentDrivenDevelopment/Models/Workflow.js +16 -0
  186. package/build/SubagentDrivenDevelopment/Persistence/AssignmentSchema.js +155 -0
  187. package/build/SubagentDrivenDevelopment/Persistence/CheckSchema.js +71 -0
  188. package/build/SubagentDrivenDevelopment/Persistence/FeatureWorkspace.js +76 -0
  189. package/build/SubagentDrivenDevelopment/Persistence/FileSystem.js +28 -0
  190. package/build/SubagentDrivenDevelopment/Persistence/FindingSchema.js +81 -0
  191. package/build/SubagentDrivenDevelopment/Persistence/LedgerRepository.js +322 -0
  192. package/build/SubagentDrivenDevelopment/Persistence/PathSafety.js +62 -0
  193. package/build/SubagentDrivenDevelopment/Persistence/ProgressSchema.js +95 -0
  194. package/build/SubagentDrivenDevelopment/Persistence/ReadinessReader.js +40 -0
  195. package/build/SubagentDrivenDevelopment/Persistence/ReviewSchema.js +68 -0
  196. package/build/SubagentDrivenDevelopment/Persistence/TicketRepository.js +147 -0
  197. package/build/SubagentDrivenDevelopment/Persistence/WorkspaceTransaction.js +282 -0
  198. package/build/SubagentDrivenDevelopment/Policies/AcceptancePolicy.js +100 -0
  199. package/build/SubagentDrivenDevelopment/Policies/AssignmentPolicy.js +36 -0
  200. package/build/SubagentDrivenDevelopment/Policies/CheckPolicy.js +93 -0
  201. package/build/SubagentDrivenDevelopment/Policies/FindingPolicy.js +53 -0
  202. package/build/SubagentDrivenDevelopment/Policies/InputValidation.js +36 -0
  203. package/build/SubagentDrivenDevelopment/Policies/ReadinessPolicy.js +26 -0
  204. package/build/SubagentDrivenDevelopment/Policies/RequiredReviewers.js +12 -0
  205. package/build/SubagentDrivenDevelopment/Policies/ReviewPolicy.js +87 -0
  206. package/build/SubagentDrivenDevelopment/Policies/WorkflowPolicy.js +85 -0
  207. package/build/SubagentDrivenDevelopment/Services/AssignmentService.js +269 -0
  208. package/build/SubagentDrivenDevelopment/Services/ChecksService.js +319 -0
  209. package/build/SubagentDrivenDevelopment/Services/CorrectionService.js +273 -0
  210. package/build/SubagentDrivenDevelopment/Services/DeliveryCorrectionService.js +253 -0
  211. package/build/SubagentDrivenDevelopment/Services/DeliveryFindingService.js +302 -0
  212. package/build/SubagentDrivenDevelopment/Services/DeliveryService.js +160 -0
  213. package/build/SubagentDrivenDevelopment/Services/DeliverySubmissionService.js +273 -0
  214. package/build/SubagentDrivenDevelopment/Services/FeatureCreationService.js +138 -0
  215. package/build/SubagentDrivenDevelopment/Services/FeatureInspectionService.js +399 -0
  216. package/build/SubagentDrivenDevelopment/Services/FindingService.js +392 -0
  217. package/build/SubagentDrivenDevelopment/Services/IntegrationService.js +258 -0
  218. package/build/SubagentDrivenDevelopment/Services/ReadinessService.js +21 -0
  219. package/build/SubagentDrivenDevelopment/Services/RequirementsService.js +216 -0
  220. package/build/SubagentDrivenDevelopment/Services/ReviewService.js +471 -0
  221. package/build/SubagentDrivenDevelopment/Services/SubmissionService.js +299 -0
  222. package/build/SubagentDrivenDevelopment/Services/TicketService.js +186 -0
  223. package/build/SubagentDrivenDevelopment/SubagentDrivenDevelopmentServiceProvider.js +113 -0
  224. package/build/Support/Records.js +5 -0
  225. package/build/Support/Repository.js +139 -0
  226. package/build/Support/Stacks.js +10 -0
  227. package/build/TemplateRendering/Computed/ComputedContextService.js +13 -0
  228. package/build/TemplateRendering/Computed/ComputedVariableProvider.js +6 -0
  229. package/build/TemplateRendering/Computed/ComputedVariableProviders.js +6 -0
  230. package/build/TemplateRendering/Computed/Providers/InternalSkillDescriptionProvider.js +6 -0
  231. package/build/TemplateRendering/Computed/Providers/SpindlePackageManagerProvider.js +11 -0
  232. package/build/TemplateRendering/Computed/ResolveRenderContext.js +18 -0
  233. package/build/TemplateRendering/Rendering/RenderText.js +43 -0
  234. package/build/TemplateRendering/TemplateRenderingServiceProvider.js +8 -0
  235. package/build/Tooling/Commands/ToolingAddCommand.js +29 -0
  236. package/build/Tooling/Commands/ToolingListCommand.js +19 -0
  237. package/build/Tooling/Commands/ToolingRemoveCommand.js +19 -0
  238. package/build/Tooling/Commands/ToolingUpdateCommand.js +30 -0
  239. package/build/Tooling/Commands/groups.js +4 -0
  240. package/build/Tooling/Models/ToolingEntry.js +1 -0
  241. package/build/Tooling/Services/ToolingService.js +278 -0
  242. package/build/Tooling/ToolingServiceProvider.js +15 -0
  243. package/build/cli.js +36 -0
  244. package/build/index.js +31 -0
  245. package/package.json +54 -3
@@ -0,0 +1,120 @@
1
+ ---
2
+ title: Generic Placeholder Names
3
+ impact: CRITICAL
4
+ impactDescription: "Reduces every variable to 'a thing' — kills the most powerful form of self-documentation"
5
+ tags: naming, generic-names, ai-fingerprint
6
+ ---
7
+
8
+ ## Generic Placeholder Names
9
+
10
+ **Impact: CRITICAL (Reduces every variable to 'a thing' — kills the most powerful form of self-documentation)**
11
+
12
+ `data`, `result`, `info`, `temp`, `value`, `item`, `helper`, `manager`, `utils` — these are the names a model picks when it doesn't know what the value represents in the domain. They pass linters, type checks, every metric. They cost the reader real attention to track ("which `data` is this?").
13
+
14
+ Names are the cheapest, highest-leverage form of self-documentation in any codebase. A model that names every intermediate variable `data` or `result` is signalling it didn't think about the domain.
15
+
16
+ ## Incorrect
17
+
18
+ ```php
19
+ // ❌ Every variable is generic
20
+
21
+ public function exportUsers(): Collection
22
+ {
23
+ $data = User::all();
24
+
25
+ $result = [];
26
+ foreach ($data as $item) {
27
+ $info = [
28
+ 'name' => $item->name,
29
+ 'email' => $item->email,
30
+ ];
31
+ $result[] = $info;
32
+ }
33
+
34
+ return collect($result);
35
+ }
36
+ ```
37
+
38
+ ```typescript
39
+ // ❌ Same pattern
40
+ async function fetchOrders(userId: string) {
41
+ const data = await api.getOrders(userId);
42
+ const result = data.map((item) => {
43
+ const info = {
44
+ id: item.id,
45
+ total: item.total,
46
+ };
47
+ return info;
48
+ });
49
+ return result;
50
+ }
51
+ ```
52
+
53
+ **Why it's slop:**
54
+
55
+ - Every variable is "a thing"; reader has no anchor to the domain
56
+ - `$item` inside a loop over `$data` is doubly opaque — what kind of item? what kind of data?
57
+ - A reader hitting line 50 of this file can't tell what `$result` holds without tracing the whole function
58
+ - A human author who lived with this code would use domain words
59
+
60
+ ## Correct
61
+
62
+ ```php
63
+ // ✅ Names tell you what the values are in the domain
64
+
65
+ public function exportUsers(): Collection
66
+ {
67
+ return User::all()
68
+ ->map(fn (User $user) => [
69
+ 'name' => $user->name,
70
+ 'email' => $user->email,
71
+ ]);
72
+ }
73
+ ```
74
+
75
+ ```typescript
76
+ // ✅ Domain words everywhere
77
+ async function fetchOrders(userId: string): Promise<OrderSummary[]> {
78
+ const orders = await api.getOrders(userId);
79
+ return orders.map((order) => ({
80
+ id: order.id,
81
+ total: order.total,
82
+ }));
83
+ }
84
+ ```
85
+
86
+ **Why it reads human:**
87
+
88
+ - A reader on any line knows the domain object in scope
89
+ - Domain names compose — `orders.map(order => …)` reads as a sentence
90
+ - The original `$data → $item → $info → $result` chain collapses into one expression because the names made the intermediate variables unnecessary
91
+
92
+ ## When generic names ARE OK
93
+
94
+ A handful of names are conventional, short-scope, and fine:
95
+
96
+ - **`i`, `j`, `k`** — loop indices in a 3-line `for`
97
+ - **`x`, `y`, `z`** — math/geometry (coordinates)
98
+ - **`_`** — explicit "ignored value"
99
+ - **`acc`** — accumulator in a `reduce` callback
100
+ - **`prev`, `next`** — in middleware / chained handlers where they're language conventions
101
+ - **`req`, `res`** — Express handlers (don't fight a framework convention)
102
+
103
+ If the value flows through 5+ lines or escapes the immediate function, use a domain name.
104
+
105
+ ## Detection
106
+
107
+ ```bash
108
+ # Bare local-variable declarations using generic names (PHP)
109
+ grep -rEn '\$(data|result|info|temp|item|helper|value)\b' --include='*.php' app/ | wc -l
110
+
111
+ # TS/JS — generic const/let
112
+ grep -rEn '\b(const|let)\s+(data|result|info|temp|helper|value|item)\b' --include='*.ts' --include='*.tsx' --include='*.js' src/ | wc -l
113
+
114
+ # Density signal: files with > 10 generic-name hits
115
+ # (in a 200-line file, 10+ generic names is suspicious)
116
+ ```
117
+
118
+ There's no fully automatic detector — judgment is required. The signal is **density**: a few are fine, a thicket is a slop fingerprint.
119
+
120
+ Reference: [Clean Code (Robert C. Martin) — Chapter 2: Meaningful Names](https://www.oreilly.com/library/view/clean-code/9780136083238/) · Internal: [`naming-over-descriptive`](naming-over-descriptive.md)
@@ -0,0 +1,108 @@
1
+ ---
2
+ title: Over-Descriptive Run-On Names
3
+ impact: HIGH
4
+ impactDescription: "Inflated identifiers that read like English instead of code"
5
+ tags: naming, verbose, ai-fingerprint
6
+ ---
7
+
8
+ ## Over-Descriptive Run-On Names
9
+
10
+ **Impact: HIGH (Inflated identifiers that read like English instead of code)**
11
+
12
+ The opposite failure mode of generic names: instead of `user`, the AI produces `theUserWhoIsCurrentlyLoggedIn`. Instead of `total`, `calculateTotalAmountFromItemsList`. The identifier becomes a sentence. Real engineers know that _context_ (function scope, parameter types, surrounding code) carries half the meaning — you don't need to encode all of it in every variable name.
13
+
14
+ A name should be **as long as needed and no longer**. Once context establishes "we're inside `processOrder`", calling the order variable `order` is fine. Calling it `theOrderThatIsCurrentlyBeingProcessed` is slop.
15
+
16
+ ## Incorrect
17
+
18
+ ```php
19
+ // ❌ Identifiers read as English
20
+
21
+ public function processOrderForCheckout(
22
+ OrderThatIsCurrentlyBeingProcessed $theOrderToProcess
23
+ ): ProcessingResultObjectContainingStatus {
24
+ $theCurrentlyLoggedInUserWhoIsCheckingOut = $theOrderToProcess->getUserWhoPlacedTheOrder();
25
+ $theTotalAmountThatNeedsToBeCharged = $this->calculateTotalAmountFromItemsListInTheOrder($theOrderToProcess);
26
+
27
+ return new ProcessingResultObjectContainingStatus(
28
+ status: 'success',
29
+ amountThatWasCharged: $theTotalAmountThatNeedsToBeCharged,
30
+ );
31
+ }
32
+ ```
33
+
34
+ ```typescript
35
+ // ❌ Same in TS
36
+ async function fetchTheUserDataObjectForTheUserWithTheGivenId(
37
+ theIdOfTheUserToFetch: string,
38
+ ): Promise<TheUserDataResponseObject> {
39
+ const theResponseFromTheAPI = await api.getUser(theIdOfTheUserToFetch);
40
+ return theResponseFromTheAPI;
41
+ }
42
+ ```
43
+
44
+ **Why it's slop:**
45
+
46
+ - Function signatures span multiple lines because identifiers eat the line budget
47
+ - Reader has to scan past redundant words ("theOrderToProcess" — yes, it's the parameter, of course we're processing it)
48
+ - "The" prefix is meaningless — what else would it be?
49
+ - Inflates token count without conveying anything new
50
+
51
+ ## Correct
52
+
53
+ ```php
54
+ // ✅ Tight; context carries the obvious
55
+
56
+ public function checkout(Order $order): ProcessingResult
57
+ {
58
+ $user = $order->user;
59
+ $total = $this->totalFor($order);
60
+
61
+ return new ProcessingResult(status: 'success', charged: $total);
62
+ }
63
+ ```
64
+
65
+ ```typescript
66
+ // ✅ Tight TS
67
+ async function fetchUser(id: string): Promise<User> {
68
+ return api.getUser(id);
69
+ }
70
+ ```
71
+
72
+ **Why it reads human:**
73
+
74
+ - The function is named `checkout`; obviously the parameter is the order being checked out — no need to spell that out
75
+ - Function fits on one line; reader takes it in at a glance
76
+ - Domain words (`Order`, `User`, `ProcessingResult`) replace English sentences
77
+
78
+ ## Guidelines
79
+
80
+ | Scope | Reasonable length |
81
+ | ------------------------ | ------------------------------------------------------------------- |
82
+ | Loop index | 1 char (`i`) |
83
+ | Block-local (< 10 lines) | 1 word (`user`, `total`) |
84
+ | Function-local | 1–2 words (`pricedItems`, `taxedTotal`) |
85
+ | Public API parameter | 2–3 words when domain requires (`stripeChargeId`, `webhookPayload`) |
86
+ | Constants / config keys | Domain-precise (`MAX_STRIPE_AMOUNT_CENTS`) — those CAN be long |
87
+ | Class names | 1–3 words (`OrderService`, `RefundCalculator`) |
88
+
89
+ The rule of thumb: **if you can drop a word and meaning survives, drop it.**
90
+
91
+ ## Detection
92
+
93
+ ```bash
94
+ # Identifiers with 4+ camelCase words (heuristic; tune to taste).
95
+ # Note: grep -E (ERE) does NOT support (?:...) non-capturing groups; use a capturing group.
96
+ grep -rEn '[a-z]+([A-Z][a-z]+){3,}' --include='*.ts' --include='*.tsx' --include='*.js' src/ \
97
+ | head -30
98
+
99
+ # PHP equivalent (variables / method names)
100
+ grep -rEn '\$[a-z][a-zA-Z]{20,}' --include='*.php' app/ | head -30
101
+ grep -rEn 'function [a-z][a-zA-Z]{30,}\(' --include='*.php' app/ | head -30
102
+
103
+ # Names starting with "the" — a strong AI tell
104
+ grep -rEnH '\b(theUser|theOrder|theData|theResult|theItem|theCurrent)' \
105
+ --include='*.php' --include='*.ts' --include='*.tsx' app/ src/
106
+ ```
107
+
108
+ Reference: [Clean Code — Chapter 2](https://www.oreilly.com/library/view/clean-code/9780136083238/) · Internal: [`naming-generic-placeholders`](naming-generic-placeholders.md) (the opposite failure mode)
@@ -0,0 +1,167 @@
1
+ ---
2
+ title: Suffix Abuse — *Helper, *Manager, *Util, *Wrapper, *Processor
3
+ impact: HIGH
4
+ impactDescription: "Catch-all suffixes signal undecided design and pad code with empty abstractions"
5
+ tags: naming, suffixes, ai-fingerprint, abstractions
6
+ ---
7
+
8
+ ## Suffix Abuse — *Helper,*Manager,*Util,*Wrapper,*Processor
9
+
10
+ **Impact: HIGH (Catch-all suffixes signal undecided design and pad code with empty abstractions)**
11
+
12
+ `UserHelper`, `OrderManager`, `DataUtil`, `RequestWrapper`, `PaymentProcessor` — these suffixes are the AI's go-to when it doesn't know what to call something. The suffix is non-information: every class is in some sense a "manager" or "helper" or "util". The name describes the noun-form of "code I had to put somewhere".
13
+
14
+ When a model generates these, it's because:
15
+
16
+ - The "Helper" class is doing things that belong on the model
17
+ - The "Manager" is a procedural blob masquerading as a class
18
+ - The "Util" is a kitchen sink that should be split or absorbed into domain types
19
+
20
+ Real domain code uses domain names: `Pricing`, `RefundPolicy`, `WebhookVerifier` — not `PricingHelper`, `RefundManager`, `WebhookProcessor`.
21
+
22
+ ## Incorrect
23
+
24
+ ```php
25
+ // ❌ Suffix abuse — every concern wrapped in *Helper or *Manager
26
+
27
+ class UserHelper
28
+ {
29
+ public function formatName(User $user): string {
30
+ return $user->firstName . ' ' . $user->lastName;
31
+ }
32
+ }
33
+
34
+ class OrderManager
35
+ {
36
+ public function processOrder(Order $order): void {
37
+ // ...
38
+ }
39
+ }
40
+
41
+ class PaymentProcessor
42
+ {
43
+ public function processPayment(Order $order, string $token): Charge {
44
+ // ...
45
+ }
46
+ }
47
+
48
+ class DataUtil
49
+ {
50
+ public static function arrayToCsv(array $rows): string { /* ... */ }
51
+ public static function csvToArray(string $csv): array { /* ... */ }
52
+ public static function snakeToCamel(string $s): string { /* ... */ }
53
+ public static function camelToSnake(string $s): string { /* ... */ }
54
+ // …grows forever
55
+ }
56
+ ```
57
+
58
+ ```typescript
59
+ // ❌ Same TS pattern
60
+ class StringHelper {
61
+ static capitalize(s: string): string {
62
+ /* ... */
63
+ }
64
+ static slugify(s: string): string {
65
+ /* ... */
66
+ }
67
+ }
68
+
69
+ class ResponseWrapper {
70
+ constructor(private res: ApiResponse) {}
71
+ getData() {
72
+ return this.res.data;
73
+ }
74
+ }
75
+ ```
76
+
77
+ **Why it's slop:**
78
+
79
+ - `UserHelper.formatName(user)` could just be `user.fullName` on the User model
80
+ - `OrderManager.processOrder(order)` is two ways of saying the same thing
81
+ - `DataUtil` is a kitchen sink — every utility ends up here, none have a clear home
82
+ - The suffix doesn't add information; it admits the author didn't decide what the class is
83
+
84
+ ## Correct
85
+
86
+ ```php
87
+ // ✅ Behavior lives on the domain type; helpers split by concern
88
+
89
+ class User extends Model
90
+ {
91
+ public function getFullNameAttribute(): string
92
+ {
93
+ return "{$this->firstName} {$this->lastName}";
94
+ }
95
+ }
96
+
97
+ // Action class — replaces "OrderManager.processOrder"
98
+ final class PlaceOrder
99
+ {
100
+ public function __invoke(Order $order, PaymentIntent $payment): void { /* ... */ }
101
+ }
102
+
103
+ // Domain class with a clear single responsibility — replaces "PaymentProcessor"
104
+ final class StripePaymentGateway implements PaymentGateway
105
+ {
106
+ public function charge(Money $amount, string $token): Charge { /* ... */ }
107
+ }
108
+
109
+ // CSV becomes its own type — replaces the kitchen-sink DataUtil
110
+ final class CsvExporter
111
+ {
112
+ public function export(iterable $rows, array $headers): string { /* ... */ }
113
+ }
114
+ ```
115
+
116
+ ```typescript
117
+ // ✅ Methods on the domain type, or named domain functions
118
+ class User {
119
+ get fullName(): string {
120
+ return `${this.firstName} ${this.lastName}`;
121
+ }
122
+ }
123
+
124
+ // Free function — capitalize doesn't need a class wrapper
125
+ export function capitalize(s: string): string {
126
+ /* ... */
127
+ }
128
+ export function slugify(s: string): string {
129
+ /* ... */
130
+ }
131
+ ```
132
+
133
+ **Why it reads human:**
134
+
135
+ - Each class has a specific domain responsibility (CsvExporter exports CSVs; PlaceOrder places orders)
136
+ - Behavior-on-data is on the type that holds the data (`user.fullName`)
137
+ - Free functions stand on their own when there's no state to wrap
138
+
139
+ ## When suffixes ARE okay
140
+
141
+ A handful of suffixes carry real meaning in their conventions:
142
+
143
+ - **`*Repository`** — DDD-style data access (specific contract)
144
+ - **`*Service`** — used sparingly for orchestration that doesn't fit on a domain type
145
+ - **`*Controller`** — HTTP entry point (Laravel/Express convention)
146
+ - **`*Middleware`** — request pipeline (Express/Laravel convention)
147
+ - **`*Gateway`** — external integration boundary (Stripe, AWS)
148
+ - **`*Listener`** / `*Observer` — event-handler conventions (Laravel)
149
+
150
+ `*Helper`, `*Manager`, `*Util`, `*Wrapper`, `*Processor` are the suspect tier.
151
+
152
+ ## Detection
153
+
154
+ ```bash
155
+ # Class declarations with suspect suffixes
156
+ grep -rEn 'class\s+[A-Z][a-zA-Z]*(Helper|Manager|Util|Utils|Wrapper|Processor|Handler)\b' \
157
+ --include='*.php' --include='*.ts' --include='*.tsx' app/ src/
158
+
159
+ # Count by suffix to size the problem
160
+ grep -rE 'class\s+[A-Z][a-zA-Z]*' --include='*.php' --include='*.ts' app/ src/ \
161
+ | grep -oE '(Helper|Manager|Util|Utils|Wrapper|Processor)\b' \
162
+ | sort | uniq -c | sort -rn
163
+ ```
164
+
165
+ A repo with **5+ `*Helper`** or **3+ `*Manager`** classes is almost certainly leaking domain logic into catch-all classes. Refactor by asking "what would I call this if I couldn't use the suffix?"
166
+
167
+ Reference: [Clean Code — Chapter 2: Meaningful Names](https://www.oreilly.com/library/view/clean-code/9780136083238/) · Internal: [`over-eng-single-method-class`](over-eng-single-method-class.md)
@@ -0,0 +1,100 @@
1
+ ---
2
+ title: Type Encoded in Variable Names
3
+ impact: MEDIUM
4
+ impactDescription: "Embeds type in the identifier when the type system already does it; ages badly with refactors"
5
+ tags: naming, hungarian, type-in-name, ai-fingerprint
6
+ ---
7
+
8
+ ## Type Encoded in Variable Names
9
+
10
+ **Impact: MEDIUM (Embeds type in the identifier when the type system already does it; ages badly with refactors)**
11
+
12
+ `userObject`, `resultArray`, `stringData`, `listOfItems`, `userIdString`, `dataMap` — these names encode the _type_ of the value, redundantly with the actual type declaration. Both PHP 8+ and TypeScript have rich type systems that show the type in the signature. The name should encode what the value **means**, not what its shape is.
13
+
14
+ The pattern is a tell because it suggests the author optimised for "obvious from any one line" rather than "obvious in context". A human author trusts the reader to look at the signature.
15
+
16
+ ## Incorrect
17
+
18
+ ```php
19
+ // ❌ Type-in-name everywhere
20
+
21
+ public function processItemsList(array $itemsArray, int $userIdInteger): array
22
+ {
23
+ $resultArray = [];
24
+ foreach ($itemsArray as $itemObject) {
25
+ $priceFloat = $itemObject->priceFloat;
26
+ $resultArray[] = $priceFloat;
27
+ }
28
+ return $resultArray;
29
+ }
30
+ ```
31
+
32
+ ```typescript
33
+ // ❌ Same in TS
34
+ function getUserDataObject(userIdString: string): UserDataResponseObject {
35
+ const responseObject = await api.fetch(userIdString);
36
+ const dataArray = responseObject.dataArray;
37
+ const userObjectList = dataArray.map((itemObject: UserObject) => itemObject);
38
+ return userObjectList;
39
+ }
40
+ ```
41
+
42
+ **Why it's slop:**
43
+
44
+ - The type is declared on the parameter and visible in the signature
45
+ - Renaming `$itemsArray` to a `Collection` requires updating every variable reference
46
+ - The name `$itemObject` is redundant — the static type says it's a `User`
47
+ - Pattern is a clear "tutorial-blog" signature; teammates don't write like this
48
+
49
+ ## Correct
50
+
51
+ ```php
52
+ // ✅ Names encode meaning, not shape
53
+
54
+ public function totalsFor(array $items, int $userId): array
55
+ {
56
+ return array_map(fn (Item $item) => $item->price, $items);
57
+ }
58
+ ```
59
+
60
+ ```typescript
61
+ // ✅ Domain words, types in the signature
62
+ async function fetchUser(userId: string): Promise<User> {
63
+ const { data } = await api.fetch(userId);
64
+ return data;
65
+ }
66
+ ```
67
+
68
+ **Why it reads human:**
69
+
70
+ - Each name describes the role (`items`, `userId`, `total`) not the shape
71
+ - Type info is in the type system, where refactors update it automatically
72
+ - If `items` becomes a `Collection<Item>`, the variable name still reads correctly
73
+
74
+ ## When type-in-name IS okay
75
+
76
+ Conventions where the type is part of the meaning:
77
+
78
+ - **`*Id`** suffix — `userId` (distinguishes from `user` which is the whole object) ✓
79
+ - **`*Count`** suffix — `userCount` ✓
80
+ - **`is*`** / **`has*`** / **`can*`** booleans — `isPaid`, `hasShipping`, `canEdit` ✓
81
+ - **Maps with two-type names** — `usersByEmail` (carries both types in one word) ✓
82
+ - **DTO classes** — `UserResponse`, `OrderPayload` (clarifies "this is the wire form, not the domain model") ✓
83
+
84
+ The suspect patterns are `*Object`, `*Array`, `*List`, `*Map`, `*String`, `*Integer`, `*Float` on local variables.
85
+
86
+ ## Detection
87
+
88
+ ```bash
89
+ # Suspect type-suffix names on variables (PHP)
90
+ grep -rEn '\$[a-z][a-zA-Z]*?(Object|Array|List|Map|String|Integer|Float|Boolean|Bool)\b' \
91
+ --include='*.php' app/
92
+
93
+ # TS / JS
94
+ grep -rEn '\b(const|let)\s+[a-z][a-zA-Z]*?(Object|Array|List|Map|String|Boolean)\b' \
95
+ --include='*.ts' --include='*.tsx' --include='*.js' --include='*.jsx' src/
96
+ ```
97
+
98
+ A few hits are fine (especially in test data setups). **Density across multiple files** is the signal — a project with 30+ `*Array` / `*Object` variables almost certainly came from a model.
99
+
100
+ Reference: [Clean Code — Chapter 2](https://www.oreilly.com/library/view/clean-code/9780136083238/) · [Joel Spolsky — Making Wrong Code Look Wrong](https://www.joelonsoftware.com/2005/05/11/making-wrong-code-look-wrong/) (the "useful Hungarian" original — different from this rule's anti-pattern) · Internal: [`naming-over-descriptive`](naming-over-descriptive.md)
@@ -0,0 +1,114 @@
1
+ ---
2
+ title: Dependency Creep — New Library When Existing One Suffices
3
+ impact: HIGH
4
+ impactDescription: "Inflates bundle/install size, adds CVE surface, signals model picked training-data favourites"
5
+ tags: over-engineering, dependencies, dependency-creep, ai-fingerprint
6
+ ---
7
+
8
+ ## Dependency Creep — New Library When Existing One Suffices
9
+
10
+ **Impact: HIGH (Inflates bundle/install size, adds CVE surface, signals model picked training-data favourites)**
11
+
12
+ AI tends to introduce a new dependency whenever a problem matches a library it has seen in training, even when the project already includes a dependency that solves the same problem. Example signals:
13
+
14
+ - Adding `date-fns` to a project that already uses `dayjs`
15
+ - Adding `axios` to a project that already imports `fetch` everywhere
16
+ - Adding `lodash` to a project that already has `lodash-es` (or uses native ES methods)
17
+ - Adding `uuid` when the project already uses `nanoid`
18
+ - Adding `winston` when the app uses `pino`
19
+ - Adding `joi` / `yup` to a TS project that already uses `zod`
20
+ - Adding `bcrypt` (the npm package) in a Laravel project where `Hash::make` handles it
21
+ - Adding `moment` in a project that just removed `moment` last quarter
22
+
23
+ Each new dependency:
24
+
25
+ - Adds to install / bundle size
26
+ - Adds a new CVE surface (every `npm audit` lights up)
27
+ - Forces the team to maintain TWO libraries for the same concern, indefinitely
28
+ - Drifts as the LLM picks whichever was popular in the training-data slice it sampled from
29
+
30
+ ## Incorrect
31
+
32
+ ```json
33
+ // ❌ package.json — two libs doing the same job
34
+ {
35
+ "dependencies": {
36
+ "dayjs": "^1.11.10", // already in use
37
+ "date-fns": "^3.0.0", // ADDED — same purpose
38
+ "axios": "^1.6.0", // ADDED — but app uses fetch everywhere
39
+ "lodash": "^4.17.21", // ADDED — lodash-es already present
40
+ "lodash-es": "^4.17.21"
41
+ }
42
+ }
43
+ ```
44
+
45
+ ```php
46
+ // ❌ composer.json — two HTTP clients
47
+ {
48
+ "require": {
49
+ "guzzlehttp/guzzle": "^7.8",
50
+ "symfony/http-client": "^7.0" // ADDED — same purpose
51
+ }
52
+ }
53
+ ```
54
+
55
+ **Why it's slop:**
56
+
57
+ - Both libraries get pulled into every install
58
+ - New `dayjs` code still gets written alongside the new `date-fns` code — drift forever
59
+ - Two CVE feeds to track
60
+ - Reviewer didn't notice because each PR seems reasonable in isolation
61
+
62
+ ## Correct
63
+
64
+ ```bash
65
+ # ✅ Use the existing dep; reject the PR adding the new one with a note
66
+
67
+ # Before merging a PR that adds a new dependency, ask:
68
+ # 1. Does an existing dependency in package.json/composer.json already do this?
69
+ # 2. Does a native browser/Node/PHP API already do this?
70
+ # 3. Is the new dep > 50KB gzipped (or > 1MB unpacked) for a single function call?
71
+ # 4. Does it have CVEs / abandoned upstream?
72
+ #
73
+ # If any answer is "yes" or "maybe", reject and use the existing tool.
74
+ ```
75
+
76
+ Common collisions and the canonical choice:
77
+
78
+ | Concern | Pick one |
79
+ | ------------------------- | ---------------------------------------------------------------------------------------- |
80
+ | Date / time | `dayjs` OR `date-fns` (not both) |
81
+ | HTTP client | `fetch` OR `axios` (not both) |
82
+ | UUID | `uuid` OR `nanoid` (not both) |
83
+ | Schema validation (TS) | `zod` (preferred) — reject `joi`/`yup`/`ajv` additions |
84
+ | HTTP client (PHP) | `guzzlehttp/guzzle` (Laravel default) — reject `symfony/http-client` unless project-wide |
85
+ | Logging | `monolog` (Laravel default) for PHP; pick one of `pino`/`winston` for Node |
86
+ | Form validation (Laravel) | Built-in `FormRequest` — reject standalone validation libs |
87
+
88
+ ## Detection
89
+
90
+ ```bash
91
+ # Node: dependency-list audit
92
+ node -e "
93
+ const pkg = require('./package.json');
94
+ const all = { ...pkg.dependencies, ...pkg.devDependencies };
95
+ const dupes = [
96
+ ['dayjs', 'date-fns', 'moment', 'luxon'],
97
+ ['axios', 'node-fetch', 'got', 'superagent'],
98
+ ['uuid', 'nanoid', 'cuid'],
99
+ ['lodash', 'lodash-es', 'ramda'],
100
+ ['joi', 'yup', 'zod', 'ajv'],
101
+ ];
102
+ for (const group of dupes) {
103
+ const found = group.filter(p => all[p]);
104
+ if (found.length > 1) console.log('OVERLAP:', found.join(', '));
105
+ }
106
+ "
107
+
108
+ # PHP: check for HTTP-client overlap
109
+ grep -E '\"(guzzlehttp/guzzle|symfony/http-client|kriswallsmith/buzz)\"' composer.json
110
+ ```
111
+
112
+ When a new dep lands in a PR, the PR author should justify why the existing options don't fit. "AI suggested this" is not a justification.
113
+
114
+ Reference: [`technical-debt`'s `deps-unused-deps`](../technical-debt/rules/deps-unused-deps.md) (the broader audit) · [BundlePhobia](https://bundlephobia.com/) (size impact for npm packages)