@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,130 @@
1
+ ---
2
+ title: Placeholder Comments Left In
3
+ impact: CRITICAL
4
+ impactDescription: "Reveals AI-generated code that was never completed; ships unfinished work as 'done'"
5
+ tags: comments, placeholder, todo, ai-fingerprint
6
+ ---
7
+
8
+ ## Placeholder Comments Left In
9
+
10
+ **Impact: CRITICAL (Reveals AI-generated code that was never completed; ships unfinished work as 'done')**
11
+
12
+ Common AI-generated placeholders that should never reach `main`:
13
+
14
+ ```
15
+ // implementation
16
+ // implementation here
17
+ // your code here
18
+ // helper function
19
+ // TODO: implement
20
+ // TODO: implement this
21
+ // TODO: add error handling
22
+ // TODO: implement validation
23
+ // FIXME: figure out edge case
24
+ // HACK: temporary
25
+ // placeholder
26
+ // add your logic here
27
+ ```
28
+
29
+ These mean the AI produced scaffolding the developer was supposed to fill in. If they reach the PR, they signal the author shipped without reading.
30
+
31
+ Distinct from properly-tagged debt markers — a `// TODO(#1234, asyraf): rewrite after Stripe v2 migration` with an owner, ticket, and concrete unblocking condition is _not_ slop. That's tracked debt.
32
+
33
+ ## Incorrect
34
+
35
+ ```php
36
+ // ❌ Placeholder comments shipped as 'done'
37
+
38
+ public function calculateRefund(Order $order): Money
39
+ {
40
+ // TODO: implement
41
+ return Money::zero();
42
+ }
43
+
44
+ public function process(Order $order): void
45
+ {
46
+ // Validate the order
47
+ // TODO: add validation
48
+
49
+ $this->charge($order);
50
+
51
+ // helper function
52
+ // TODO: implement error handling
53
+ }
54
+ ```
55
+
56
+ ```typescript
57
+ // ❌ Same in TS
58
+ function exportUsers(): User[] {
59
+ // your code here
60
+ return [];
61
+ }
62
+
63
+ function handlePayment(token: string) {
64
+ // implementation
65
+ // TODO: implement
66
+ }
67
+ ```
68
+
69
+ **Why it's slop:**
70
+
71
+ - The function name promises a Behavior the body doesn't deliver
72
+ - Reviewers usually skip past `// TODO` without realising the function is empty
73
+ - These slip through tests because the placeholder body type-checks
74
+ - If genuinely intended as future work, it belongs in the issue tracker, not the source file
75
+
76
+ ## Correct
77
+
78
+ ```php
79
+ // ✅ Either implement, or fail loud, or remove the method entirely
80
+
81
+ public function calculateRefund(Order $order): Money
82
+ {
83
+ throw new BadMethodCallException(
84
+ 'Refund calculation not yet implemented — see #1842 for the policy spec.'
85
+ );
86
+ }
87
+
88
+ // ✅ Or genuine, tracked work-in-progress with owner + ticket:
89
+ // TODO(#1842, asyraf): cap refunds at original-charge-minus-shipping
90
+ public function calculateRefund(Order $order): Money
91
+ {
92
+ return $order->total->subtract($order->shippingCost);
93
+ }
94
+ ```
95
+
96
+ ```typescript
97
+ // ✅ Fail loud so the gap is impossible to ship past
98
+ function exportUsers(): User[] {
99
+ throw new Error("exportUsers: not implemented (see #420)");
100
+ }
101
+ ```
102
+
103
+ **Why it reads human:**
104
+
105
+ - An empty function body that throws is impossible to merge by accident; tests will catch it
106
+ - A tracked `TODO` with `(#issue, @owner)` is real debt, not abandoned scaffolding
107
+ - A human author either implements the function or explicitly fails — they don't ship "Returns nothing for now"
108
+
109
+ ## Detection
110
+
111
+ ```bash
112
+ # Common AI placeholders — match only when prefixed by a comment marker
113
+ # (without the required prefix, the regex would flood on class names like "ServiceImplementation").
114
+ grep -rEn --include='*.php' --include='*.ts' --include='*.tsx' --include='*.js' --include='*.jsx' \
115
+ '(//|/\*|#)\s*(implementation|implementation here|your code here|helper function|placeholder|add your logic|add error handling|add validation)\b' \
116
+ app/ src/ 2>/dev/null
117
+
118
+ # Bare TODO/FIXME (without ticket reference)
119
+ grep -rEn --include='*.php' --include='*.ts' --include='*.tsx' --include='*.js' --include='*.jsx' \
120
+ '(TODO|FIXME)([^(#]|$)' app/ src/ 2>/dev/null | grep -v '#[0-9]'
121
+
122
+ # Combined: TODOs lacking issue references — CI gate
123
+ NEW=$(git diff --name-only --diff-filter=ACM origin/main...HEAD)
124
+ BARE=$(echo "$NEW" | xargs grep -EnH '\b(TODO|FIXME)\b' 2>/dev/null | grep -v '#[0-9]')
125
+ test -z "$BARE" || { echo "Bare TODO/FIXME found — add (#issue, @owner):"; echo "$BARE"; exit 1; }
126
+ ```
127
+
128
+ See also `technical-debt`'s `process-todo-fixme-aging` rule — the broader policy for tracked debt markers.
129
+
130
+ Reference: Internal: [`comments-narration`](comments-narration.md)
@@ -0,0 +1,153 @@
1
+ ---
2
+ title: Generic catch Blocks That Don't Distinguish Errors
3
+ impact: CRITICAL
4
+ impactDescription: "82% of AI PRs (OX Security) — masks bugs as 'handled', breaks observability, kills debuggability"
5
+ tags: defensive-programming, error-handling, ai-fingerprint
6
+ ---
7
+
8
+ ## Generic catch Blocks That Don't Distinguish Errors
9
+
10
+ **Impact: CRITICAL (82% of AI PRs per OX Security study; masks bugs as 'handled', breaks observability, kills debuggability)**
11
+
12
+ The single most-cited AI anti-pattern in 2025 research. Try/catch wrapped around code, with a generic catch that logs and swallows. Looks responsible. Is the opposite — it hides bugs and converts loud failures into silent corruption.
13
+
14
+ Real error handling distinguishes:
15
+
16
+ - **What can throw** (specific exception types)
17
+ - **What's recoverable** (catch, retry, fall back)
18
+ - **What's a bug** (re-throw, let it propagate)
19
+
20
+ A bare `catch (e) { console.error(e); }` does none of this. It says "if anything goes wrong, I'll keep going" — and "anything" includes programmer errors that should crash so they're noticed.
21
+
22
+ ## Incorrect
23
+
24
+ ```php
25
+ // ❌ Generic catch that swallows everything
26
+
27
+ public function processPayment(Order $order): bool
28
+ {
29
+ try {
30
+ $charge = $this->stripe->charges->create([
31
+ 'amount' => $order->total->cents(),
32
+ 'currency' => 'usd',
33
+ 'source' => $order->paymentToken,
34
+ ]);
35
+ $order->update(['stripe_charge_id' => $charge->id, 'status' => 'paid']);
36
+ return true;
37
+ } catch (Exception $e) {
38
+ Log::error('Payment failed: ' . $e->getMessage());
39
+ return false;
40
+ }
41
+ }
42
+ ```
43
+
44
+ ```typescript
45
+ // ❌ Same TS pattern
46
+ async function exportUsers(): Promise<User[]> {
47
+ try {
48
+ const users = await api.fetchAllUsers();
49
+ return users;
50
+ } catch (e) {
51
+ console.error("Export failed:", e);
52
+ return [];
53
+ }
54
+ }
55
+ ```
56
+
57
+ **Why it's slop:**
58
+
59
+ - `Exception $e` catches _everything_, including `TypeError` (programmer bug) and `OutOfMemoryError` (system crash) — those should not be "handled" by logging and continuing
60
+ - Returning `false` / `[]` lets the caller think the operation succeeded with no data, masking a real failure
61
+ - `Log::error` lacks context — what was the order? what user? what amount? Future debugger has no anchor
62
+ - A real Stripe error (card declined) gets the same treatment as a typo in the code
63
+
64
+ ## Correct
65
+
66
+ ```php
67
+ // ✅ Catch specifically; re-throw what you don't understand
68
+
69
+ public function processPayment(Order $order): void
70
+ {
71
+ try {
72
+ $charge = $this->stripe->charges->create([
73
+ 'amount' => $order->total->cents(),
74
+ 'currency' => 'usd',
75
+ 'source' => $order->paymentToken,
76
+ ]);
77
+ $order->update(['stripe_charge_id' => $charge->id, 'status' => 'paid']);
78
+ } catch (CardException $e) {
79
+ // Customer-facing failure — known, expected
80
+ $order->update(['status' => 'declined', 'decline_reason' => $e->getStripeCode()]);
81
+ throw new PaymentDeclined($e->getStripeCode(), previous: $e);
82
+ } catch (RateLimitException $e) {
83
+ // Transient — caller retries
84
+ throw new TransientPaymentFailure(retryAfterSeconds: 30, previous: $e);
85
+ }
86
+ // Any other exception propagates: TypeError, OutOfMemoryError, etc.
87
+ // — those are bugs we WANT to know about.
88
+ }
89
+ ```
90
+
91
+ ```typescript
92
+ // ✅ Specific errors, propagate the unknown
93
+ async function exportUsers(): Promise<User[]> {
94
+ try {
95
+ return await api.fetchAllUsers();
96
+ } catch (e) {
97
+ if (e instanceof AbortError) {
98
+ // Caller aborted; that's a feature, not a failure
99
+ throw e;
100
+ }
101
+ if (e instanceof RateLimitError) {
102
+ await sleep(e.retryAfterMs);
103
+ return api.fetchAllUsers(); // one retry
104
+ }
105
+ // Network / parse / bug — propagate; don't return [] (the caller would think it succeeded with no users)
106
+ throw e;
107
+ }
108
+ }
109
+ ```
110
+
111
+ **Why it reads human:**
112
+
113
+ - Each `catch` branch handles a specific, named condition with a specific remediation
114
+ - Unknown errors propagate — the system fails loud, observability catches them, on-call wakes up before customers do
115
+ - No silent "return false" / "return empty array" — caller can't accidentally treat failure as empty success
116
+
117
+ ## The "what would I want at 2am?" test
118
+
119
+ When debugging a production incident, you want:
120
+
121
+ - **Errors at the right loudness** — bugs crash with stack traces; expected failures have domain-specific exceptions you can grep
122
+ - **Context, not just the message** — order ID, user ID, request ID, all in the log line
123
+ - **No silent corruption** — a "successful" call that returned no data is the worst kind of failure
124
+
125
+ The generic-catch pattern fails all three.
126
+
127
+ ## Detection
128
+
129
+ ```bash
130
+ # Bare catches in PHP
131
+ grep -rEn 'catch\s*\(\s*\\?Exception\b' --include='*.php' app/
132
+
133
+ # Bare catches in TS / JS
134
+ grep -rEn '\}\s*catch\s*\(\s*[a-zA-Z_]+\s*\)\s*\{' --include='*.ts' --include='*.tsx' --include='*.js' src/
135
+
136
+ # Catch blocks that only log and continue
137
+ grep -rEnB1 'console\.error\(.*\)\s*;\s*$' --include='*.ts' --include='*.tsx' src/
138
+
139
+ # PHP equivalent
140
+ grep -rEnB1 'Log::(error|warning)\(.*\)' --include='*.php' app/Http/ app/Services/
141
+
142
+ # Linter rules
143
+ # Oxlint: enable no-empty for empty blocks and typescript/no-explicit-any for explicit any
144
+ # These checks do not detect catch blocks that only log and continue.
145
+ # Mago: detect empty PHP catch bodies
146
+ mago lint --only no-empty-catch-clause
147
+ ```
148
+
149
+ Mago's `no-empty-catch-clause` does not flag non-empty log-and-continue handlers. Review those manually. For catches that cannot match a known exception, the analyzer offers `check-dead-catch`, which requires `check-throws`; both default to `false`. These options check exception flow, not whether a catch is too broad, and undocumented throws can limit their accuracy.
150
+
151
+ A small handful of generic catches is fine (e.g., at HTTP boundaries with structured logging). **Density** is the signal — > 5 generic catches in a single service is the AI fingerprint.
152
+
153
+ Reference: [Oxlint no-empty](https://oxc.rs/docs/guide/usage/linter/rules/eslint/no-empty.html) · [Oxlint typescript/no-explicit-any](https://oxc.rs/docs/guide/usage/linter/rules/typescript/no-explicit-any.html) · [Mago no-empty-catch-clause](https://mago.carthage.software/1.59.0/en/tools/linter/rules/#no-empty-catch-clause) · [Mago analyzer configuration](https://mago.carthage.software/1.59.0/en/tools/analyzer/configuration-reference/) · Internal: [`defensive-impossible-null`](defensive-impossible-null.md), [`defensive-missing-real`](defensive-missing-real.md)
@@ -0,0 +1,157 @@
1
+ ---
2
+ title: Null Checks for Impossible Nulls
3
+ impact: HIGH
4
+ impactDescription: "Defensive code in places that can't fail; clutters the path and signals model didn't trust the type system"
5
+ tags: defensive-programming, null-checks, type-safety, ai-fingerprint
6
+ ---
7
+
8
+ ## Null Checks for Impossible Nulls
9
+
10
+ **Impact: HIGH (Defensive code in places that can't fail; clutters the path and signals model didn't trust the type system)**
11
+
12
+ When the type system or surrounding code already guarantees a value is non-null, a defensive null check adds noise and tells the reader "the author wasn't sure". Common cases:
13
+
14
+ - A non-nullable parameter (typed `User $user`, not `?User $user`) — can't be null
15
+ - After `Model::findOrFail()` — never returns null (throws on miss)
16
+ - After a non-null assertion in the previous line
17
+ - Inside a `forEach` / `map` loop where the iterable can't contain null
18
+
19
+ The pattern signals the model defaulted to "check everything for safety" without reading the types around it.
20
+
21
+ ## Incorrect
22
+
23
+ ```php
24
+ // ❌ Null check after findOrFail — findOrFail throws if not found
25
+
26
+ public function show(int $id): View
27
+ {
28
+ $user = User::findOrFail($id);
29
+
30
+ if ($user === null) {
31
+ abort(404);
32
+ }
33
+
34
+ return view('users.show', compact('user'));
35
+ }
36
+
37
+ // ❌ Null check on a non-nullable parameter
38
+
39
+ public function notify(User $user, string $message): void // $user is required
40
+ {
41
+ if ($user === null) {
42
+ return;
43
+ }
44
+ Mail::to($user)->send(new GenericNotification($message));
45
+ }
46
+
47
+ // ❌ Null check repeated in same function
48
+ public function process(Order $order): void
49
+ {
50
+ if ($order === null) return;
51
+ $items = $order->items;
52
+ if ($order === null) return; // already checked above; flow can't make it null
53
+ foreach ($items as $item) {
54
+ if ($order === null) return; // still impossible
55
+ // ...
56
+ }
57
+ }
58
+ ```
59
+
60
+ ```typescript
61
+ // ❌ TS: defensive checks the compiler already enforced
62
+
63
+ function greet(user: User): string {
64
+ // `user: User` — non-null in type system
65
+ if (!user) return ""; // dead branch; TS would error
66
+ return `Hi, ${user.name}`;
67
+ }
68
+
69
+ // ❌ Defensive after a guard
70
+ function process(user: User | null): void {
71
+ if (!user) return; // narrows to User
72
+ if (user) {
73
+ // always true after the guard
74
+ doStuff(user);
75
+ }
76
+ }
77
+
78
+ // ❌ Optional chaining on a definitely-defined value
79
+ const userId = currentUser.id; // currentUser is non-nullable here
80
+ console.log(currentUser?.email); // ?. is unnecessary
81
+ ```
82
+
83
+ **Why it's slop:**
84
+
85
+ - The dead branch is dead — never executes; reviewers must mentally rule it out
86
+ - Signals the author didn't trust the type system
87
+ - `findOrFail` is well-known Laravel API; checking its result for null says "I read the docs but don't believe them"
88
+ - Stacking redundant guards in one function (the third example) is unmistakable
89
+
90
+ ## Correct
91
+
92
+ ```php
93
+ // ✅ Trust findOrFail — it throws, doesn't return null
94
+
95
+ public function show(int $id): View
96
+ {
97
+ return view('users.show', [
98
+ 'user' => User::findOrFail($id),
99
+ ]);
100
+ }
101
+
102
+ // ✅ Non-nullable parameter — no check needed
103
+ public function notify(User $user, string $message): void
104
+ {
105
+ Mail::to($user)->send(new GenericNotification($message));
106
+ }
107
+ ```
108
+
109
+ ```typescript
110
+ // ✅ Trust the types
111
+ function greet(user: User): string {
112
+ return `Hi, ${user.name}`;
113
+ }
114
+
115
+ // ✅ Single guard; TS narrows the type below
116
+ function process(user: User | null): void {
117
+ if (!user) return;
118
+ doStuff(user); // TS knows user is User here
119
+ }
120
+
121
+ // ✅ No optional chaining when not optional
122
+ console.log(currentUser.email);
123
+ ```
124
+
125
+ **Why it reads human:**
126
+
127
+ - Each line carries weight; no dead branches
128
+ - Type system does the work, not runtime checks
129
+ - Reader can scan past the function without ruling out impossible paths
130
+
131
+ ## When null checks ARE warranted
132
+
133
+ - **At trust boundaries** — input from HTTP/queue/file, before the type narrows
134
+ - **On nullable returns** from third-party libraries (e.g., `Eloquent::find()` returns `?Model`)
135
+ - **In `try {} catch` flows** where the value might be partially constructed
136
+ - **When the type really IS nullable** — `?User $user` parameters that the caller can leave empty
137
+
138
+ The test: **does the type say it could be null?** If yes, check. If no, trust.
139
+
140
+ ## Detection
141
+
142
+ ```bash
143
+ # Null checks immediately after findOrFail in PHP — a recognisable AI signature
144
+ # (Two-pass: find files with findOrFail, then look for null checks inside them.)
145
+ grep -rl 'findOrFail' --include='*.php' app/ | xargs grep -EnB1 'if\s*\(\s*\$[a-zA-Z_]+\s*===?\s*null\s*\)' 2>/dev/null
146
+
147
+ # TS: optional chaining on values typed as non-null
148
+ # (best caught via TS strict mode: noUncheckedIndexedAccess + strictNullChecks)
149
+ npx tsc --noEmit --strict
150
+
151
+ # PHP: run Mago's type analyzer, not just its syntax-based linter
152
+ mago analyze
153
+ ```
154
+
155
+ Use Mago's analyzer for PHP type analysis and inspect its diagnostics alongside the guard and surrounding control flow. Detection depends on the available type information, framework stubs, and configured ignores or baseline; a clean run does not prove every null check necessary. For TypeScript, retain strict type checking and manually verify redundant guards.
156
+
157
+ Reference: [Mago analyzer configuration](https://mago.carthage.software/1.59.0/en/tools/analyzer/configuration-reference/) · [Mago analyzer command reference](https://mago.carthage.software/1.59.0/en/tools/analyzer/command-reference/) · [TS strict mode](https://www.typescriptlang.org/tsconfig#strict) · Internal: [`defensive-generic-catch`](defensive-generic-catch.md), [`defensive-missing-real`](defensive-missing-real.md)
@@ -0,0 +1,157 @@
1
+ ---
2
+ title: Defensive in the Wrong Places — Missing the Real Defenses
3
+ impact: CRITICAL
4
+ impactDescription: "Code looks safe but the *actual* failure modes (network, queues, races) are unprotected"
5
+ tags: defensive-programming, timeouts, resilience, ai-fingerprint
6
+ ---
7
+
8
+ ## Defensive in the Wrong Places — Missing the Real Defenses
9
+
10
+ **Impact: CRITICAL (Code looks safe but the actual failure modes — network, queues, races — are unprotected)**
11
+
12
+ OX Security 2025: **76% of AI-assisted PRs miss timeouts on external calls**. The same PRs are full of impossible null checks and generic try/catch. The pattern is: defensive in places that don't need it; not defensive in places that do.
13
+
14
+ What AI often misses (the failure modes that actually take down production):
15
+
16
+ - **No timeouts on outbound HTTP** — a slow third-party API hangs your request indefinitely
17
+ - **No retry policy + jitter** — a transient blip cascades into a customer-visible failure
18
+ - **No idempotency keys on payment/order creation** — a network retry creates duplicate charges
19
+ - **No rate-limit checks before hitting an external API** — banned by Stripe / Shopify / etc.
20
+ - **No circuit breaker** — keeps hammering a known-down dependency, queue backs up
21
+ - **No locking / unique constraint** — race condition double-spends inventory
22
+ - **No backpressure on workers** — queue grows unbounded; OOM
23
+
24
+ These are the defenses that matter. A robust system has these; the dramatic-looking try/catch and null checks don't replace them.
25
+
26
+ ## Incorrect
27
+
28
+ ```php
29
+ // ❌ Defensive theatre: try/catch wraps the wrong thing; real risks unprotected
30
+
31
+ public function syncOrder(string $orderId): void
32
+ {
33
+ try {
34
+ // No timeout — could hang for minutes
35
+ $response = Http::get("https://api.shopify.com/orders/{$orderId}");
36
+ $data = $response->json();
37
+
38
+ if ($data === null) { // impossible — Http returns array or throws
39
+ Log::error('Sync failed');
40
+ return;
41
+ }
42
+
43
+ // No idempotency — if this retries, we create duplicates
44
+ Order::create($data);
45
+ } catch (Exception $e) {
46
+ Log::error('Sync failed: ' . $e->getMessage());
47
+ }
48
+ }
49
+ ```
50
+
51
+ ```typescript
52
+ // ❌ Same pattern in TS
53
+ async function syncOrder(orderId: string): Promise<void> {
54
+ try {
55
+ // No timeout; no retry; no backoff
56
+ const res = await fetch(`https://api.shopify.com/orders/${orderId}`);
57
+ const data = await res.json();
58
+
59
+ if (!data) {
60
+ // impossible if res.json() resolved
61
+ console.error("Sync failed");
62
+ return;
63
+ }
64
+
65
+ await db.orders.create({ data });
66
+ } catch (e) {
67
+ console.error(e); // swallow
68
+ }
69
+ }
70
+ ```
71
+
72
+ **Why it's slop:**
73
+
74
+ - The `if ($data === null)` is dead defence; the actual failure mode is "Shopify takes 90s to respond and our request timeout hits us first"
75
+ - The try/catch swallows real failures but doesn't add the things that prevent them
76
+ - Retried calls create duplicate orders (idempotency missing)
77
+ - Looks responsible; isn't
78
+
79
+ ## Correct
80
+
81
+ ```php
82
+ // ✅ The real defences — timeouts, idempotency, retry with backoff, circuit-break
83
+
84
+ public function syncOrder(string $orderId): void
85
+ {
86
+ $response = Http::timeout(10) // hard timeout
87
+ ->retry(times: 3, sleepMilliseconds: 200, when: fn ($e) =>
88
+ $e instanceof ConnectionException || $e->getCode() === 429)
89
+ ->get("https://api.shopify.com/orders/{$orderId}");
90
+
91
+ $response->throw(); // throw on 4xx/5xx — let it propagate
92
+
93
+ Order::updateOrCreate(
94
+ ['shopify_id' => $orderId], // idempotency via unique key
95
+ $response->json()
96
+ );
97
+ }
98
+ ```
99
+
100
+ ```typescript
101
+ // ✅ TS with AbortController for timeout + retry policy
102
+ async function syncOrder(orderId: string): Promise<void> {
103
+ const data = await fetchWithRetry(`https://api.shopify.com/orders/${orderId}`, {
104
+ timeoutMs: 10_000,
105
+ retries: 3,
106
+ retryOnStatus: [429, 502, 503, 504],
107
+ });
108
+
109
+ // Idempotent upsert by external id (unique index on shopify_id)
110
+ await db.orders.upsert({
111
+ where: { shopify_id: orderId },
112
+ create: data,
113
+ update: data,
114
+ });
115
+ }
116
+ ```
117
+
118
+ **Why it reads human:**
119
+
120
+ - The actual failure modes (slow third party, transient errors, duplicate retries) are each addressed
121
+ - Errors NOT covered by retry propagate — observability/alerts catch them
122
+ - The idempotency key (`shopify_id`) prevents duplicate orders even under retry storms
123
+ - The "try/catch" is gone — it added no value here
124
+
125
+ ## The real-defences checklist
126
+
127
+ For any code that talks to the outside world, ask:
128
+
129
+ - [ ] **Timeout** on every outbound call (HTTP, DB, queue, cache)?
130
+ - [ ] **Retry** policy: how many, with what backoff, on which error types?
131
+ - [ ] **Idempotency**: if the call is retried, will it create duplicate side effects?
132
+ - [ ] **Rate limit** awareness: am I tracking my own request rate or relying on the upstream's error?
133
+ - [ ] **Circuit breaker** for known-down dependencies (or at least a backoff cap)?
134
+ - [ ] **Locking / unique constraints** on writes that could race?
135
+ - [ ] **Backpressure** on workers reading from a queue?
136
+ - [ ] **Real errors propagated** to observability instead of swallowed?
137
+
138
+ A try/catch that doesn't add any of these isn't a defense. It's theatre.
139
+
140
+ ## Detection
141
+
142
+ ```bash
143
+ # HTTP calls without explicit timeout (Laravel Http facade)
144
+ grep -rEn 'Http::get\(|Http::post\(|Http::put\(|Http::delete\(' --include='*.php' app/ \
145
+ | grep -v 'timeout('
146
+
147
+ # fetch() calls without AbortController / signal
148
+ grep -rEn 'await fetch\(' --include='*.ts' --include='*.tsx' --include='*.js' src/ \
149
+ | grep -vE 'signal:|AbortController'
150
+
151
+ # create() / insert() without idempotency check (rough — manual review)
152
+ grep -rEn '(Order|Charge|Payment)::create\(' --include='*.php' app/
153
+ ```
154
+
155
+ A repo can pass every other rule in this skill and still ship the wrong defenses. **This rule is the one to take seriously on payment, checkout, and integration code paths.**
156
+
157
+ Reference: [Stripe — Idempotent Requests](https://docs.stripe.com/api/idempotent_requests) · [Hystrix / Resilience4j circuit breaker patterns](https://github.com/resilience4j/resilience4j) · OX Security study · Internal: [`defensive-generic-catch`](defensive-generic-catch.md)