@mrciphersmith/keryx 0.2.164 → 0.3.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 (182) hide show
  1. package/README.md +4 -1
  2. package/dist/cli.js +82540 -50300
  3. package/dist/core.js +28967 -18937
  4. package/package.json +2 -2
  5. package/src/gdgraph/affected-report.ts +141 -0
  6. package/src/gdgraph/build.ts +170 -23
  7. package/src/gdgraph/service.ts +6 -0
  8. package/src/gdgraph/staleness.ts +253 -45
  9. package/src/gdskills/bundled/agents/codebase-navigator.md +55 -0
  10. package/src/gdskills/bundled/agents/design-advisor.md +64 -0
  11. package/src/gdskills/bundled/agents/docs-maintainer.md +56 -0
  12. package/src/gdskills/bundled/agents/end-to-end-tester.md +56 -0
  13. package/src/gdskills/bundled/agents/error-path-auditor.md +57 -0
  14. package/src/gdskills/bundled/agents/go-build-fixer.md +52 -0
  15. package/src/gdskills/bundled/agents/go-code-auditor.md +49 -0
  16. package/src/gdskills/bundled/agents/performance-auditor.md +63 -0
  17. package/src/gdskills/bundled/agents/python-build-fixer.md +52 -0
  18. package/src/gdskills/bundled/agents/python-code-auditor.md +49 -0
  19. package/src/gdskills/bundled/agents/refactoring-steward.md +61 -0
  20. package/src/gdskills/bundled/agents/security-auditor.md +62 -0
  21. package/src/gdskills/bundled/agents/test-first-driver.md +61 -0
  22. package/src/gdskills/bundled/agents/work-planner.md +62 -0
  23. package/src/gdskills/bundled/install-manifest.json +797 -0
  24. package/src/gdskills/bundled/rules/core/model-selection.mdc +51 -0
  25. package/src/gdskills/bundled/rules/core/skill-lifecycle.mdc +29 -1
  26. package/src/gdskills/bundled/rules/core/skills-storage-workflow.mdc +2 -2
  27. package/src/gdskills/bundled/skills/review/code-style-review/SKILL.md +1 -1
  28. package/src/gdskills/bundled/skills/review/review-jev-rules/SKILL.md +267 -0
  29. package/src/gdskills/bundled/skills/review/review-orchestrator/SKILL.detail.md +26 -0
  30. package/src/gdskills/bundled/skills/review/review-orchestrator/SKILL.md +75 -247
  31. package/src/gdskills/bundled/skills/review/review-orchestrator/output-contract.schema.json +19 -0
  32. package/src/gdskills/bundled/skills/review/review-orchestrator/reviewer-finding.schema.json +10 -0
  33. package/src/gdskills/bundled/skills/review/review-orchestrator/reviewer-input.schema.json +5 -0
  34. package/src/gdskills/bundled/skills/review/review-orchestrator/templates/pr-comment-backend.md +50 -0
  35. package/src/gdskills/bundled/skills/review/review-orchestrator/templates/pr-comment-frontend.md +52 -0
  36. package/src/gdskills/bundled/skills/review/review-orchestrator/templates/review-report.md +143 -0
  37. package/src/gdskills/bundled/stacks/angular/agent-refs.json +4 -0
  38. package/src/gdskills/bundled/stacks/angular/governance/eval.json +1751 -0
  39. package/src/gdskills/bundled/stacks/angular/governance/scout.json +32 -0
  40. package/src/gdskills/bundled/stacks/angular/pack.json +55 -0
  41. package/src/gdskills/bundled/stacks/angular/rules/coding-style.mdc +82 -0
  42. package/src/gdskills/bundled/stacks/angular/rules/patterns.mdc +84 -0
  43. package/src/gdskills/bundled/stacks/angular/rules/security.mdc +70 -0
  44. package/src/gdskills/bundled/stacks/angular/rules/testing.mdc +73 -0
  45. package/src/gdskills/bundled/stacks/angular/skills/angular-build-fix/SKILL.md +127 -0
  46. package/src/gdskills/bundled/stacks/angular/skills/angular-build-fix/evals.json +72 -0
  47. package/src/gdskills/bundled/stacks/angular/skills/angular-code-review/SKILL.md +98 -0
  48. package/src/gdskills/bundled/stacks/angular/skills/angular-code-review/evals.json +73 -0
  49. package/src/gdskills/bundled/stacks/angular/skills/angular-implementation/SKILL.md +112 -0
  50. package/src/gdskills/bundled/stacks/angular/skills/angular-implementation/evals.json +74 -0
  51. package/src/gdskills/bundled/stacks/angular/skills/angular-testing/SKILL.md +102 -0
  52. package/src/gdskills/bundled/stacks/angular/skills/angular-testing/evals.json +71 -0
  53. package/src/gdskills/bundled/stacks/go/agent-refs.json +3 -0
  54. package/src/gdskills/bundled/stacks/go/governance/eval.json +1745 -0
  55. package/src/gdskills/bundled/stacks/go/governance/scout.json +31 -0
  56. package/src/gdskills/bundled/stacks/go/pack.json +41 -0
  57. package/src/gdskills/bundled/stacks/go/rules/coding-style.mdc +85 -0
  58. package/src/gdskills/bundled/stacks/go/rules/patterns.mdc +65 -0
  59. package/src/gdskills/bundled/stacks/go/rules/security.mdc +73 -0
  60. package/src/gdskills/bundled/stacks/go/rules/testing.mdc +68 -0
  61. package/src/gdskills/bundled/stacks/go/skills/go-build-fix/SKILL.md +138 -0
  62. package/src/gdskills/bundled/stacks/go/skills/go-build-fix/evals.json +75 -0
  63. package/src/gdskills/bundled/stacks/go/skills/go-code-review/SKILL.md +121 -0
  64. package/src/gdskills/bundled/stacks/go/skills/go-code-review/evals.json +72 -0
  65. package/src/gdskills/bundled/stacks/go/skills/go-implementation/SKILL.md +122 -0
  66. package/src/gdskills/bundled/stacks/go/skills/go-implementation/evals.json +76 -0
  67. package/src/gdskills/bundled/stacks/go/skills/go-testing/SKILL.md +126 -0
  68. package/src/gdskills/bundled/stacks/go/skills/go-testing/evals.json +73 -0
  69. package/src/gdskills/bundled/stacks/mobx/agent-refs.json +4 -0
  70. package/src/gdskills/bundled/stacks/mobx/governance/eval.json +904 -0
  71. package/src/gdskills/bundled/stacks/mobx/governance/scout.json +18 -0
  72. package/src/gdskills/bundled/stacks/mobx/pack.json +28 -0
  73. package/src/gdskills/bundled/stacks/mobx/rules/coding-style.mdc +91 -0
  74. package/src/gdskills/bundled/stacks/mobx/rules/patterns.mdc +122 -0
  75. package/src/gdskills/bundled/stacks/mobx/rules/security.mdc +56 -0
  76. package/src/gdskills/bundled/stacks/mobx/rules/testing.mdc +63 -0
  77. package/src/gdskills/bundled/stacks/mobx/skills/mobx-observable-testing/SKILL.md +124 -0
  78. package/src/gdskills/bundled/stacks/mobx/skills/mobx-observable-testing/evals.json +73 -0
  79. package/src/gdskills/bundled/stacks/mobx/skills/mobx-store-implementation/SKILL.md +149 -0
  80. package/src/gdskills/bundled/stacks/mobx/skills/mobx-store-implementation/evals.json +74 -0
  81. package/src/gdskills/bundled/stacks/nestjs/agent-refs.json +4 -0
  82. package/src/gdskills/bundled/stacks/nestjs/governance/eval.json +1308 -0
  83. package/src/gdskills/bundled/stacks/nestjs/governance/scout.json +34 -0
  84. package/src/gdskills/bundled/stacks/nestjs/pack.json +53 -0
  85. package/src/gdskills/bundled/stacks/nestjs/rules/coding-style.mdc +70 -0
  86. package/src/gdskills/bundled/stacks/nestjs/rules/patterns.mdc +83 -0
  87. package/src/gdskills/bundled/stacks/nestjs/rules/security.mdc +73 -0
  88. package/src/gdskills/bundled/stacks/nestjs/rules/testing.mdc +69 -0
  89. package/src/gdskills/bundled/stacks/nestjs/skills/nestjs-build-fix/SKILL.md +157 -0
  90. package/src/gdskills/bundled/stacks/nestjs/skills/nestjs-build-fix/evals.json +70 -0
  91. package/src/gdskills/bundled/stacks/nestjs/skills/nestjs-implementation/SKILL.md +129 -0
  92. package/src/gdskills/bundled/stacks/nestjs/skills/nestjs-implementation/evals.json +71 -0
  93. package/src/gdskills/bundled/stacks/nestjs/skills/nestjs-testing/SKILL.md +143 -0
  94. package/src/gdskills/bundled/stacks/nestjs/skills/nestjs-testing/evals.json +69 -0
  95. package/src/gdskills/bundled/stacks/nextjs-nuxt/agent-refs.json +4 -0
  96. package/src/gdskills/bundled/stacks/nextjs-nuxt/governance/eval.json +2413 -0
  97. package/src/gdskills/bundled/stacks/nextjs-nuxt/governance/scout.json +42 -0
  98. package/src/gdskills/bundled/stacks/nextjs-nuxt/pack.json +42 -0
  99. package/src/gdskills/bundled/stacks/nextjs-nuxt/rules/coding-style.mdc +69 -0
  100. package/src/gdskills/bundled/stacks/nextjs-nuxt/rules/patterns.mdc +88 -0
  101. package/src/gdskills/bundled/stacks/nextjs-nuxt/rules/security.mdc +72 -0
  102. package/src/gdskills/bundled/stacks/nextjs-nuxt/rules/testing.mdc +64 -0
  103. package/src/gdskills/bundled/stacks/nextjs-nuxt/skills/nextjs-nuxt-build-fix/SKILL.md +147 -0
  104. package/src/gdskills/bundled/stacks/nextjs-nuxt/skills/nextjs-nuxt-build-fix/evals.json +75 -0
  105. package/src/gdskills/bundled/stacks/nextjs-nuxt/skills/nextjs-nuxt-code-review/SKILL.md +118 -0
  106. package/src/gdskills/bundled/stacks/nextjs-nuxt/skills/nextjs-nuxt-code-review/evals.json +76 -0
  107. package/src/gdskills/bundled/stacks/nextjs-nuxt/skills/nextjs-nuxt-implementation/SKILL.md +135 -0
  108. package/src/gdskills/bundled/stacks/nextjs-nuxt/skills/nextjs-nuxt-implementation/evals.json +78 -0
  109. package/src/gdskills/bundled/stacks/nextjs-nuxt/skills/nextjs-nuxt-testing/SKILL.md +116 -0
  110. package/src/gdskills/bundled/stacks/nextjs-nuxt/skills/nextjs-nuxt-testing/evals.json +75 -0
  111. package/src/gdskills/bundled/stacks/nextjs-nuxt/skills/nextjs-nuxt-upgrade-migration/SKILL.md +134 -0
  112. package/src/gdskills/bundled/stacks/nextjs-nuxt/skills/nextjs-nuxt-upgrade-migration/evals.json +76 -0
  113. package/src/gdskills/bundled/stacks/python/agent-refs.json +3 -0
  114. package/src/gdskills/bundled/stacks/python/governance/eval.json +1758 -0
  115. package/src/gdskills/bundled/stacks/python/governance/scout.json +34 -0
  116. package/src/gdskills/bundled/stacks/python/pack.json +41 -0
  117. package/src/gdskills/bundled/stacks/python/rules/coding-style.mdc +63 -0
  118. package/src/gdskills/bundled/stacks/python/rules/patterns.mdc +88 -0
  119. package/src/gdskills/bundled/stacks/python/rules/security.mdc +84 -0
  120. package/src/gdskills/bundled/stacks/python/rules/testing.mdc +77 -0
  121. package/src/gdskills/bundled/stacks/python/skills/python-build-fix/SKILL.md +144 -0
  122. package/src/gdskills/bundled/stacks/python/skills/python-build-fix/evals.json +74 -0
  123. package/src/gdskills/bundled/stacks/python/skills/python-code-review/SKILL.md +155 -0
  124. package/src/gdskills/bundled/stacks/python/skills/python-code-review/evals.json +72 -0
  125. package/src/gdskills/bundled/stacks/python/skills/python-implementation/SKILL.md +143 -0
  126. package/src/gdskills/bundled/stacks/python/skills/python-implementation/evals.json +78 -0
  127. package/src/gdskills/bundled/stacks/python/skills/python-testing/SKILL.md +132 -0
  128. package/src/gdskills/bundled/stacks/python/skills/python-testing/evals.json +73 -0
  129. package/src/gdskills/bundled/stacks/react/agent-refs.json +4 -0
  130. package/src/gdskills/bundled/stacks/react/governance/eval.json +2188 -0
  131. package/src/gdskills/bundled/stacks/react/governance/scout.json +40 -0
  132. package/src/gdskills/bundled/stacks/react/pack.json +42 -0
  133. package/src/gdskills/bundled/stacks/react/rules/coding-style.mdc +58 -0
  134. package/src/gdskills/bundled/stacks/react/rules/patterns.mdc +79 -0
  135. package/src/gdskills/bundled/stacks/react/rules/security.mdc +70 -0
  136. package/src/gdskills/bundled/stacks/react/rules/testing.mdc +60 -0
  137. package/src/gdskills/bundled/stacks/react/skills/react-build-fix/SKILL.md +139 -0
  138. package/src/gdskills/bundled/stacks/react/skills/react-build-fix/evals.json +72 -0
  139. package/src/gdskills/bundled/stacks/react/skills/react-code-review/SKILL.md +148 -0
  140. package/src/gdskills/bundled/stacks/react/skills/react-code-review/evals.json +74 -0
  141. package/src/gdskills/bundled/stacks/react/skills/react-implementation/SKILL.md +140 -0
  142. package/src/gdskills/bundled/stacks/react/skills/react-implementation/evals.json +74 -0
  143. package/src/gdskills/bundled/stacks/react/skills/react-testing/SKILL.md +142 -0
  144. package/src/gdskills/bundled/stacks/react/skills/react-testing/evals.json +83 -0
  145. package/src/gdskills/bundled/stacks/react/skills/react-upgrade-migration/SKILL.md +155 -0
  146. package/src/gdskills/bundled/stacks/react/skills/react-upgrade-migration/evals.json +74 -0
  147. package/src/gdskills/bundled/stacks/ts-js-node/agent-refs.json +4 -0
  148. package/src/gdskills/bundled/stacks/ts-js-node/governance/eval.json +2155 -0
  149. package/src/gdskills/bundled/stacks/ts-js-node/governance/scout.json +40 -0
  150. package/src/gdskills/bundled/stacks/ts-js-node/pack.json +41 -0
  151. package/src/gdskills/bundled/stacks/ts-js-node/rules/coding-style.mdc +73 -0
  152. package/src/gdskills/bundled/stacks/ts-js-node/rules/patterns.mdc +61 -0
  153. package/src/gdskills/bundled/stacks/ts-js-node/rules/security.mdc +71 -0
  154. package/src/gdskills/bundled/stacks/ts-js-node/rules/testing.mdc +63 -0
  155. package/src/gdskills/bundled/stacks/ts-js-node/skills/nodejs-build-fix/SKILL.md +137 -0
  156. package/src/gdskills/bundled/stacks/ts-js-node/skills/nodejs-build-fix/evals.json +73 -0
  157. package/src/gdskills/bundled/stacks/ts-js-node/skills/nodejs-code-review/SKILL.md +124 -0
  158. package/src/gdskills/bundled/stacks/ts-js-node/skills/nodejs-code-review/evals.json +74 -0
  159. package/src/gdskills/bundled/stacks/ts-js-node/skills/nodejs-esm-migration/SKILL.md +152 -0
  160. package/src/gdskills/bundled/stacks/ts-js-node/skills/nodejs-esm-migration/evals.json +71 -0
  161. package/src/gdskills/bundled/stacks/ts-js-node/skills/nodejs-implementation/SKILL.md +127 -0
  162. package/src/gdskills/bundled/stacks/ts-js-node/skills/nodejs-implementation/evals.json +72 -0
  163. package/src/gdskills/bundled/stacks/ts-js-node/skills/nodejs-testing/SKILL.md +134 -0
  164. package/src/gdskills/bundled/stacks/ts-js-node/skills/nodejs-testing/evals.json +70 -0
  165. package/src/gdskills/bundled/stacks/vue/agent-refs.json +4 -0
  166. package/src/gdskills/bundled/stacks/vue/governance/eval.json +2215 -0
  167. package/src/gdskills/bundled/stacks/vue/governance/scout.json +42 -0
  168. package/src/gdskills/bundled/stacks/vue/pack.json +42 -0
  169. package/src/gdskills/bundled/stacks/vue/rules/coding-style.mdc +73 -0
  170. package/src/gdskills/bundled/stacks/vue/rules/patterns.mdc +84 -0
  171. package/src/gdskills/bundled/stacks/vue/rules/security.mdc +60 -0
  172. package/src/gdskills/bundled/stacks/vue/rules/testing.mdc +69 -0
  173. package/src/gdskills/bundled/stacks/vue/skills/vue-build-fix/SKILL.md +137 -0
  174. package/src/gdskills/bundled/stacks/vue/skills/vue-build-fix/evals.json +72 -0
  175. package/src/gdskills/bundled/stacks/vue/skills/vue-code-review/SKILL.md +120 -0
  176. package/src/gdskills/bundled/stacks/vue/skills/vue-code-review/evals.json +71 -0
  177. package/src/gdskills/bundled/stacks/vue/skills/vue-implementation/SKILL.md +122 -0
  178. package/src/gdskills/bundled/stacks/vue/skills/vue-implementation/evals.json +72 -0
  179. package/src/gdskills/bundled/stacks/vue/skills/vue-testing/SKILL.md +115 -0
  180. package/src/gdskills/bundled/stacks/vue/skills/vue-testing/evals.json +72 -0
  181. package/src/gdskills/bundled/stacks/vue/skills/vue2-to-vue3-migration/SKILL.md +135 -0
  182. package/src/gdskills/bundled/stacks/vue/skills/vue2-to-vue3-migration/evals.json +71 -0
@@ -0,0 +1,1308 @@
1
+ {
2
+ "schemaVersion": "1.0.0",
3
+ "reports": [
4
+ {
5
+ "schemaVersion": "1.0.0",
6
+ "skillId": "nestjs/nestjs-implementation",
7
+ "strictness": "high",
8
+ "trials": 10,
9
+ "triggerAccuracy": {
10
+ "truePositive": 6,
11
+ "falsePositive": 0,
12
+ "positives": 7,
13
+ "negatives": 6
14
+ },
15
+ "evidence": "authored",
16
+ "scenarios": [
17
+ {
18
+ "id": "trigger-positive-1",
19
+ "kind": "trigger-positive",
20
+ "prompt": "We're adding an invoices feature to our NestJS API -- I need the module scaffolding: a controller, a service, and the provider wired up.",
21
+ "strictness": "high",
22
+ "trials": 1,
23
+ "passes": 1,
24
+ "passRate": 1,
25
+ "passAtK": 1,
26
+ "grader": "trigger-rank-fork-family",
27
+ "status": "ran",
28
+ "deterministic": true
29
+ },
30
+ {
31
+ "id": "trigger-positive-2",
32
+ "kind": "trigger-positive",
33
+ "prompt": "I need to wire OrdersService into the DI container for this new module",
34
+ "strictness": "high",
35
+ "trials": 1,
36
+ "passes": 1,
37
+ "passRate": 1,
38
+ "passAtK": 1,
39
+ "grader": "trigger-rank-fork-family",
40
+ "status": "ran",
41
+ "deterministic": true
42
+ },
43
+ {
44
+ "id": "trigger-positive-3",
45
+ "kind": "trigger-positive",
46
+ "prompt": "Implement a NestJS guard that checks the JWT and only allows admins through",
47
+ "strictness": "high",
48
+ "trials": 1,
49
+ "passes": 1,
50
+ "passRate": 1,
51
+ "passAtK": 1,
52
+ "grader": "trigger-rank-fork-family",
53
+ "status": "ran",
54
+ "deterministic": true
55
+ },
56
+ {
57
+ "id": "trigger-positive-4",
58
+ "kind": "trigger-positive",
59
+ "prompt": "Every response from our NestJS app should get its duration logged automatically -- I need an interceptor wired in globally rather than per-controller.",
60
+ "strictness": "high",
61
+ "trials": 1,
62
+ "passes": 1,
63
+ "passRate": 1,
64
+ "passAtK": 1,
65
+ "grader": "trigger-rank-fork-family",
66
+ "status": "ran",
67
+ "deterministic": true
68
+ },
69
+ {
70
+ "id": "trigger-positive-5",
71
+ "kind": "trigger-positive",
72
+ "prompt": "Right now if anything throws in our NestJS app, the client gets the raw stack trace back in the response -- I want every uncaught error across the whole app to come back as a clean, generic error instead.",
73
+ "strictness": "high",
74
+ "trials": 1,
75
+ "passes": 0,
76
+ "passRate": 0,
77
+ "passAtK": 0,
78
+ "grader": "trigger-rank-fork-family",
79
+ "status": "ran",
80
+ "deterministic": true
81
+ },
82
+ {
83
+ "id": "trigger-positive-6",
84
+ "kind": "trigger-positive",
85
+ "prompt": "A NestJS provider I'm writing reads something off the incoming request -- should that make it request-scoped, or is the default singleton still fine?",
86
+ "strictness": "high",
87
+ "trials": 1,
88
+ "passes": 1,
89
+ "passRate": 1,
90
+ "passAtK": 1,
91
+ "grader": "trigger-rank-fork-family",
92
+ "status": "ran",
93
+ "deterministic": true
94
+ },
95
+ {
96
+ "id": "trigger-positive-7",
97
+ "kind": "trigger-positive",
98
+ "prompt": "Move this business logic out of the controller and into a proper service method",
99
+ "strictness": "high",
100
+ "trials": 1,
101
+ "passes": 1,
102
+ "passRate": 1,
103
+ "passAtK": 1,
104
+ "grader": "trigger-rank-fork-family",
105
+ "status": "ran",
106
+ "deterministic": true
107
+ },
108
+ {
109
+ "id": "trigger-negative-1",
110
+ "kind": "trigger-negative",
111
+ "prompt": "Review this NestJS PR for missing DTO validation and N+1 queries in the repository layer",
112
+ "strictness": "high",
113
+ "trials": 1,
114
+ "passes": 1,
115
+ "passRate": 1,
116
+ "passAtK": 1,
117
+ "grader": "trigger-rank-fork-family",
118
+ "status": "ran",
119
+ "deterministic": true
120
+ },
121
+ {
122
+ "id": "trigger-negative-2",
123
+ "kind": "trigger-negative",
124
+ "prompt": "Fix this NestJS build error: Nest can't resolve dependencies of UsersService",
125
+ "strictness": "high",
126
+ "trials": 1,
127
+ "passes": 1,
128
+ "passRate": 1,
129
+ "passAtK": 1,
130
+ "grader": "trigger-rank-fork-family",
131
+ "status": "ran",
132
+ "deterministic": true
133
+ },
134
+ {
135
+ "id": "trigger-negative-3",
136
+ "kind": "trigger-negative",
137
+ "prompt": "Write @nestjs/testing unit tests for this NestJS service with a mocked repository",
138
+ "strictness": "high",
139
+ "trials": 1,
140
+ "passes": 1,
141
+ "passRate": 1,
142
+ "passAtK": 1,
143
+ "grader": "trigger-rank-fork-family",
144
+ "status": "ran",
145
+ "deterministic": true
146
+ },
147
+ {
148
+ "id": "trigger-negative-4",
149
+ "kind": "trigger-negative",
150
+ "prompt": "Add class-validator decorators to this DTO for the new signup endpoint",
151
+ "strictness": "high",
152
+ "trials": 1,
153
+ "passes": 1,
154
+ "passRate": 1,
155
+ "passAtK": 1,
156
+ "grader": "trigger-rank-fork-family",
157
+ "status": "ran",
158
+ "deterministic": true
159
+ },
160
+ {
161
+ "id": "trigger-negative-5",
162
+ "kind": "trigger-negative",
163
+ "prompt": "Implement a React component that displays the user's profile card",
164
+ "strictness": "high",
165
+ "trials": 1,
166
+ "passes": 1,
167
+ "passRate": 1,
168
+ "passAtK": 1,
169
+ "grader": "trigger-rank-fork-family",
170
+ "status": "ran",
171
+ "deterministic": true
172
+ },
173
+ {
174
+ "id": "trigger-negative-6",
175
+ "kind": "trigger-negative",
176
+ "prompt": "Fix this tsc module resolution error in a plain Node.js script with no framework",
177
+ "strictness": "high",
178
+ "trials": 1,
179
+ "passes": 1,
180
+ "passRate": 1,
181
+ "passAtK": 1,
182
+ "grader": "trigger-rank-fork-family",
183
+ "status": "ran",
184
+ "deterministic": true
185
+ },
186
+ {
187
+ "id": "global-guard-with-public-escape-hatch",
188
+ "kind": "behavior",
189
+ "prompt": "I want to protect most routes in my NestJS app with a JWT auth guard, but let a few endpoints stay public. What's the right way to set this up?",
190
+ "strictness": "high",
191
+ "trials": 10,
192
+ "passes": 10,
193
+ "passRate": 1,
194
+ "passAtK": 1,
195
+ "grader": "judge",
196
+ "status": "ran",
197
+ "trialRecords": [
198
+ {
199
+ "output": "Set up one global guard, and opt individual routes out of it with a custom `@Public()` decorator. Don't hand-decorate the protected controllers, and don't leave the public ones undecorated either.\n\n## Why this shape\n\nTwo failure modes to avoid:\n\n- **Per-controller `@UseGuards(JwtAuthGuard)` on every protected controller.** Works today, but the next controller someone adds is unprotected by default — you have to remember to guard it, and forgetting fails *open*. That's the wrong direction for an auth boundary.\n- **Leaving public endpoints bare** while protecting others. Then nothing in the code marks which endpoints are intentionally public vs. accidentally unguarded. A reader can't tell the difference.\n\nThe global-guard + explicit-opt-out shape inverts the default: every route is protected unless it says otherwise in the code, and the exceptions are visible at the route itself.\n\n## 1. The decorator\n\n```ts\n// src/auth/public.decorator.ts\nimport { SetMetadata } from '@nestjs/common';\n\nexport const IS_PUBLIC_KEY = 'isPublic';\nexport const Public = () => SetMetadata(IS_PUBLIC_KEY, true);\n```\n\n## 2. The guard reads it via `Reflector`\n\n```ts\n// src/auth/jwt-auth.guard.ts\nimport {\n CanActivate,\n ExecutionContext,\n Injectable,\n UnauthorizedException,\n} from '@nestjs/common';\nimport { Reflector } from '@nestjs/core';\nimport { JwtService } from '@nestjs/jwt';\nimport { Request } from 'express';\nimport { IS_PUBLIC_KEY } from './public.decorator';\n\n@Injectable()\nexport class JwtAuthGuard implements CanActivate {\n constructor(\n private readonly reflector: Reflector,\n private readonly jwtService: JwtService,\n ) {}\n\n async canActivate(context: ExecutionContext): Promise<boolean> {\n // getAllAndOverride so a @Public() on the method beats a guard\n // applied at the controller class level.\n const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [\n context.getHandler(),\n context.getClass(),\n ]);\n if (isPublic) return true;\n\n const request = context.switchToHttp().getRequest<Request>();\n const token = this.extractToken(request);\n if (!token) throw new UnauthorizedException();\n\n try {\n request['user'] = await this.jwtService.verifyAsync(token);\n } catch {\n throw new UnauthorizedException();\n }\n return true;\n }\n\n private extractToken(request: Request): string | undefined {\n const [type, token] = request.headers.authorization?.split(' ') ?? [];\n return type === 'Bearer' ? token : undefined;\n }\n}\n```\n\n## 3. Register it globally as an `APP_GUARD` provider\n\n```ts\n// src/auth/auth.module.ts\nimport { Module } from '@nestjs/common';\nimport { APP_GUARD } from '@nestjs/core';\nimport { JwtModule } from '@nestjs/jwt';\nimport { JwtAuthGuard } from './jwt-auth.guard';\n\n@Module({\n imports: [\n JwtModule.register({\n secret: process.env.JWT_SECRET,\n signOptions: { expiresIn: '1h' },\n }),\n ],\n providers: [\n {\n provide: APP_GUARD,\n useClass: JwtAuthGuard,\n },\n ],\n})\nexport class AuthModule {}\n```\n\nUse the `APP_GUARD` token, **not** `app.useGlobalGuards(new JwtAuthGuard())` in `main.ts`. Both apply the guard globally, but the `useGlobalGuards()` form instantiates the guard yourself, outside Nest's DI graph — it can't inject `Reflector`, `JwtService`, or a `UsersService`. The `APP_GUARD` provider form is resolved by the container, so constructor injection just works. That's the whole reason this pattern is viable.\n\nAlso make sure `AuthModule` is imported somewhere reachable from `AppModule` (importing it in `AppModule` is fine); a module's `APP_*` providers only take effect if the module is part of the application graph.\n\n## 4. Opt out at the route\n\n```ts\n// src/auth/auth.controller.ts\nimport { Body, Controller, Post } from '@nestjs/common';\nimport { Public } from './public.decorator';\n\n@Controller('auth')\nexport class AuthController {\n @Public()\n @Post('login')\n login(@Body() dto: LoginDto) {\n return this.authService.login(dto);\n }\n\n @Public()\n @Post('register')\n register(@Body() dto: RegisterDto) {\n return this.authService.register(dto);\n }\n}\n\n// src/health/health.controller.ts\n@Controller('health')\nexport class HealthController {\n @Public()\n @Get()\n check() {\n return { status: 'ok' };\n }\n}\n```\n\nEverything else in the app is now protected without any decoration.\n\n## A few things to get right\n\n- **Use `getAllAndOverride`, not `get`.** If you ever apply `@UseGuards` or a class-level `@Public()`, `getAllAndOverride(..., [handler, class])` gives method-level metadata precedence. `reflector.get(IS_PUBLIC_KEY, context.getHandler())` only looks at the handler and misses class-level placement.\n- **Health/metrics probes and the login/register routes** are the usual public set. Health checks in particular often run before a token exists — marking them `@Public()` is expected, not a smell.\n- **Don't make the guard request-scoped.** It doesn't need per-request state (it reads the request off the `ExecutionContext`), so leave it Singleton. Making it `Scope.REQUEST` would propagate request scope up through everything that injects it.\n- **This is authentication, not authorization.** The guard establishes *who* the caller is. Per-route role/permission checks are a second guard (a `RolesGuard` reading `@Roles(...)` metadata, also registered as `APP_GUARD` and also honoring `@Public()`), layered after this one.\n- **Fail closed on your own additions.** If you ever add a route and forget to think about auth, it's protected — that's the point. The only way to expose something is to type `@Public()`, which is a deliberate, reviewable act.\n\n## Verify\n\n- The app boots with no `UnknownDependenciesException` — that error here almost always means you used `useGlobalGuards()` instead of `APP_GUARD`, or `Reflector`/`JwtService` isn't resolvable from the module.\n- Hit a protected route with no `Authorization` header → 401.\n- Hit a `@Public()` route with no header → 200.\n- Hit a protected route with a valid Bearer token → 200, and confirm the decoded user landed on `request.user`.\n- Grep the codebase for `@Public()` and confirm every hit is a route you intend to be public — that list should be short and boring.",
200
+ "outputSha256": "eab71aed5d3e8d5d86828a9a4332387d0d0f5964e318e068706584dd280ffc47",
201
+ "promptSha256": "c8b48a2ffe48719bd225a3960bd8799719b519e6138cdccd4922f1255a83dee8",
202
+ "deterministic": [],
203
+ "judge": {
204
+ "verdict": "pass",
205
+ "reason": "Criterion 1: Section 3 registers the guard via `{ provide: APP_GUARD, useClass: JwtAuthGuard }` in AuthModule providers, and explicitly warns against `app.useGlobalGuards()`. Criterion 2: Section 1 defines `Public = () => SetMetadata(IS_PUBLIC_KEY, true)`, and the guard reads it via `this.reflector.getAllAndOverride(IS_PUBLIC_KEY, ...)`. No fail criterion: it warns against per-controller @UseGuards as the whole mechanism."
206
+ },
207
+ "passed": true
208
+ },
209
+ {
210
+ "output": "Set up a **global guard** registered through the `APP_GUARD` token, and let public endpoints **opt out** with a custom `@Public()` decorator. That way every route is protected by default, and a new controller someone adds later is protected automatically rather than silently open. Here's the shape:\n\n**1. The `@Public()` decorator** — a metadata marker with no logic of its own:\n\n```ts\n// src/auth/decorators/public.decorator.ts\nimport { SetMetadata } from '@nestjs/common';\n\nexport const IS_PUBLIC_KEY = 'isPublic';\nexport const Public = () => SetMetadata(IS_PUBLIC_KEY, true);\n```\n\n**2. The guard** — injects `Reflector` and the JWT service, checks the metadata first, then verifies the token:\n\n```ts\n// src/auth/guards/jwt-auth.guard.ts\nimport {\n CanActivate,\n ExecutionContext,\n Injectable,\n UnauthorizedException,\n} from '@nestjs/common';\nimport { Reflector } from '@nestjs/core';\nimport { JwtService } from '@nestjs/jwt';\nimport { IS_PUBLIC_KEY } from '../decorators/public.decorator';\nimport type { Request } from 'express';\n\n@Injectable()\nexport class JwtAuthGuard implements CanActivate {\n constructor(\n private readonly reflector: Reflector,\n private readonly jwtService: JwtService,\n ) {}\n\n async canActivate(context: ExecutionContext): Promise<boolean> {\n const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [\n context.getHandler(),\n context.getClass(),\n ]);\n if (isPublic) {\n return true;\n }\n\n const request = context.switchToHttp().getRequest<Request>();\n const token = this.extractBearerToken(request);\n if (!token) {\n throw new UnauthorizedException();\n }\n\n try {\n request['user'] = await this.jwtService.verifyAsync(token);\n return true;\n } catch {\n throw new UnauthorizedException();\n }\n }\n\n private extractBearerToken(request: Request): string | undefined {\n const [type, token] = request.headers.authorization?.split(' ') ?? [];\n return type === 'Bearer' ? token : undefined;\n }\n}\n```\n\n**3. Register it globally via `APP_GUARD`** — this is the key part. Note it goes in a module's `providers` array with the `APP_GUARD` token, *not* `app.useGlobalGuards()` in `main.ts`. The `APP_*` form keeps the guard inside Nest's DI graph, so it can actually inject `Reflector` and `JwtService`. The `app.useGlobalGuards(new JwtAuthGuard())` form cannot, and would force you to wire dependencies by hand.\n\n```ts\n// src/auth/auth.module.ts\nimport { Module } from '@nestjs/common';\nimport { APP_GUARD } from '@nestjs/core';\nimport { JwtModule } from '@nestjs/jwt';\nimport { JwtAuthGuard } from './guards/jwt-auth.guard';\n\n@Module({\n imports: [JwtModule.register({ secret: process.env.JWT_SECRET })],\n providers: [\n {\n provide: APP_GUARD,\n useClass: JwtAuthGuard,\n },\n ],\n})\nexport class AuthModule {}\n```\n\n**4. Mark the exceptions explicitly** on the deliberately public routes:\n\n```ts\n@Controller('health')\nexport class HealthController {\n @Public()\n @Get()\n check() {\n return { status: 'ok' };\n }\n}\n```\n\n```ts\n@Controller('auth')\nexport class AuthController {\n @Public()\n @Post('login')\n login(@Body() dto: LoginDto) {\n /* ... */\n }\n}\n```\n\nA few things worth flagging:\n\n- Flag exceptions in the open, not by omission. The failure mode of the opposite approach — decorating each protected controller with `@UseGuards(JwtAuthGuard)` — is that a new controller added later is public by default and nobody notices. The global-guard-plus-`@Public()` setup fails closed instead.\n- `getAllAndOverride` reads handler-level metadata first and falls back to class-level, so `@Public()` works on either a single method or a whole controller (useful for something like an entirely public webhooks controller).\n- If you have other global guards (roles, etc.), they run in registration order. If a role guard needs the authenticated user, make sure the JWT guard runs before it, or have the role guard also check `@Public()` and no-op.\n- I'd suggest combining this with a global `APP_PIPE` carrying `ValidationPipe` so your login DTO is validated, and keeping the token-verification and `request.user` assignment in the guard rather than spreading it across controllers.\n\nSince I can't see your project here, match the file layout and existing auth setup in your nearest sibling feature module before dropping this in — and after wiring it, boot the app and confirm there's no `UnknownDependenciesException` or circular-dependency warning at startup, not just a clean `tsc`.",
211
+ "outputSha256": "b5753159e2892d029c5cc40b938f4aa40db8d813da70ede86332889acd23763b",
212
+ "promptSha256": "c8b48a2ffe48719bd225a3960bd8799719b519e6138cdccd4922f1255a83dee8",
213
+ "deterministic": [],
214
+ "judge": {
215
+ "verdict": "pass",
216
+ "reason": "Criterion 1: answer registers guard via APP_GUARD token in AuthModule providers array (provide: APP_GUARD, useClass: JwtAuthGuard) and explicitly contrasts it with app.useGlobalGuards(). Criterion 2: defines @Public() with SetMetadata(IS_PUBLIC_KEY, true) and guard reads it via reflector.getAllAndOverride. Fail criterion 1 not met: @UseGuards only mentioned as the anti-pattern to avoid."
217
+ },
218
+ "passed": true
219
+ },
220
+ {
221
+ "output": "Register the guard once, globally, through Nest's DI graph, and make the public endpoints explicit opt-outs. Concretely:\n\n**1. Write the guard so it can inject what it needs.**\n\n```ts\n// auth/jwt-auth.guard.ts\nimport { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';\nimport { Reflector } from '@nestjs/core';\nimport { IS_PUBLIC_KEY } from './public.decorator';\n\n@Injectable()\nexport class JwtAuthGuard implements CanActivate {\n constructor(\n private readonly reflector: Reflector,\n private readonly jwtService: JwtService,\n ) {}\n\n canActivate(context: ExecutionContext): boolean {\n const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [\n context.getHandler(),\n context.getClass(),\n ]);\n if (isPublic) return true;\n\n const req = context.switchToHttp().getRequest();\n const token = extractBearerToken(req); // your own extraction\n if (!token) throw new UnauthorizedException();\n\n try {\n req.user = this.jwtService.verify(token);\n return true;\n } catch {\n throw new UnauthorizedException();\n }\n }\n}\n```\n\nBecause it takes `Reflector` and `JwtService` as constructor deps, it has to live inside Nest's DI graph — that's the reason for the setup below.\n\n**2. Register it globally with the `APP_GUARD` token, not `useGlobalGuards`.**\n\n```ts\n// app.module.ts (or a dedicated AuthModule)\nimport { Module } from '@nestjs/common';\nimport { APP_GUARD } from '@nestjs/core';\nimport { JwtModule } from '@nestjs/jwt';\nimport { JwtAuthGuard } from './auth/jwt-auth.guard';\n\n@Module({\n imports: [JwtModule.register({ /* secret/keys */ })],\n providers: [\n JwtAuthGuard,\n { provide: APP_GUARD, useClass: JwtAuthGuard },\n ],\n})\nexport class AppModule {}\n```\n\nDo **not** use `app.useGlobalGuards(new JwtAuthGuard())` in `main.ts` here. That form instantiates the guard outside Nest's container, so it can't inject `Reflector` or `JwtService` and you'd have to hand-wire them. The `APP_GUARD` provider keeps it in the container.\n\n**3. Make the public route an explicit opt-out via a metadata decorator.**\n\n```ts\n// auth/public.decorator.ts\nimport { SetMetadata } from '@nestjs/common';\nexport const IS_PUBLIC_KEY = 'isPublic';\nexport const Public = () => SetMetadata(IS_PUBLIC_KEY, true);\n```\n\nThen mark the exceptions and let everything else default to protected:\n\n```ts\n@Controller('auth')\nexport class AuthController {\n @Public()\n @Post('login')\n login(@Body() dto: LoginDto) { /* ... */ }\n}\n\n// everything on this controller is protected without any decorator\n@Controller('orders')\nexport class OrdersController { /* ... */ }\n```\n\nThe guard reads the flag with `getAllAndOverride` against both the handler and the class, so `@Public()` works at either level.\n\n**Why this shape rather than the alternative:**\n\n- **Fails safe.** A global guard protects every route by default — including controllers someone adds next month. A `@UseGuards(JwtAuthGuard)` copied onto each controller does the opposite: any new controller without it is silently unauthenticated, and nothing surfaces that until it's exploited.\n- **Keeps one source of truth.** The guard logic, token extraction, and the public/private decision live in one place instead of being restated per controller.\n- **Safe to supersede.** If you later need a route to be public *only* for a specific method, `@Public()` on that method is a visible, greppable exception rather than a missing decorator.\n\nA couple of things to check before calling it done: confirm the app boots with no `UnknownDependenciesException` (this fails at startup if `JwtModule`/`Reflector` aren't resolvable in the guard's module scope), and make sure the `@Public()` endpoints are genuinely the ones you intend — an accidental `@Public()` on a class-wide decorator opens up the whole controller. Also note the ordering point: if you already have other global guards or interceptors, they run in registration order, so an auth guard that depends on something another guard sets should be registered after it.",
222
+ "outputSha256": "babaf73fe392c76e5d928e795c7c076c9efeb0fc4bce439772913ae9e1703d73",
223
+ "promptSha256": "c8b48a2ffe48719bd225a3960bd8799719b519e6138cdccd4922f1255a83dee8",
224
+ "deterministic": [],
225
+ "judge": {
226
+ "verdict": "pass",
227
+ "reason": "Criterion 1: answer registers guard via APP_GUARD token in providers array ({ provide: APP_GUARD, useClass: JwtAuthGuard }) and explicitly warns against app.useGlobalGuards. Criterion 2: defines Public() decorator with SetMetadata(IS_PUBLIC_KEY, true) and guard reads it via reflector.getAllAndOverride. No fail criterion: @UseGuards only mentioned as anti-pattern to avoid."
228
+ },
229
+ "passed": true
230
+ },
231
+ {
232
+ "output": "# Protecting most routes with a JWT guard while keeping some public\n\nThe right shape is a **global guard with an explicit opt-out decorator**, not decorating every controller individually. Here's the pattern:\n\n## 1. The `@Public()` decorator\n\n```ts\n// src/common/decorators/public.decorator.ts\nimport { SetMetadata } from '@nestjs/common';\n\nexport const IS_PUBLIC_KEY = 'isPublic';\nexport const Public = () => SetMetadata(IS_PUBLIC_KEY, true);\n```\n\n## 2. The guard reads it via `Reflector`\n\n```ts\n// src/common/guards/jwt-auth.guard.ts\nimport { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';\nimport { Reflector } from '@nestjs/core';\nimport { IS_PUBLIC_KEY } from '../decorators/public.decorator';\n\n@Injectable()\nexport class JwtAuthGuard implements CanActivate {\n constructor(private readonly reflector: Reflector) {}\n\n canActivate(context: ExecutionContext): boolean {\n const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [\n context.getHandler(),\n context.getClass(),\n ]);\n if (isPublic) return true;\n // ...verify JWT off the request...\n }\n}\n```\n\n`getAllAndOverride` with both `getHandler()` and `getClass()` lets `@Public()` sit on either a single route or a whole controller.\n\n## 3. Register it globally as `APP_GUARD`, not `useGlobalGuards()`\n\n```ts\n// src/app.module.ts\nimport { Module } from '@nestjs/common';\nimport { APP_GUARD } from '@nestjs/core';\nimport { JwtAuthGuard } from './common/guards/jwt-auth.guard';\n\n@Module({\n providers: [\n { provide: APP_GUARD, useClass: JwtAuthGuard },\n ],\n})\nexport class AppModule {}\n```\n\nUse the `APP_GUARD` token rather than `app.useGlobalGuards(new JwtAuthGuard())` in `main.ts`, because the token form keeps the guard inside Nest's DI graph — so it can inject `Reflector`, a `JwtService`, a `UsersService`, etc. The instance form you pass to `useGlobalGuards()` cannot inject anything.\n\n## 4. Mark the exceptions\n\n```ts\n@Controller('auth')\nexport class AuthController {\n @Public()\n @Post('login')\n login(@Body() dto: LoginDto) { /* ... */ }\n}\n```\n\n## Why this direction (fail-safe), not per-controller `@UseGuards`\n\nThe whole point is which way the default points. With a global guard, **every new controller anyone adds is protected by default** and an endpoint only becomes public if someone deliberately writes `@Public()` on it. The inverse — decorating each protected controller with `@UseGuards(JwtAuthGuard)` and leaving the rest bare — means a teammate adding a controller next sprint silently ships an unprotected route. Global-guard-with-opt-out fails closed; the other fails open.\n\n## Two caveats worth knowing up front\n\n- **Register the guard once** in a module's `providers` array (e.g. `AppModule`, or a dedicated `AuthModule`) — not copy-pasted into every feature controller. That's the \"cross-cutting concern registered once\" rule.\n- **Keep the guard Singleton.** Don't make it request-scoped \"just in case\" — a REQUEST-scoped `APP_GUARD` re-instantiates its injection subtree (and anything that depends on it) on every request. Read per-request data off `context.switchToHttp().getRequest()` inside `canActivate` instead; that doesn't require changing scope.\n\n## Verify before calling it done\n\n- `nestjs` build + `tsc --noEmit` exit 0.\n- The app boots with no `UnknownDependenciesException` or circular-dependency warning — a guard that injects something from a module you forgot to `import` fails exactly here, not at type-check time.\n- Hit a protected route with no token → 401; hit a `@Public()` route with no token → passes the guard.",
233
+ "outputSha256": "2d968bb733ce7f2410e552f947264930b86b850b3154a82657fb73cdc6710eca",
234
+ "promptSha256": "c8b48a2ffe48719bd225a3960bd8799719b519e6138cdccd4922f1255a83dee8",
235
+ "deterministic": [],
236
+ "judge": {
237
+ "verdict": "pass",
238
+ "reason": "Criterion 1: answer registers guard via APP_GUARD token in AppModule providers array ({ provide: APP_GUARD, useClass: JwtAuthGuard }) and explicitly contrasts with app.useGlobalGuards(). Criterion 2: defines @Public() with SetMetadata(IS_PUBLIC_KEY, true) and reads it in guard via Reflector.getAllAndOverride. No fail criterion: it warns against per-controller @UseGuards as the whole mechanism."
239
+ },
240
+ "passed": true
241
+ },
242
+ {
243
+ "output": "Set the guard up **globally** and opt routes out explicitly, rather than decorating the protected controllers one by one.\n\n**1. Register the guard globally via an `APP_*` token, not `useGlobalGuards()`**\n\nIn a module's `providers` array (commonly `AppModule` or an `AuthModule`):\n\n```ts\nproviders: [\n { provide: APP_GUARD, useClass: JwtAuthGuard },\n]\n```\n\nUse the `APP_GUARD` token form, not `app.useGlobalGuards(new JwtAuthGuard())` on the bootstrapped instance. The token form keeps the guard inside Nest's DI graph, so it can inject collaborators like `Reflector` or a `UsersService` — which you need for the opt-out mechanism below. The instance form cannot.\n\n**2. Define a `@Public()` decorator backed by `SetMetadata`**\n\n```ts\nexport const IS_PUBLIC_KEY = 'isPublic';\nexport const Public = () => SetMetadata(IS_PUBLIC_KEY, true);\n```\n\n**3. Have the guard read the metadata via `Reflector` and short-circuit**\n\n```ts\n@Injectable()\nexport class JwtAuthGuard extends AuthGuard('jwt') {\n constructor(private reflector: Reflector) {\n super();\n }\n\n canActivate(context: ExecutionContext) {\n const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [\n context.getHandler(),\n context.getClass(),\n ]);\n if (isPublic) return true;\n return super.canActivate(context);\n }\n}\n```\n\n`getAllAndOverride` with both handler and class lets `@Public()` sit on a single method or on the whole controller.\n\n**4. Mark the exceptions**\n\n```ts\n@Public()\n@Post('login')\nlogin(@Body() dto: LoginDto) { ... }\n```\n\nThis is the part that matters most: it **fails safe**. A guard you copy onto each controller fails open — the next controller someone adds is silently unprotected until they remember the decorator. A global guard is on by default, and going public is a deliberate, greppable annotation.\n\nA couple of things to watch:\n\n- Ordering matters if you add more global guards. Guards registered through `APP_GUARD` run in the order their providers appear, so put your auth guard before any guard that assumes an authenticated `request.user`.\n- If you also have a global `APP_PIPE`/`APP_INTERCEPTOR` doing auth-adjacent work (e.g. an interceptor that reads `request.user`), it runs after guards, so a `@Public()` route still needs to tolerate a missing user.\n- Keep the `@Public()` set small and reviewable. Login, register, health-check, and maybe a webhook are the usual legitimate members; anything else is worth questioning in review.\n\nFinally, confirm at boot that the guard actually resolved — no `UnknownDependenciesException` from the `Reflector` injection and no circular-dependency warning — and that an un-annotated new route returns 401 without you touching it. That's the real test that the default-deny posture is working.",
244
+ "outputSha256": "d1c56092b130fef834123b1816a5653c8ee064af00f23bffb6e2156512aece31",
245
+ "promptSha256": "c8b48a2ffe48719bd225a3960bd8799719b519e6138cdccd4922f1255a83dee8",
246
+ "deterministic": [],
247
+ "judge": {
248
+ "verdict": "pass",
249
+ "reason": "Criterion 1: answer shows `providers: [{ provide: APP_GUARD, useClass: JwtAuthGuard }]` and explicitly rejects `app.useGlobalGuards(new JwtAuthGuard())`. Criterion 2: defines `Public = () => SetMetadata(IS_PUBLIC_KEY, true)` and reads it in the guard via `this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, ...)`. No fail criterion: it argues against per-controller @UseGuards."
250
+ },
251
+ "passed": true
252
+ },
253
+ {
254
+ "output": "Register it globally via `APP_GUARD` and opt out per-route with a metadata decorator the guard reads via `Reflector`. That way new controllers are protected by default instead of requiring every author to remember to add a decorator.\n\n**1. Decorator to mark public routes**\n\n```ts\n// src/auth/public.decorator.ts\nimport { SetMetadata } from '@nestjs/common';\n\nexport const IS_PUBLIC_KEY = 'isPublic';\nexport const Public = () => SetMetadata(IS_PUBLIC_KEY, true);\n```\n\n**2. The guard**\n\n```ts\n// src/auth/jwt-auth.guard.ts\nimport {\n CanActivate,\n ExecutionContext,\n Injectable,\n UnauthorizedException,\n} from '@nestjs/common';\nimport { Reflector } from '@nestjs/core';\nimport { JwtService } from '@nestjs/jwt';\nimport { IS_PUBLIC_KEY } from './public.decorator';\n\n@Injectable()\nexport class JwtAuthGuard implements CanActivate {\n constructor(\n private readonly reflector: Reflector,\n private readonly jwtService: JwtService,\n ) {}\n\n async canActivate(context: ExecutionContext): Promise<boolean> {\n const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [\n context.getHandler(),\n context.getClass(),\n ]);\n if (isPublic) return true;\n\n const request = context.switchToHttp().getRequest();\n const authHeader = request.headers['authorization'];\n if (!authHeader?.startsWith('Bearer ')) {\n throw new UnauthorizedException('Missing bearer token');\n }\n\n const token = authHeader.slice('Bearer '.length);\n try {\n request.user = await this.jwtService.verifyAsync(token);\n } catch {\n throw new UnauthorizedException('Invalid or expired token');\n }\n return true;\n }\n}\n```\n\n`getAllAndOverride` checks the handler first, then falls back to the class, so `@Public()` can go on a single route or a whole controller.\n\n**3. Register it globally**\n\nIn whichever module owns your auth wiring:\n\n```ts\nimport { Module } from '@nestjs/common';\nimport { APP_GUARD } from '@nestjs/core';\n\n@Module({\n providers: [\n JwtAuthGuard,\n { provide: APP_GUARD, useClass: JwtAuthGuard },\n ],\n})\nexport class AuthModule {}\n```\n\nUse the `APP_GUARD` token, not `app.useGlobalGuards(new JwtAuthGuard())` in `main.ts`. The `APP_GUARD` form keeps the guard inside Nest's DI graph, so it can inject `Reflector`, `JwtService`, and any of your own providers. The `useGlobalGuards` call constructs an instance outside DI and cannot inject anything, which is why the `Reflector`-based opt-out would not work.\n\n**4. Mark the public endpoints**\n\n```ts\n@Post('login')\n@Public()\nlogin(@Body() dto: LoginDto) { /* ... */ }\n```\n\n**A few things to get right**\n\n- `@Public()` is a simple metadata flag, and any request that lacks it is challenged. That is the fail-safe direction: forgetting the decorator protects a route you meant to expose, which is a bug you notice immediately in testing. The inverse (decorating each controller and forgetting one) silently leaves a route open in production.\n- Keep the guard free of business logic. It verifies the token and attaches `request.user`; authorization decisions about *what* a valid user may do belong in a separate guard or in the service layer. `rules/patterns.mdc` covers the guard-vs-service split.\n- If you need a public route to still get `request.user` when a token happens to be present, do not early-return on the `@Public()` check. Instead, attempt verification, attach the user if it succeeds, and only skip the *throw* when the route is public.\n- Do not inject a request-scoped provider into a singleton guard. If your `JwtService` config genuinely needs per-request state, understand that the guard becomes request-scoped too and re-instantiates on every request.\n\nPer `nestjs-dto.mdc`, the login endpoint that mints the token should itself validate its body with a typed DTO, and the token-issuing service should return an explicit type. The guard only consumes the token; it should not be reaching into a repository.",
255
+ "outputSha256": "b0b08135acfbb133641e7c147567612c2eda1afc4ffbb47fe19aefe4e43eff35",
256
+ "promptSha256": "c8b48a2ffe48719bd225a3960bd8799719b519e6138cdccd4922f1255a83dee8",
257
+ "deterministic": [],
258
+ "judge": {
259
+ "verdict": "pass",
260
+ "reason": "Answer registers guard via APP_GUARD token in providers array (step 3: '{ provide: APP_GUARD, useClass: JwtAuthGuard }') and explicitly rejects app.useGlobalGuards(). It creates @Public() with SetMetadata (IS_PUBLIC_KEY) and reads it in the guard via Reflector.getAllAndOverride. No @UseGuards-everywhere recommendation."
261
+ },
262
+ "passed": true
263
+ },
264
+ {
265
+ "output": "# Protecting most routes with a JWT guard, with opt-out public endpoints\n\nThe short answer: register the JWT guard **globally via an `APP_GUARD` provider**, and expose a **`@Public()` decorator backed by `SetMetadata`** that the guard reads with `Reflector` to skip auth on the few open routes. That fails safe — any new controller somebody adds later is protected by default unless it explicitly opts out.\n\nHere's the shape, step by step.\n\n## 1. The `@Public()` decorator\n\n```ts\n// src/auth/decorators/public.decorator.ts\nimport { SetMetadata } from '@nestjs/common';\n\nexport const IS_PUBLIC_KEY = 'isPublic';\nexport const Public = () => SetMetadata(IS_PUBLIC_KEY, true);\n```\n\n## 2. The guard that honors it\n\n```ts\n// src/auth/guards/jwt-auth.guard.ts\nimport {\n CanActivate,\n ExecutionContext,\n Injectable,\n UnauthorizedException,\n} from '@nestjs/common';\nimport { Reflector } from '@nestjs/core';\nimport { JwtService } from '@nestjs/jwt';\nimport { IS_PUBLIC_KEY } from '../decorators/public.decorator';\nimport type { Request } from 'express';\n\n@Injectable()\nexport class JwtAuthGuard implements CanActivate {\n constructor(\n private readonly reflector: Reflector,\n private readonly jwtService: JwtService,\n ) {}\n\n async canActivate(context: ExecutionContext): Promise<boolean> {\n const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [\n context.getHandler(),\n context.getClass(),\n ]);\n if (isPublic) return true;\n\n const req = context.switchToHttp().getRequest<Request>();\n const [type, token] = req.headers.authorization?.split(' ') ?? [];\n if (type !== 'Bearer' || !token) {\n throw new UnauthorizedException();\n }\n try {\n // attach the verified payload for downstream handlers\n (req as any).user = await this.jwtService.verifyAsync(token);\n return true;\n } catch {\n throw new UnauthorizedException();\n }\n }\n}\n```\n\nTwo details worth calling out:\n\n- `getAllAndOverride` checks the **handler first, then the class**, so `@Public()` works on a single route *or* on an entire controller.\n- The guard injects `Reflector` and `JwtService`. That's only possible because it's a real provider inside Nest's DI graph — which is exactly why you must register it via the `APP_GUARD` token and **not** via `app.useGlobalGuards(new JwtAuthGuard())` in `main.ts`. The `useGlobalGuards` form instantiates the class outside DI, so those constructor parameters can't be resolved.\n\n## 3. Register it globally\n\nIn your auth module (or a dedicated `core`/`security` module):\n\n```ts\n// src/auth/auth.module.ts\nimport { Module } from '@nestjs/common';\nimport { APP_GUARD } from '@nestjs/core';\nimport { JwtModule } from '@nestjs/jwt';\nimport { JwtAuthGuard } from './guards/jwt-auth.guard';\n\n@Module({\n imports: [JwtModule.register({ /* secret / signOptions */ })],\n providers: [\n {\n provide: APP_GUARD,\n useClass: JwtAuthGuard,\n },\n ],\n})\nexport class AuthModule {}\n```\n\nNow every route in the app is protected by default.\n\n## 4. Mark the exceptions\n\n```ts\n@Controller('auth')\nexport class AuthController {\n @Public()\n @Post('login')\n login(@Body() dto: LoginDto) { /* ... */ }\n\n @Public()\n @Post('register')\n register(@Body() dto: RegisterDto) { /* ... */ }\n\n @Get('me') // no @Public -> guarded\n me(@Req() req: Request) { /* ... */ }\n}\n```\n\nYou can also put `@Public()` at the class level to open up a whole controller (e.g. a health-check controller), then nothing under it needs the guard.\n\n## Why this and not the alternatives\n\n- **`@UseGuards(JwtAuthGuard)` on each controller.** Any controller added later silently starts unprotected. You'd have to remember to decorate every one, and a forgotten decorator is an unauthenticated endpoint — the failure mode is a security hole, not a startup error. With a global `APP_GUARD` + `@Public()`, the failure mode of a forgotten decorator is a *protected* route, which is safe.\n- **`app.useGlobalGuards(new JwtAuthGuard())` in `main.ts`.** Works, but the instance is created outside the DI container, so the guard can't inject `Reflector`, `JwtService`, `UsersService`, etc. No `@Public()` support, no easy `overrideProvider` in tests. Avoid it for anything nontrivial.\n- **Per-route `@Public()` metadata read with `reflector.get` instead of `getAllAndOverride`.** `get` only checks one context; `getAllAndOverride` handles both class- and handler-level metadata, which is what you want for controller-wide public sections.\n\n## While you're here\n\n- Keep the controller thin: `login` above should call one `AuthService.login(dto)` method that does the credential check and token signing — no repository calls in the controller.\n- Validate `LoginDto`/`RegisterDto` with class-validator decorators (the existing `nestjs-dto` convention in your project) so a malformed body is rejected by the global `ValidationPipe` before it reaches your service.\n- Throw typed `UnauthorizedException` (or a domain error the guard/filter translates) rather than a bare `Error`, so the response status is a real 401.\n- If you have several global concerns (auth guard, roles guard, logging interceptor), they are **order-sensitive**: guards run before interceptors, and among guards the registration order is the execution order. The `APP_GUARD`/`APP_INTERCEPTOR`/`APP_PIPE`/`APP_FILTER` tokens let you keep them all as injectable providers rather than mixing them into `main.ts`.\n\n## Verify before calling it done\n\n- `nest build` (or the project's build script) and `tsc --noEmit` both exit 0.\n- The app **boots** with no `UnknownDependenciesException` or circular-dependency warning — the guard's `Reflector`/`JwtService` dependencies must resolve. A clean `tsc` does not prove this; only a successful boot does.\n- Hit one guarded route with no token → 401, with a valid token → 200; hit a `@Public()` route with no token → 200. That's the whole contract, so test all three.\n- Confirm every endpoint you intended to stay open actually carries `@Public()`, and that nothing else accidentally does.",
266
+ "outputSha256": "495ca7c426c18a2267333b2a631f81a7eb79835d96d1b349876c525fbb630d6f",
267
+ "promptSha256": "c8b48a2ffe48719bd225a3960bd8799719b519e6138cdccd4922f1255a83dee8",
268
+ "deterministic": [],
269
+ "judge": {
270
+ "verdict": "pass",
271
+ "reason": "Answer registers guard via APP_GUARD provider token in AuthModule providers array (step 3, `provide: APP_GUARD, useClass: JwtAuthGuard`) and explicitly rejects app.useGlobalGuards(). It creates @Public() with SetMetadata (IS_PUBLIC_KEY) and reads it in the guard via Reflector.getAllAndOverride. It warns against per-controller @UseGuards as the whole mechanism, not recommending it."
272
+ },
273
+ "passed": true
274
+ },
275
+ {
276
+ "output": "Set it up as a **global guard with an explicit opt-out decorator**, not by decorating every controller individually.\n\n## 1. Mark the public routes with a custom decorator\n\nCreate a small decorator backed by `SetMetadata`:\n\n```ts\n// src/auth/public.decorator.ts\nimport { SetMetadata } from '@nestjs/common';\n\nexport const IS_PUBLIC_KEY = 'isPublic';\nexport const Public = () => SetMetadata(IS_PUBLIC_KEY, true);\n```\n\n## 2. Write the guard so it checks the metadata\n\n```ts\n// src/auth/jwt-auth.guard.ts\nimport { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';\nimport { Reflector } from '@nestjs/core';\nimport { IS_PUBLIC_KEY } from './public.decorator';\n\n@Injectable()\nexport class JwtAuthGuard implements CanActivate {\n constructor(private readonly reflector: Reflector) {}\n\n canActivate(context: ExecutionContext): boolean {\n const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [\n context.getHandler(),\n context.getClass(),\n ]);\n if (isPublic) {\n return true;\n }\n // ...verify the JWT here (or delegate to a Passport/JWT strategy)\n }\n}\n```\n\nUsing `getAllAndOverride` lets you mark either a whole controller or a single method as public.\n\n## 3. Register it globally as an `APP_GUARD` provider\n\nIn your root (or auth) module:\n\n```ts\nimport { Module } from '@nestjs/common';\nimport { APP_GUARD } from '@nestjs/core';\n\n@Module({\n providers: [\n { provide: APP_GUARD, useClass: JwtAuthGuard },\n ],\n})\nexport class AppModule {}\n```\n\n## Why the `APP_GUARD` token and not `app.useGlobalGuards()`\n\nThe `APP_*` token form registers the guard **inside Nest's own DI graph**, so it can inject other providers — here, `Reflector`, and in a fuller setup a `JwtService`, `UsersService`, etc. `app.useGlobalGuards(new JwtAuthGuard())` on the bootstrapped instance bypasses DI and can't inject anything.\n\n## 4. Mark the exceptions\n\nAny endpoint that should stay open just gets the decorator — on the method or the whole controller:\n\n```ts\n@Public()\n@Post('login')\nlogin(@Body() dto: LoginDto) { /* ... */ }\n```\n\n## The key reason to do it this way\n\nThis **fails safe**. Every new controller anyone adds later is protected by default, and the only way to open one is a deliberate `@Public()` annotation that shows up in a diff. If instead you decorate controllers one by one with `@UseGuards(JwtAuthGuard)`, a newly added controller silently starts out unprotected — the exact failure mode you want to avoid.\n\n## Verification before calling it done\n\n- `nest build` and `tsc --noEmit` both exit 0.\n- The app boots with no `UnknownDependenciesException` — a common cause here is forgetting that `JwtAuthGuard` now needs `Reflector` (and whatever strategy service it depends on) available in the module that provides it.\n- Confirm both directions actually work: a request to a normal route without a token is rejected, and a request to a `@Public()` route goes through with no token. Don't assume the decorator wiring is correct just because it compiles.",
277
+ "outputSha256": "622c28882ea3dee3b12f9f68a36511c6d8025d6e2117613d3ebdb3b6386d7a1f",
278
+ "promptSha256": "c8b48a2ffe48719bd225a3960bd8799719b519e6138cdccd4922f1255a83dee8",
279
+ "deterministic": [],
280
+ "judge": {
281
+ "verdict": "pass",
282
+ "reason": "Criterion 1: answer registers guard via APP_GUARD token in providers array ({ provide: APP_GUARD, useClass: JwtAuthGuard }) and explicitly contrasts with app.useGlobalGuards(). Criterion 2: creates Public() decorator with SetMetadata(IS_PUBLIC_KEY, true) and reads it in guard via Reflector.getAllAndOverride. No fail criterion: it warns against per-controller @UseGuards, not recommending it."
283
+ },
284
+ "passed": true
285
+ },
286
+ {
287
+ "output": "Register the guard globally via the `APP_GUARD` provider token, have it check for an opt-out decorator using `Reflector`, and decorate the public endpoints with that decorator. Global-by-default with explicit opt-out fails safe: any controller someone adds later is protected automatically, instead of silently public because they forgot the decorator.\n\n**1. Mark public routes with a metadata decorator**\n\n```ts\n// src/auth/public.decorator.ts\nimport { SetMetadata } from '@nestjs/common';\n\nexport const IS_PUBLIC_KEY = 'isPublic';\nexport const Public = () => SetMetadata(IS_PUBLIC_KEY, true);\n```\n\n**2. Have the guard read that metadata**\n\n```ts\n// src/auth/jwt-auth.guard.ts\nimport {\n CanActivate,\n ExecutionContext,\n Injectable,\n UnauthorizedException,\n} from '@nestjs/common';\nimport { Reflector } from '@nestjs/core';\nimport { JwtService } from '@nestjs/jwt';\nimport { IS_PUBLIC_KEY } from './public.decorator';\n\n@Injectable()\nexport class JwtAuthGuard implements CanActivate {\n constructor(\n private readonly jwtService: JwtService,\n private readonly reflector: Reflector,\n ) {}\n\n async canActivate(context: ExecutionContext): Promise<boolean> {\n const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [\n context.getHandler(),\n context.getClass(),\n ]);\n if (isPublic) {\n return true;\n }\n\n const request = context.switchToHttp().getRequest();\n const header: string | undefined = request.headers['authorization'];\n const token = header?.startsWith('Bearer ') ? header.slice(7) : undefined;\n if (!token) {\n throw new UnauthorizedException();\n }\n\n try {\n request.user = await this.jwtService.verifyAsync(token);\n return true;\n } catch {\n throw new UnauthorizedException();\n }\n }\n}\n```\n\n`getAllAndOverride` checks the handler first, then the class, so a decorator on a single method wins over one on the controller.\n\n**3. Register it as an APP_GUARD, not `useGlobalGuards`**\n\n```ts\n// src/auth/auth.module.ts\nimport { Module } from '@nestjs/common';\nimport { APP_GUARD } from '@nestjs/core';\nimport { JwtModule } from '@nestjs/jwt';\nimport { JwtAuthGuard } from './jwt-auth.guard';\n\n@Module({\n imports: [JwtModule.register({ secret: process.env.JWT_SECRET })],\n providers: [\n {\n provide: APP_GUARD,\n useClass: JwtAuthGuard,\n },\n ],\n})\nexport class AuthModule {}\n```\n\nThe `APP_GUARD` token keeps the guard inside Nest's own DI graph, so it can inject `Reflector` and `JwtService` the way it does above. `app.useGlobalGuards(new JwtAuthGuard())` runs the instance you construct there, outside the container — so those constructor injections don't resolve and you end up hand-wiring dependencies.\n\n**4. Opt individual endpoints out**\n\n```ts\n// src/users/users.controller.ts\nimport { Controller, Get } from '@nestjs/common';\nimport { Public } from '../auth/public.decorator';\n\n@Controller('users')\nexport class UsersController {\n @Public()\n @Get('health')\n health() {\n return { status: 'ok' };\n }\n\n @Get('me')\n me() {\n // reaches here only with a valid token\n }\n}\n```\n\n**Two things worth calling out**\n\nOrdering: a global guard registered with `APP_GUARD` runs before controller-level `@UseGuards` but after middleware. If you later need a guard that must run before auth (say, a rate limiter keyed by IP rather than user), register that as a separate `APP_GUARD` too — Nest runs multiple global guards in the order their providers are registered.\n\nComposition with roles: don't fold role checks into the JWT guard. Keep `JwtAuthGuard` doing authentication only, then add a second `RolesGuard` registered globally after it, reading a `@Roles(...)` metadata key. That guard should return `true` early when the route is `@Public()` or carries no roles metadata, so the two guards compose instead of fighting each other.\n\nBefore calling this done: confirm the app boots with no `UnknownDependenciesException` from the guard's injections, and hit one protected and one `@Public()` route to verify the opt-out actually takes effect.",
288
+ "outputSha256": "8aef383f1d07502e234b5a35ab4fc0ecda07449f901ed3476758d655450416e5",
289
+ "promptSha256": "c8b48a2ffe48719bd225a3960bd8799719b519e6138cdccd4922f1255a83dee8",
290
+ "deterministic": [],
291
+ "judge": {
292
+ "verdict": "pass",
293
+ "reason": "Criterion 1: Step 3 registers guard via providers array with {provide: APP_GUARD, useClass: JwtAuthGuard}, explicitly contrasting app.useGlobalGuards(). Criterion 2: Step 1 defines Public() with SetMetadata(IS_PUBLIC_KEY,true); Step 2 guard reads it via reflector.getAllAndOverride(IS_PUBLIC_KEY,...) returning true. No fail criterion: @UseGuards not proposed as the mechanism."
294
+ },
295
+ "passed": true
296
+ },
297
+ {
298
+ "output": "# Global JWT guard with opt-out public routes\n\nThe right shape is a **global guard registered through the DI graph** plus a **`SetMetadata`-backed opt-out decorator** read via `Reflector`. That way every route is protected by default and adding a new controller can never accidentally leave it open — a future endpoint only becomes public if someone deliberately marks it.\n\n## 1. Mark public routes with a custom decorator\n\n```ts\n// src/auth/public.decorator.ts\nimport { SetMetadata } from '@nestjs/common';\n\nexport const IS_PUBLIC_KEY = 'isPublic';\nexport const Public = () => SetMetadata(IS_PUBLIC_KEY, true);\n```\n\n## 2. Read it in the guard\n\n```ts\n// src/auth/jwt-auth.guard.ts\nimport {\n CanActivate, ExecutionContext, Injectable, UnauthorizedException,\n} from '@nestjs/common';\nimport { Reflector } from '@nestjs/core';\nimport { JwtService } from '@nestjs/jwt';\nimport { IS_PUBLIC_KEY } from './public.decorator';\n\n@Injectable()\nexport class JwtAuthGuard implements CanActivate {\n constructor(\n private readonly reflector: Reflector,\n private readonly jwtService: JwtService,\n ) {}\n\n async canActivate(context: ExecutionContext): Promise<boolean> {\n const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [\n context.getHandler(),\n context.getClass(),\n ]);\n if (isPublic) return true;\n\n const req = context.switchToHttp().getRequest();\n const token = req.headers.authorization?.replace(/^Bearer\\s+/i, '');\n if (!token) throw new UnauthorizedException();\n\n try {\n req.user = await this.jwtService.verifyAsync(token);\n return true;\n } catch {\n throw new UnauthorizedException();\n }\n }\n}\n```\n\n`getAllAndOverride` checks the handler first, then the class, so `@Public()` can sit on a single method or on a whole controller.\n\n## 3. Register it globally as an `APP_GUARD`\n\n```ts\n// src/auth/auth.module.ts\nimport { Module } from '@nestjs/common';\nimport { APP_GUARD } from '@nestjs/core';\nimport { JwtModule } from '@nestjs/jwt';\nimport { JwtAuthGuard } from './jwt-auth.guard';\nimport { AuthController } from './auth.controller';\n\n@Module({\n imports: [JwtModule.register({ secret: process.env.JWT_SECRET })],\n controllers: [AuthController],\n providers: [\n { provide: APP_GUARD, useClass: JwtAuthGuard },\n ],\n})\nexport class AuthModule {}\n```\n\nThe `APP_GUARD` token form is the key detail: it registers the guard inside Nest's own DI graph, so the guard can inject `Reflector`, `JwtService`, a `UsersService`, etc. `app.useGlobalGuards(new JwtAuthGuard())` would **not** — that instance is constructed outside DI and cannot inject anything.\n\n## 4. Opt out on the endpoints that should stay open\n\n```ts\n@Controller('auth')\nexport class AuthController {\n @Public()\n @Post('login')\n login(@Body() dto: LoginDto) { /* ... */ }\n\n @Public()\n @Post('register')\n register(@Body() dto: RegisterDto) { /* ... */ }\n\n @Get('me') // protected by default, no decorator needed\n me(@Req() req) { return req.user; }\n}\n```\n\nYou can also mark a whole controller public with `@Public()` at the class level and re-protect individual methods if needed — the handler-level metadata wins.\n\n## Why this over the alternatives\n\n- **Per-controller `@UseGuards(JwtAuthGuard)`** means a new controller added six months from now is unprotected until someone remembers. A global guard fails *closed*.\n- **`app.useGlobalGuards(...)`** works for a guard with no dependencies, but as soon as the guard needs `Reflector` or your `JwtService` you're stuck — and most real auth guards need both.\n- **A middleware instead of a guard** runs before the route metadata is easily reachable and doesn't compose with `@Public()` cleanly; `Reflector` is designed for exactly this.\n\n## Verification before you call it done\n\n- App boots with no `UnknownDependenciesException` — the guard resolved `Reflector` and `JwtService` from DI.\n- A protected route returns 401 without a token and 200 with a valid one.\n- Each `@Public()` route returns its normal response **without** a token.\n- `tsc --noEmit` / `nest build` exit 0.\n- Grep the routes you intended to be public and confirm each one carries `@Public()` — don't rely on \"I think I marked it.\"",
299
+ "outputSha256": "dc415633979003b15ae410d44690fe1089987c46e8a1216c44fa87a227891796",
300
+ "promptSha256": "c8b48a2ffe48719bd225a3960bd8799719b519e6138cdccd4922f1255a83dee8",
301
+ "deterministic": [],
302
+ "judge": {
303
+ "verdict": "pass",
304
+ "reason": "Criterion 1: Section 3 registers the guard via providers: [{ provide: APP_GUARD, useClass: JwtAuthGuard }] and explicitly contrasts it with app.useGlobalGuards(). Criterion 2: Section 1 defines Public = () => SetMetadata(IS_PUBLIC_KEY, true), and Section 2 reads it via reflector.getAllAndOverride(IS_PUBLIC_KEY, ...). No fail criterion: @UseGuards is only warned against, not proposed as the mechanism."
305
+ },
306
+ "passed": true
307
+ }
308
+ ]
309
+ },
310
+ {
311
+ "id": "request-scoped-into-singleton",
312
+ "kind": "behavior",
313
+ "prompt": "I have a small provider that reads the current user off the request (it's REQUEST-scoped). I want to inject it directly into UsersService, which is a plain singleton used all over the app. Is that fine to do as-is?",
314
+ "strictness": "high",
315
+ "trials": 10,
316
+ "passes": 10,
317
+ "passRate": 1,
318
+ "passAtK": 1,
319
+ "grader": "judge",
320
+ "status": "ran",
321
+ "trialRecords": [
322
+ {
323
+ "output": "No — that's exactly the case this skill calls out as a red flag. Injecting a REQUEST-scoped provider into `UsersService` (a Singleton, used all over the app) will either:\n\n- silently promote `UsersService` itself to request scope, because Nest propagates scope up the injection graph — so every consumer of `UsersService` now gets a fresh instance per request, and anything depending on it may get promoted too; or\n- throw at resolution time if something in that chain can't legally be request-scoped.\n\nEither way, you lose the whole point of it being a singleton, and it's a transitive, hard-to-see change: any provider that injected `UsersService` is now affected.\n\nOptions, roughly in order of preference:\n\n1. **Don't inject the request-scoped thing into the singleton.** Pass the current user in as a method argument from the controller (or from a guard that has already resolved it), e.g. `usersService.findForUser(user, params)`. The service stays a plain singleton, and it's easy to test.\n\n2. **Resolve the request-scoped provider lazily, per call**, using `ModuleRef.get(CurrentUserProvider, { strict: false })` inside the singleton, at the point of use rather than in the constructor. This keeps `UsersService` a singleton, but it's a deliberate escape hatch — only reach for it if option 1 doesn't fit.\n\n3. **Make the endpoint's controller request-scoped instead**, so the request-scoped provider is only pulled into a per-request tree that doesn't touch the shared singleton. Usually more churn than it's worth.\n\nWhat you should not do is inject it into the constructor and hope. If you do nothing else, check what `UsersService` actually needs the user for: if it's only one or two methods, option 1 is almost always the cleanest fix and it keeps the service testable with a plain object argument instead of an HTTP request.",
324
+ "outputSha256": "cb539c8f6ce3f92d638cff186b145b6d4b6cb18cee00405bd6b3dd513abecab3",
325
+ "promptSha256": "185cd5c62d689e33518253bb500a99a1184db4be7e06b42f33af2b3516acc778",
326
+ "deterministic": [],
327
+ "judge": {
328
+ "verdict": "pass",
329
+ "reason": "Answer states injecting REQUEST-scoped provider into UsersService 'silently promote[s] UsersService itself to request scope, because Nest propagates scope up the injection graph — so every consumer of UsersService now gets a fresh instance per request' (criterion 1). It recommends against injecting into the singleton, proposing option 1: pass current user as method argument from controller, e.g. usersService.findForUser(user, params) (criterion 2)."
330
+ },
331
+ "passed": true
332
+ },
333
+ {
334
+ "output": "No, not as-is. That injection is exactly the case the rule above is flagging.\n\nNest's DI resolves an injection graph bottom-up, and scope propagates *up* the graph. When you inject a REQUEST-scoped provider into a Singleton provider, UsersService stops being a true singleton: Nest has to instantiate UsersService per request so it can hand it a fresh request-scoped dependency. Concretely that means:\n\n- Every consumer of UsersService inherits request scope too. Anything that injects UsersService (controllers, other services, a repository, a guard registered globally) gets pulled onto the request-scoped subtree as well. Scope contamination cascades further than you expect.\n- You lose the instantiation and caching benefits of the singleton. UsersService is rebuilt per request, along with anything downstream of it.\n- In some layouts you don't even get the silent-scope-promotion path — the provider resolution fails at startup with a scope mismatch rather than resolving. Either way the stated design intent (\"a plain singleton used all over the app\") is no longer true.\n\nSo the honest answer: it will probably *work*, and that's the trap. It works by quietly converting a shared singleton into a per-request provider and dragging its dependents with it, and you won't see it in a type-check or a build — only in startup resolution behavior once a controller that injects UsersService is exercised.\n\nBetter options, in rough order of preference:\n\n1. **Pass the user in as an argument.** Keep the request-scoped provider at the edge (controller or a request-scoped guard/interceptor) and have it call `usersService.someMethod(currentUser, ...)`. UsersService stays a pure singleton; the per-request value travels as a parameter. This is usually the right answer and is what \"keep the controller thin, delegate to one service call\" is compatible with — the controller already has the request context.\n\n2. **Inject `REQUEST` directly into the singleton at the leaf.** `@Inject(REQUEST) private readonly request: Request` in a singleton pulls it onto the request scope just the same, so this is only appropriate if UsersService genuinely needs to *be* request-scoped. It's not a workaround for option 1.\n\n3. **Make the scope explicit and accept it.** If UsersService really must read the current user throughout its logic, mark it `Scope.REQUEST` deliberately, accept the re-instantiation cost, and audit every consumer to make sure they're OK being request-scoped too. This is a design decision, not a quiet side effect.\n\nThe thing not to do is exactly what you asked about: inject the request-scoped provider into the singleton and let the scope promotion happen implicitly. If you go with option 1, the request-scoped provider should live where the request actually exists — a controller parameter, a guard, or an interceptor — and UsersService should receive the value, not fetch it.",
335
+ "outputSha256": "07a752f8841b7a2b71ebb14c0fda5c137fe9643c3c65d297138a6b4b71734e9e",
336
+ "promptSha256": "185cd5c62d689e33518253bb500a99a1184db4be7e06b42f33af2b3516acc778",
337
+ "deterministic": [],
338
+ "judge": {
339
+ "verdict": "pass",
340
+ "reason": "Answer states scope propagates up the graph: injecting REQUEST-scoped provider makes UsersService per-request and 'Every consumer of UsersService inherits request scope too.' It recommends against direct injection, proposing option 1: pass the user as an argument from the controller/guard/interceptor so UsersService stays a singleton."
341
+ },
342
+ "passed": true
343
+ },
344
+ {
345
+ "output": "No — not as-is. That's exactly the scope-propagation trap.\n\n`UsersService` is a plain Singleton. If you inject a REQUEST-scoped provider directly into it via its constructor, Nest propagates scope up the injection graph: `UsersService` effectively becomes REQUEST-scoped too. Every consumer that injects `UsersService` then also becomes request-scoped (or Nest throws at resolution time if it can't bubble the scope, e.g. it's injected into something that must stay a Singleton like a global guard or another Singleton that can't be re-scoped). Either way you lose the Singleton: `UsersService` gets re-instantiated per request, its `OnModuleInit`/`OnModuleDestroy` lifecycle hooks fire per request instead of once, and anything it holds in memory (caches, pooled connections, counters) now leaks or resets constantly. That defeats the entire reason `UsersService` was a Singleton in a first place.\n\nSo the short answer is: it compiles and might even appear to work in a small app, which is what makes it dangerous — the cost only shows up as per-request re-instantiation and broken lifecycle hooks.\n\nOptions, in rough order of preference:\n\n1. Don't inject the request-scoped provider into the singleton at all. Pass the current user (or whatever slice of it `UsersService` needs) in as an explicit method argument from the controller, which is where the request context legitimately lives. This is usually the right fix — it keeps `UsersService` pure, trivially testable, and Singleton. The controller reads the request-scoped provider and hands `user` to `usersService.something(user, ...)`.\n\n2. If the singleton only needs the request in a few methods and you can't thread it through, inject Nest's `REQUEST` token where you actually need it, or use `ModuleRef` to resolve the request-scoped provider lazily inside the method call rather than at construction time. This avoids making the singleton request-scoped, because the dependency isn't held as a constructor field.\n\n3. Inject `Reflector`/context rather than the user, if what you're really after is request metadata.\n\n4. Only if `UsersService` genuinely needs per-request state in a way that justifies it, accept the re-scope deliberately — but then you've decided `UsersService` is request-scoped, and every consumer inherits that, so it's a global decision, not a local one.\n\nAlso worth checking: if you go with option 1, `git status` after the change should show the scope of edits staying inside the controller and the service methods — if you find yourself touching many consumers, that's the propagation already leaking outward and a sign to back off and use approach 1.\n\nOne more thing to verify after whatever you pick: boot the app and confirm no `UnknownDependenciesException` or circular-dependency warning, and that a Singleton-only check (e.g. injecting `UsersService` into a global `APP_GUARD` or a `forRoot`-registered provider) doesn't throw — that's the fastest way to catch accidental scope propagation.",
346
+ "outputSha256": "deab23e8bbe89a72090fa47d88f8253c8e75be5658e136e8570f2f52a78ef40f",
347
+ "promptSha256": "185cd5c62d689e33518253bb500a99a1184db4be7e06b42f33af2b3516acc778",
348
+ "deterministic": [],
349
+ "judge": {
350
+ "verdict": "pass",
351
+ "reason": "Answer states Nest propagates scope up the injection graph, making UsersService and its consumers request-scoped/re-instantiated per request (\"Every consumer that injects UsersService then also becomes request-scoped\"). It recommends against injecting directly, proposing explicit method argument from controller (option 1) and isolating via REQUEST token/ModuleRef (option 2)."
352
+ },
353
+ "passed": true
354
+ },
355
+ {
356
+ "output": "No — injecting a REQUEST-scoped provider into a Singleton `UsersService` is exactly the case the rules call out. It is not fine as-is, for a concrete reason: Nest propagates scope **up** the injection graph. The moment `UsersService` depends on a REQUEST-scoped provider, `UsersService` itself becomes request-scoped. Every provider that injects `UsersService` gets pulled into that, and the whole subtree is re-instantiated per request. You either get that silent perf/behavior change or a resolution-time error, depending on how the graph lines up — and either way the \"plain singleton used all over the app\" assumption is now false. Someone reading `UsersService` later has no hint that it's now per-request.\n\nThe typical fix is **don't inject the request into the service; pass the user in as an argument.** Keep the REQUEST-scoped provider (or a `@CurrentUser()` param decorator that reads off the request) at the controller edge, and have the controller call `usersService.doThing(user, dto)`. `UsersService` stays a Singleton, stays trivially unit-testable by passing a plain user object, and no scope propagation happens. This is also consistent with keeping the controller thin — the controller's job is to get the caller's identity off the request and hand it to one service call.\n\nIf you genuinely can't move the user out to the call boundary, the alternatives are worse and should be deliberate:\n\n- Make `UsersService` explicitly `Scope.REQUEST` and accept per-request instantiation everywhere it's injected — usually not worth it for a service \"used all over the app.\"\n- Inject the `REQUEST` token / `REQUEST`-scoped provider only into a thin REQUEST-scoped wrapper service that the controller uses, leaving the Singleton `UsersService` untouched underneath.\n\nBefore shipping, confirm the change actually works at runtime, not just in `tsc`: boot the app (or the e2e bootstrap test) and check for `UnknownDependenciesException` or a circular-dependency warning, since scope propagation failures often only surface at resolution time. And note this is a \"why is this wired this way\" decision worth stating in the change — a silent singleton-to-request-scope promotion is the kind of thing that confuses the next reader.\n\nSo: no, don't inject it directly into the Singleton. Pass the user down from the controller edge instead.",
357
+ "outputSha256": "850d7c986c8823863b4b8d54f9bcd56501314d9181a11802dbd7af2ea43f293e",
358
+ "promptSha256": "185cd5c62d689e33518253bb500a99a1184db4be7e06b42f33af2b3516acc778",
359
+ "deterministic": [],
360
+ "judge": {
361
+ "verdict": "pass",
362
+ "reason": "Answer states Nest propagates scope up the injection graph, making UsersService and every provider injecting it request-scoped and re-instantiated per request ('the whole subtree is re-instantiated per request'). It recommends against direct injection, proposing passing the user as an argument from the controller edge ('usersService.doThing(user, dto)') or isolating into a thin REQUEST-scoped wrapper service. No fail criterion holds."
363
+ },
364
+ "passed": true
365
+ },
366
+ {
367
+ "output": "No — that's exactly the case the skill's rules call out, and it will bite you in one of two ways.\n\nInjecting a `REQUEST`-scoped provider into `UsersService` (a Singleton) doesn't leave `UsersService` unchanged. Nest resolves scope **up the injection graph**: the moment a Singleton depends on a Request-scoped provider, Nest has to re-instantiate `UsersService` — and everything that injects `UsersService` — per request. So the \"plain singleton used all over the app\" quietly stops being a singleton. Every consumer of `UsersService` inherits the cost: one instance tree built per request, more GC pressure, and lifecycle behavior you didn't sign up for. In some dependency shapes it can also surface as a resolution-time error or a circular-ish boot failure rather than silent scope propagation, but either way the intent behind a Singleton provider is defeated.\n\nSo: not fine as-is.\n\nWhat to do instead, depending on what the provider is actually for:\n\n1. **If it's just reading the user off the request cheaply** (e.g. an `AsyncLocalStorage`-backed current-user holder, or you only need `req.user` inside a specific handler), don't inject it into `UsersService` at all. Read it where the request actually exists — the controller, or a guard/interceptor — and pass the resolved user id/value down to the service as an explicit argument. That keeps `UsersService` a true Singleton and makes it trivially unit-testable with no HTTP stack.\n\n2. **If `UsersService` genuinely needs per-request identity for many methods**, that's a signal the per-request bit should be a parameter, not a hidden dependency. Make the method signatures take the caller/actor explicitly (e.g. `findVisibleTo(actor: User, id: string)`). This is the usual fix and keeps the DI graph flat.\n\n3. **If you truly need request-scoped behavior in a service**, then own it: mark that service (and accept that its consumers) as request-scoped deliberately, or use `durable: true` on any custom request-scoped provider so you at least avoid the harder failure modes — but understand you're still paying per-request instantiation across the subtree. Reach for this only when per-request state is a real requirement, not a convenience.\n\nBefore changing anything, check the sibling feature modules for how they handle \"current user.\" Most codebases settle on option 1 or 2 (a `@CurrentUser()` param decorator plus an explicit argument into the service). Match whatever the existing modules do rather than introducing a different pattern in one place.",
368
+ "outputSha256": "2373e30af950a291f0e266a790bccc6cfbf0248a5bf74021600da93b8f3cfcd5",
369
+ "promptSha256": "185cd5c62d689e33518253bb500a99a1184db4be7e06b42f33af2b3516acc778",
370
+ "deterministic": [],
371
+ "judge": {
372
+ "verdict": "pass",
373
+ "reason": "Answer states Nest resolves scope up the injection graph, so injecting the REQUEST-scoped provider makes UsersService and everything injecting it re-instantiated per request (\"quietly stops being a singleton... Every consumer inherits the cost\"). It recommends against direct injection, proposing passing the resolved user as an explicit argument from controller/guard (option 1) or making it a method parameter (option 2)."
374
+ },
375
+ "passed": true
376
+ },
377
+ {
378
+ "output": "No, not as-is. This is exactly the failure mode the \"NEVER inject a REQUEST-scoped provider into a Singleton\" rule covers.\n\nWhat actually happens: Nest builds the injection graph at startup and propagates scope *upward*. The moment `UsersService` (default singleton) has a constructor dependency on a `Scope.REQUEST` provider, `UsersService` is no longer a singleton in practice — Nest silently promotes it to request-scoped, so a fresh `UsersService` instance is constructed per request. Depending on the Nest version that mismatch can instead surface as a resolution-time error, but either way the singleton you intended to use \"all over the app\" isn't one anymore.\n\nThe cost is not just the one class. Every provider that injects `UsersService` inherits the bubbling too, so a service you expected to be long-lived and shared now gets re-instantiated per request, along with whatever it holds (in-memory caches, connection state, `OnModuleInit`-initialized resources that now reinitialize constantly). If `UsersService` is used in a hot path or wrapped in any `OnModuleDestroy` lifecycle, this is where you'll first notice something is wrong.\n\nWhat to do instead, in rough order of preference:\n\n1. **Don't inject the current-user provider at all — pass the value down.** If the caller (controller or a request-scoped entry point) already knows the current user, have it pass that value as an explicit argument into the singleton's method. The singleton stays a singleton, the dependency is visible at the call site, and it's trivially testable. This is the right default for most \"read the current user\" cases.\n\n2. **Inject `REQUEST` directly where you actually need it.** If the user only needs to be read inside a specific operation, that operation's owner (typically the controller, or a thin request-scoped provider) can `@Inject(REQUEST)` and extract the user itself, then call the singleton. The request-scoped edge stays as close to the request as possible and never touches the shared service.\n\n3. **Use `ModuleRef.get(REQUEST, { strict: false })`** to pull the request object out of the DI container lazily inside the singleton method, avoiding a constructor dependency entirely. This keeps the singleton a singleton, though it's more magic than option 1 and harder to follow — reach for it only when passing the value down genuinely isn't practical (e.g. deep call chains you don't control).\n\n4. **If the singleton truly needs per-request state throughout its lifetime**, then making it request-scoped on purpose — and accepting the per-request instantiation cost knowingly — is legitimate. But that's a deliberate decision, not something to arrive at by injecting one request-scoped dependency into it.\n\nThe thing to be careful about: this often \"works\" in a dev smoke test. The app boots, requests succeed, tests pass, and the scope promotion is invisible until someone inspects `app.get(UsersService)` identity across requests or profiles memory under load. So don't take booting cleanly as evidence that the injection is sound.\n\nVerify by checking what scope `UsersService` actually resolves to — compare the instance returned by `app.get(UsersService)` across two requests, or inspect the resolved scope through the container. If the two references differ, it's been promoted and you've got per-request construction you didn't intend.\n\nMy recommendation: go with option 1 unless you have a concrete reason you can state out loud for why the value can't be passed down. It keeps `UsersService` a real singleton and makes the data flow obvious to the next reader.",
379
+ "outputSha256": "0998f2c34f29f687342cb0f98080e58073f23c16c9acaba27468e6c20ee32e31",
380
+ "promptSha256": "185cd5c62d689e33518253bb500a99a1184db4be7e06b42f33af2b3516acc778",
381
+ "deterministic": [],
382
+ "judge": {
383
+ "verdict": "pass",
384
+ "reason": "Answer states Nest propagates scope upward: injecting Scope.REQUEST provider makes UsersService request-scoped, re-instantiated per request, and every provider injecting UsersService inherits the bubbling. Recommends against direct injection, proposing option 1 (pass value as explicit argument from controller) and option 2 (inject REQUEST in a thin request-scoped provider/controller). Both pass criteria concretely met."
385
+ },
386
+ "passed": true
387
+ },
388
+ {
389
+ "output": "No — that will not work as-is, or at least not in the way you want.\n\nNest propagates scope up the injection graph. The moment `UsersService` injects a `REQUEST`-scoped provider, `UsersService` itself effectively becomes request-scoped: Nest has to instantiate a new `UsersService` (and everything that depends on it) per request in order to supply a fresh request-scoped dependency. That silently changes the scope of a provider you described as \"used all over the app,\" which is exactly the case the cost warning applies to — a new instance of that service and its dependency subtree on every request, plus the objects that inject it also being pulled into request scope.\n\nDepending on how it's wired you may also hit a resolution error rather than silent propagation (e.g. if the singleton is consumed from a context where no request scope exists, like a startup-time or a non-HTTP caller), so \"it compiled\" is not a sufficient check here.\n\nOptions, roughly in order of preference:\n\n1. Don't inject the user-fetching provider at all. Have the controller pull the current user and pass the needed value (or a plain typed object) into the service method as an argument. `UsersService` stays a singleton; the request-scoped provider stays confined to the controller/guard layer where it belongs.\n\n2. If the service genuinely needs to react to the request, invert the dependency: inject `REQUEST` into the service's *method* call path or use a request-scoped context helper (`AsyncLocalStorage`-backed, or `@Inject(REQUEST)` in a thin wrapper) at the boundary, not into the singleton's constructor.\n\n3. Only if per-request state is a real requirement for `UsersService` itself — make it explicitly `Scope.REQUEST` and accept that every consumer must also be request-scoped. Do this as a deliberate decision, not as a side effect of injecting one small provider.\n\nBefore changing anything, check the nearest existing feature module: if the codebase already has a pattern for \"read current user,\" follow it. If not, (1) is usually the right default — the request-scoped provider is a boundary concern, and the singleton service should receive what it needs as data, not as an injected request handle.\n\nQuick self-check on the change: after implementing, the app should still boot with no `UnknownDependenciesException` or circular-dependency warnings, and `UsersService`'s scope should be unchanged (Singleton). If either changed, the injection above it is the cause.",
390
+ "outputSha256": "f34f2ebc3f73ec37904e929e9c94ac9e6a8084e8549e5ae54f2ebdc3a6224af4",
391
+ "promptSha256": "185cd5c62d689e33518253bb500a99a1184db4be7e06b42f33af2b3516acc778",
392
+ "deterministic": [],
393
+ "judge": {
394
+ "verdict": "pass",
395
+ "reason": "Answer states Nest propagates scope up the injection graph, making UsersService and everything depending on it request-scoped per request (\"UsersService itself effectively becomes request-scoped... a new UsersService (and everything that depends on it) per request\"). It recommends against injecting directly, proposing controller passes value as argument (option 1) or isolating request-scoped logic in a thin wrapper/boundary (option 2)."
396
+ },
397
+ "passed": true
398
+ },
399
+ {
400
+ "output": "No — injecting your REQUEST-scoped provider directly into `UsersService` as-is is exactly the trap called out in the rules, and it will not compile into the DI graph the way you want.\n\nHere's why: Nest propagates scope **up** the injection graph. The moment a REQUEST-scoped provider appears in a provider's constructor, that consumer becomes REQUEST-scoped as well. So `UsersService` — currently a singleton \"used all over the app\" — silently becomes request-scoped. Every service that injects `UsersService`, transitively, gets dragged into request scope too. That means a fresh instance of that whole subtree is constructed per HTTP request, destroying the singleton's caching/lifecycle and potentially throwing at startup if the propagation hits a provider that can't accommodate it. Either way you've defeated the point of a plain shared singleton.\n\n## What to do instead\n\nPick whichever fits your actual need:\n\n**1. You genuinely need the current user inside `UsersService` logic.**\nVerify that requirement first — often it's really the *caller* (controller or a request-scoped orchestrator) that should read the user and pass it in as an argument. A singleton method like:\n\n```ts\nasync findForUser(userId: string, ...) { ... }\n```\n\nkeeps `UsersService` a singleton and shifts the request-boundary concern to the layer that's actually request-bound. This is the cleanest fix and should be your default.\n\n**2. You truly need the request-scoped provider, but not everywhere.**\nConfine it. Create a thin request-scoped provider (or a per-request context service) that depends on both the request-scoped user provider and `UsersService`, and inject *that* only where the current user is needed. Now the scope boundary is a deliberate, small subtree rather than the whole app:\n\n```ts\n@Injectable({ scope: Scope.REQUEST })\nclass UserContextService {\n constructor(\n private readonly currentUser: CurrentUserProvider, // request-scoped\n private readonly users: UsersService, // stays singleton\n ) {}\n}\n```\n\n`UsersService` stays a singleton; only `UserContextService` and its consumers are request-scoped.\n\n**3. You only need the request in one narrow case.**\nInject `REQUEST` via `@Inject(REQUEST)` inside that single request-scoped provider — not inside the singleton.\n\n## The judgment call\n\nReach for option 1 unless you can state in one sentence why the singleton itself needs request state. \"Just in case\" is not a reason — request scope re-instantiates the entire injection subtree per request, so it's a cost you pay app-wide for one provider's convenience.\n\nBefore calling it done, boot the app (or run the e2e bootstrap) and confirm there's no scope-propagation warning and no `UnknownDependenciesException`, since this class of mistake surfaces at resolution time rather than in `tsc`.",
401
+ "outputSha256": "64edf985cdff66f4dc1c2aa287f8d8ec7cc29e08c72f2e631467073388f49786",
402
+ "promptSha256": "185cd5c62d689e33518253bb500a99a1184db4be7e06b42f33af2b3516acc778",
403
+ "deterministic": [],
404
+ "judge": {
405
+ "verdict": "pass",
406
+ "reason": "Answer states Nest propagates scope up the injection graph, making UsersService and every transitive consumer request-scoped, re-instantiated per request (\"silently becomes request-scoped... dragged into request scope too\"). It recommends against direct injection, offering passing the value as a method argument (findForUser(userId)) or isolating into a thin request-scoped UserContextService. No fail criterion holds."
407
+ },
408
+ "passed": true
409
+ },
410
+ {
411
+ "output": "No — that's exactly the case the skill flags as a red flag. Injecting a REQUEST-scoped provider into a Singleton makes the Singleton request-scoped too: Nest propagates scope up the whole injection graph, so `UsersService` gets re-instantiated per request, and every provider that injects `UsersService` (directly or transitively) inherits that cost as well. In an app where `UsersService` is \"used all over,\" that's a broad, easy-to-miss perf regression, not a local change. It's not a compile error and the app will still boot, so `tsc` being clean won't catch it — the downside only shows up at runtime under load.\n\nWhat to do instead depends on what the provider actually does:\n\n- **If it's just reading the current user off the request** (e.g. a header, a JWT payload already decoded by a guard), don't inject it at all where you can avoid it. Pass the value down as a method argument: the controller (or the guard) extracts the user and calls `usersService.doSomething(user)`. The service stays a Singleton with an explicit dependency in its signature, and it's trivially testable.\n\n- **If the caller genuinely needs request-scoped state deep in the service layer**, keep `UsersService` Singleton and inject the request-scoped provider only at the points that actually need it — e.g. have the request-scoped piece be the thing that receives the current user and calls into `UsersService`, rather than `UsersService` reaching back up for it. Inversion of the dependency direction avoids the scope propagation entirely.\n\n- **If you must inject it into `UsersService`**, then accept that `UsersService` is now REQUEST-scoped and make that deliberate: confirm that's acceptable for every consumer, and note that you can't then inject `UsersService` into a Singleton either without pushing the same problem one level further up. If it's already used all over as a Singleton, this is almost certainly not the right trade.\n\nSo: don't do it as-is. Default to passing the current user as an argument, and only reach for request scope in `UsersService` if per-request state there is a real requirement rather than a convenience. After changing anything here, re-run the project's build and confirm the app still boots with no scope-related warnings or resolution errors at startup, since this class of problem doesn't surface in a plain type-check.",
412
+ "outputSha256": "f900a6e3cab0dfc4768c3bc9a664d975c8d41335e0477076b98d8a06410690f0",
413
+ "promptSha256": "185cd5c62d689e33518253bb500a99a1184db4be7e06b42f33af2b3516acc778",
414
+ "deterministic": [],
415
+ "judge": {
416
+ "verdict": "pass",
417
+ "reason": "Answer states injecting REQUEST-scoped provider makes UsersService request-scoped via scope propagation up the injection graph, re-instantiated per request, and every consumer inherits it. Recommends passing the user as a method argument from the controller/guard, or isolating request-scoped logic in a dedicated provider, keeping UsersService singleton. No fail criterion met."
418
+ },
419
+ "passed": true
420
+ },
421
+ {
422
+ "output": "No — that's exactly the trap this skill's rules warn about, and injecting it as-is will silently break the singleton.\n\n## Why it's not fine\n\nNest propagates provider scope **up** the injection graph, not down. If `UsersService` depends on a `REQUEST`-scoped provider, `UsersService` cannot stay a Singleton: Nest must instantiate a fresh `UsersService` for every incoming request in order to give it a fresh request-scoped dependency. So:\n\n- `UsersService` effectively becomes request-scoped whether you declared it that way or not.\n- Everything that injects `UsersService` (controllers, other services, and anything that injects *those*) gets dragged into per-request instantiation too — the scope propagates transitively.\n- For a service \"used all over the app,\" that means the whole subtree is rebuilt on every request: per-request allocation and GC pressure, lost cross-request caching/memoization, and any `OnModuleInit` lifecycle work re-running per request instead of once at boot.\n- Depending on how it's wired, you may instead get a resolution-time error rather than a silent behavior change — either outcome is a real bug, and the silent one is worse because tests that don't exercise concurrency won't catch it.\n\nThe rule is direct: **never inject a `REQUEST`-scoped or `TRANSIENT` provider into a Singleton provider** unless you have deliberately decided that the Singleton's scope should change. For a service this widely used, you almost certainly have not.\n\n## What to do instead\n\nPick based on what actually needs the current user:\n\n**1. Pass the user in as a method argument (usually the right answer).**\nKeep the request-scoped provider at the edge (controller or a thin request-scoped helper) and hand the resolved user — or just the id — into the singleton as a plain parameter:\n\n```ts\n// request-scoped provider stays at the edge\n@Injectable({ scope: Scope.REQUEST })\nexport class RequestUserProvider {\n constructor(@Inject(REQUEST) private readonly req: Request) {}\n get currentUser(): AuthenticatedUser { /* read off req */ }\n}\n\n// singleton stays a singleton\n@Injectable()\nexport class UsersService {\n findForUser(userId: string) { /* ... */ }\n}\n\n@Controller('users')\nexport class UsersController {\n constructor(\n private readonly currentUser: RequestUserProvider,\n private readonly users: UsersService,\n ) {}\n\n @Get('me')\n me() {\n return this.users.findForUser(this.currentUser.currentUser.id);\n }\n}\n```\n\nThe scope change is confined to the controller/edge, and `UsersService` remains a true singleton. This is also easier to test — call `findForUser('u1')` directly with no HTTP stack.\n\n**2. Use `@Inject(REQUEST)` only where the request is genuinely needed**, not as a transitive dependency of a shared service.\n\n**3. If you truly want request-scoped semantics in a singleton, use `AsyncLocalStorage`** (e.g. `nestjs-cls` or a small `AsyncLocalStorage`-backed context provider) rather than `Scope.REQUEST`. It gives you per-request context without re-instantiating the injection subtree per request.\n\n**4. Only accept the scope change if you actually mean it** — i.e. you've decided `UsersService` should be request-scoped, you're aware of the cost, and you're not surprised that its consumers become request-scoped too. That's a rare, deliberate choice for a service \"used all over the app.\"\n\n## Bottom line\n\nDon't inject the request-scoped provider into the singleton as-is. Introduce it at the controller/edge and pass the resolved user or id down into `UsersService` as a normal argument — or switch to `AsyncLocalStorage`-based context if you need ambient per-request access deep in the call stack. Either way, verify by booting the app and checking there's no scope-propagation surprise and that `UsersService` is still instantiated once at startup, not once per request.",
423
+ "outputSha256": "cd586704bd6bfb9b20c899e6fb8165a5183664edf727247ebc4bc86bb623a17a",
424
+ "promptSha256": "185cd5c62d689e33518253bb500a99a1184db4be7e06b42f33af2b3516acc778",
425
+ "deterministic": [],
426
+ "judge": {
427
+ "verdict": "pass",
428
+ "reason": "Answer states Nest propagates scope up the injection graph, making UsersService request-scoped and dragging its consumers transitively (\"Everything that injects UsersService ... gets dragged into per-request instantiation too\"). It recommends against direct injection, showing passing the user/id as a method argument from the controller (findForUser(userId)) and isolating request-scoped logic in a thin edge provider."
429
+ },
430
+ "passed": true
431
+ }
432
+ ]
433
+ }
434
+ ],
435
+ "verdict": "fail",
436
+ "scope": "bundled",
437
+ "skillDigest": "3ca8f6f93c76be9dc10b0c7ed02d34173404358caab330a42dbbceae3934ce20",
438
+ "catalogDigest": "139cc7e7c63f9a3fcb3560551b7740c5642c828db2570e2f40728089218cc6d4",
439
+ "judgePromptVersion": "2026-09-25.1",
440
+ "runner": "deepseek",
441
+ "model": "deepseek-chat",
442
+ "runnerPromptVersion": "2026-09-25.1",
443
+ "recordedAt": "2026-09-25T14:54:24.836Z",
444
+ "judge": "deepseek",
445
+ "judgeModel": "deepseek-chat"
446
+ },
447
+ {
448
+ "schemaVersion": "1.0.0",
449
+ "skillId": "nestjs/nestjs-testing",
450
+ "strictness": "high",
451
+ "trials": 10,
452
+ "triggerAccuracy": {
453
+ "truePositive": 6,
454
+ "falsePositive": 0,
455
+ "positives": 6,
456
+ "negatives": 6
457
+ },
458
+ "evidence": "authored",
459
+ "scenarios": [
460
+ {
461
+ "id": "trigger-positive-1",
462
+ "kind": "trigger-positive",
463
+ "prompt": "I need a unit test for OrdersService that swaps in a fake for its Repository dependency instead of hitting the real database",
464
+ "strictness": "high",
465
+ "trials": 1,
466
+ "passes": 1,
467
+ "passRate": 1,
468
+ "passAtK": 1,
469
+ "grader": "trigger-rank-fork-family",
470
+ "status": "ran",
471
+ "deterministic": true
472
+ },
473
+ {
474
+ "id": "trigger-positive-2",
475
+ "kind": "trigger-positive",
476
+ "prompt": "How do I replace the payment gateway provider with a stub when testing this NestJS module, without making real API calls",
477
+ "strictness": "high",
478
+ "trials": 1,
479
+ "passes": 1,
480
+ "passRate": 1,
481
+ "passAtK": 1,
482
+ "grader": "trigger-rank-fork-family",
483
+ "status": "ran",
484
+ "deterministic": true
485
+ },
486
+ {
487
+ "id": "trigger-positive-3",
488
+ "kind": "trigger-positive",
489
+ "prompt": "I need to drive the real POST /users route through supertest against a fully bootstrapped NestJS app instance, hitting actual guards and pipes instead of mocking the controller directly.",
490
+ "strictness": "high",
491
+ "trials": 1,
492
+ "passes": 1,
493
+ "passRate": 1,
494
+ "passAtK": 1,
495
+ "grader": "trigger-rank-fork-family",
496
+ "status": "ran",
497
+ "deterministic": true
498
+ },
499
+ {
500
+ "id": "trigger-positive-4",
501
+ "kind": "trigger-positive",
502
+ "prompt": "I want to unit test a NestJS route guard that checks role metadata, but without booting the whole app -- just fake out whatever it pulls from Reflector.",
503
+ "strictness": "high",
504
+ "trials": 1,
505
+ "passes": 1,
506
+ "passRate": 1,
507
+ "passAtK": 1,
508
+ "grader": "trigger-rank-fork-family",
509
+ "status": "ran",
510
+ "deterministic": true
511
+ },
512
+ {
513
+ "id": "trigger-positive-5",
514
+ "kind": "trigger-positive",
515
+ "prompt": "My NestJS test throws saying a provider is missing when the test module tries to compile -- what's wrong with my test setup",
516
+ "strictness": "high",
517
+ "trials": 1,
518
+ "passes": 1,
519
+ "passRate": 1,
520
+ "passAtK": 1,
521
+ "grader": "trigger-rank-fork-family",
522
+ "status": "ran",
523
+ "deterministic": true
524
+ },
525
+ {
526
+ "id": "trigger-positive-6",
527
+ "kind": "trigger-positive",
528
+ "prompt": "My NestJS e2e test suite hangs and never exits after the run finishes, even though every test passes",
529
+ "strictness": "high",
530
+ "trials": 1,
531
+ "passes": 1,
532
+ "passRate": 1,
533
+ "passAtK": 1,
534
+ "grader": "trigger-rank-fork-family",
535
+ "status": "ran",
536
+ "deterministic": true
537
+ },
538
+ {
539
+ "id": "trigger-negative-1",
540
+ "kind": "trigger-negative",
541
+ "prompt": "Fix this NestJS build error: Nest can't resolve dependencies of UsersService",
542
+ "strictness": "high",
543
+ "trials": 1,
544
+ "passes": 1,
545
+ "passRate": 1,
546
+ "passAtK": 1,
547
+ "grader": "trigger-rank-fork-family",
548
+ "status": "ran",
549
+ "deterministic": true
550
+ },
551
+ {
552
+ "id": "trigger-negative-2",
553
+ "kind": "trigger-negative",
554
+ "prompt": "Add a new NestJS module with a controller and service for invoices",
555
+ "strictness": "high",
556
+ "trials": 1,
557
+ "passes": 1,
558
+ "passRate": 1,
559
+ "passAtK": 1,
560
+ "grader": "trigger-rank-fork-family",
561
+ "status": "ran",
562
+ "deterministic": true
563
+ },
564
+ {
565
+ "id": "trigger-negative-3",
566
+ "kind": "trigger-negative",
567
+ "prompt": "Write plain Jest tests for a date-formatting utility function with no NestJS dependencies",
568
+ "strictness": "high",
569
+ "trials": 1,
570
+ "passes": 1,
571
+ "passRate": 1,
572
+ "passAtK": 1,
573
+ "grader": "trigger-rank-fork-family",
574
+ "status": "ran",
575
+ "deterministic": true
576
+ },
577
+ {
578
+ "id": "trigger-negative-4",
579
+ "kind": "trigger-negative",
580
+ "prompt": "Review this NestJS PR for missing DTO validation and N+1 queries",
581
+ "strictness": "high",
582
+ "trials": 1,
583
+ "passes": 1,
584
+ "passRate": 1,
585
+ "passAtK": 1,
586
+ "grader": "trigger-rank-fork-family",
587
+ "status": "ran",
588
+ "deterministic": true
589
+ },
590
+ {
591
+ "id": "trigger-negative-5",
592
+ "kind": "trigger-negative",
593
+ "prompt": "Write Vue component tests using Vue Test Utils and Vitest",
594
+ "strictness": "high",
595
+ "trials": 1,
596
+ "passes": 1,
597
+ "passRate": 1,
598
+ "passAtK": 1,
599
+ "grader": "trigger-rank-fork-family",
600
+ "status": "ran",
601
+ "deterministic": true
602
+ },
603
+ {
604
+ "id": "trigger-negative-6",
605
+ "kind": "trigger-negative",
606
+ "prompt": "Add class-validator decorators to this DTO for the new signup endpoint",
607
+ "strictness": "high",
608
+ "trials": 1,
609
+ "passes": 1,
610
+ "passRate": 1,
611
+ "passAtK": 1,
612
+ "grader": "trigger-rank-fork-family",
613
+ "status": "ran",
614
+ "deterministic": true
615
+ },
616
+ {
617
+ "id": "mock-dependency-boundary",
618
+ "kind": "behavior",
619
+ "prompt": "I'm writing a unit test for UsersService, which depends on UsersRepository. What's the right way to set this up with @nestjs/testing?",
620
+ "strictness": "high",
621
+ "trials": 10,
622
+ "passes": 10,
623
+ "passRate": 1,
624
+ "passAtK": 1,
625
+ "grader": "judge",
626
+ "status": "ran",
627
+ "trialRecords": [
628
+ {
629
+ "output": "# Unit-testing `UsersService` with a mocked `UsersRepository`\n\nBecause you're testing one provider in isolation, don't import `UsersModule`. Hand-assemble the providers array and declare the mock repository directly — no `overrideProvider` needed, since you already control the whole list.\n\n## Setup\n\n```typescript\n// users.service.spec.ts\nimport { Test, TestingModule } from '@nestjs/testing';\nimport { UsersService } from './users.service';\nimport { UsersRepository } from './users.repository';\n\ndescribe('UsersService', () => {\n let service: UsersService;\n let repo: jest.Mocked<UsersRepository>; // or whatever mock type fits your repo\n\n beforeEach(async () => {\n const mockRepo = {\n findById: jest.fn(),\n save: jest.fn(),\n // ...only the methods UsersService actually calls\n };\n\n const moduleRef: TestingModule = await Test.createTestingModule({\n providers: [\n UsersService,\n { provide: UsersRepository, useValue: mockRepo },\n ],\n }).compile();\n\n service = moduleRef.get(UsersService);\n repo = moduleRef.get(UsersRepository);\n });\n\n it('returns the user from the repository', async () => {\n repo.findById.mockResolvedValue({ id: '1', name: 'Ada' });\n\n await expect(service.findOne('1')).resolves.toEqual({ id: '1', name: 'Ada' });\n });\n\n it('throws NotFoundException when the repository returns null', async () => {\n repo.findById.mockResolvedValue(null);\n\n await expect(service.findOne('1')).rejects.toThrow(NotFoundException);\n });\n});\n```\n\n## The rules that matter here\n\n- **Build through the testing module, not `new`.** `Test.createTestingModule(...).compile()` is what proves `UsersService`'s constructor actually resolves against the provider token you registered. `new UsersService(mockRepo)` skips that wiring and can pass while the real module would fail to compile. (Nest's own docs do show `new` for pure logic, but use the testing module when you want the DI graph exercised.)\n- **Mock at the injected boundary** — the repository methods — not a private method on `UsersService`. Stubbing `service['somePrivateHelper']` couples the test to an implementation detail.\n- **Assert on behavior**, not on `repo.findById` being called N times as the whole test. The call-count check is fine as a supporting assertion, but the test should pin down the service's return value or the exception it throws.\n- **Pick one technique per provider.** Either declare the mock in the providers array (this case) *or* `.overrideProvider(UsersRepository).useValue(...)` when you're importing a real module you don't want to reassemble — never both for the same token.\n\n## What you don't need here\n\nNo `createNestApplication()`, no supertest, no `app.close()` — those belong to e2e specs that drive the real HTTP pipeline through guards/pipes/filters. For a single-provider unit test, `moduleRef.get(UsersService)` and direct method calls are the whole story.\n\nIf `UsersService` has other injected dependencies, add a mock entry for each one in `providers`; a missing one will surface as a compile-time \"Nest can't resolve dependencies\" error, which is exactly the signal that the module graph isn't complete.",
630
+ "outputSha256": "40973096599ab594f003ff499cd4b6935a78ec88effdc10418a6c54aedb17d3a",
631
+ "promptSha256": "52b4c350df70699aef1adced535916a43f0cde9b93c89df4c7d7d039bab573a7",
632
+ "deterministic": [],
633
+ "judge": {
634
+ "verdict": "pass",
635
+ "reason": "Answer declares `{ provide: UsersRepository, useValue: mockRepo }` in a hand-assembled Test.createTestingModule providers array, mocking at the injected boundary. It explicitly warns against stubbing a private method on UsersService ('Stubbing service[\"somePrivateHelper\"] couples the test to an implementation detail'). No fail criterion holds."
636
+ },
637
+ "passed": true
638
+ },
639
+ {
640
+ "output": "Build the test through `Test.createTestingModule` with the mock declared directly in the `providers` array — you control the whole list, so no `.overrideProvider()` is needed:\n\n```typescript\nimport { Test, TestingModule } from '@nestjs/testing';\nimport { UsersService } from './users.service';\nimport { UsersRepository } from './users.repository';\n\ndescribe('UsersService', () => {\n let service: UsersService;\n let repo: { findById: jest.Mock };\n\n beforeEach(async () => {\n repo = {\n findById: jest.fn(),\n };\n\n const moduleRef: TestingModule = await Test.createTestingModule({\n providers: [\n UsersService,\n { provide: UsersRepository, useValue: repo },\n ],\n }).compile();\n\n service = moduleRef.get(UsersService);\n });\n\n it('returns the user when the repo finds one', async () => {\n const user = { id: '1', name: 'Ada' };\n repo.findById.mockResolvedValue(user);\n\n await expect(service.findById('1')).resolves.toEqual(user);\n expect(repo.findById).toHaveBeenCalledWith('1');\n });\n\n it('throws when the repo returns null', async () => {\n repo.findById.mockResolvedValue(null);\n\n await expect(service.findById('1')).rejects.toThrow();\n });\n});\n```\n\nKey points, tied to the workflow:\n\n1. **Mock the boundary, not the internals.** `UsersRepository` is the injected dependency — replace it with `{ provide: UsersRepository, useValue: mockRepo }`. Do *not* stub a private method on `UsersService` that happens to call the repo.\n\n2. **Use `{ provide: UsersRepository, useValue: ... }` (or `useFactory`)** rather than `.overrideProvider()` here. `.overrideProvider()` exists to swap one provider inside a real module you're importing wholesale (`imports: [UsersModule]`). Since you're declaring the providers yourself, the mock *is* the provider — no override step.\n\n3. **Resolve the instance with `moduleRef.get(UsersService)`.** Don't write `new UsersService(mockRepo)`; that bypasses the DI graph you just assembled.\n\n4. **Assert on behavior, not call counts alone.** Check the resolved value / thrown exception (`expect(repo.findById).toHaveBeenCalledWith(...)` is a fine *supplement*, but the return value or rejection is the real assertion).\n\n5. **Recreate the module (and reset mocks) in `beforeEach`** so specs don't leak state into each other. `jest.fn()` fresh each time handles the reset; if you reuse a mock object across tests, call `mockClear()`/`mockReset()` in `beforeEach` or `afterEach`.\n\n6. **If the dependency is something other than a class** (e.g. a config injection token or an HTTP client provided via a custom token), provide it with that same token string/symbol so Nest can match it.\n\nThat's the entirety of the setup — compile once per test with the mock in the provider list, grab the service via `get()`, and drive it through its public methods.",
641
+ "outputSha256": "81c6f83d54ed1ee29b75431d0abc7c55e85c927b188754caa691cb97ebc2c46b",
642
+ "promptSha256": "52b4c350df70699aef1adced535916a43f0cde9b93c89df4c7d7d039bab573a7",
643
+ "deterministic": [],
644
+ "judge": {
645
+ "verdict": "pass",
646
+ "reason": "Answer declares { provide: UsersRepository, useValue: repo } in Test.createTestingModule providers array (code block), and explicitly says 'Mock the boundary, not the internals... Do not stub a private method on UsersService.' No fail criterion met."
647
+ },
648
+ "passed": true
649
+ },
650
+ {
651
+ "output": "Use `Test.createTestingModule` with a provider that supplies a double for the repository, compiling only the providers you actually need. Both of these are correct and idiomatic — pick based on what you control:\n\n**Hand-assembled providers array (usual choice for a focused unit test):**\n\n```typescript\nimport { Test, TestingModule } from '@nestjs/testing';\nimport { UsersService } from './users.service';\nimport { UsersRepository } from './users.repository';\n\ndescribe('UsersService', () => {\n let service: UsersService;\n let repo: { findById: jest.Mock; save: jest.Mock };\n\n beforeEach(async () => {\n repo = {\n findById: jest.fn(),\n save: jest.fn(),\n };\n\n const moduleRef: TestingModule = await Test.createTestingModule({\n providers: [\n UsersService,\n { provide: UsersRepository, useValue: repo },\n ],\n }).compile();\n\n service = moduleRef.get(UsersService);\n });\n\n it('returns the user from the repository', async () => {\n const user = { id: 1, name: 'Ada' };\n repo.findById.mockResolvedValue(user);\n\n await expect(service.findOne(1)).resolves.toEqual(user);\n expect(repo.findById).toHaveBeenCalledWith(1);\n });\n\n it('throws when the user is missing', async () => {\n repo.findById.mockResolvedValue(null);\n await expect(service.findOne(1)).rejects.toThrow();\n });\n});\n```\n\n**Override on a real module** — use this when `UsersService` is declared inside a `UsersModule` you'd rather import than reassemble by hand:\n\n```typescript\nconst moduleRef = await Test.createTestingModule({ imports: [UsersModule] })\n .overrideProvider(UsersRepository)\n .useValue(repo)\n .compile();\n```\n\nNotes that matter here:\n\n- Pass the **repository token** (`UsersRepository`) as `provide`, and `useValue` for a plain object of jest mocks (`useFactory`/`useClass` if you need construction logic). Never reach inside the service and stub a private method — mock at the injected-dependency boundary.\n- Get the instance with `moduleRef.get(UsersService)`; don't `new UsersService(repo)` yourself. `new` is fine for a pure logic test, but if you want the test to prove the module's DI wiring actually resolves, go through `Test.createTestingModule`.\n- Only pick one approach per provider — don't hand-assemble *and* `overrideProvider` the same token.\n- Assert on behavior (return value / thrown exception / that the repo was called with the right args), not on the mock's call count as the whole test.\n- For an e2e spec (booting `createNestApplication()` and driving it with supertest instead), the setup differs — separate spec file under `test/`, and it must `app.close()` in `afterAll`.",
652
+ "outputSha256": "209f5bc225ac334051ed3e2f47489d8fb717e23e0fa247e4ef6246c28397af1c",
653
+ "promptSha256": "52b4c350df70699aef1adced535916a43f0cde9b93c89df4c7d7d039bab573a7",
654
+ "deterministic": [],
655
+ "judge": {
656
+ "verdict": "pass",
657
+ "reason": "Answer shows { provide: UsersRepository, useValue: repo } in Test.createTestingModule providers, and .overrideProvider(UsersRepository).useValue(repo) on an imported module. Explicitly warns 'Never reach inside the service and stub a private method — mock at the injected-dependency boundary.' No internal-method stubbing recommended."
658
+ },
659
+ "passed": true
660
+ },
661
+ {
662
+ "output": "The short answer: build the service through `Test.createTestingModule(...).compile()` with a mock declared directly in the `providers` array, then pull the instance with `moduleRef.get(UsersService)`.\n\n```typescript\nimport { Test, TestingModule } from '@nestjs/testing';\nimport { UsersService } from './users.service';\nimport { UsersRepository } from './users.repository';\n\ndescribe('UsersService', () => {\n let service: UsersService;\n let mockRepo: { findById: jest.Mock; save: jest.Mock /* ...your methods */ };\n\n beforeEach(async () => {\n mockRepo = {\n findById: jest.fn(),\n save: jest.fn(),\n };\n\n const moduleRef: TestingModule = await Test.createTestingModule({\n providers: [\n UsersService,\n { provide: UsersRepository, useValue: mockRepo },\n ],\n }).compile();\n\n service = moduleRef.get<UsersService>(UsersService);\n });\n\n it('returns the user from the repository', async () => {\n mockRepo.findById.mockResolvedValue({ id: 1, name: 'Ada' });\n\n await expect(service.findById(1)).resolves.toEqual({ id: 1, name: 'Ada' });\n });\n});\n```\n\nA few points that matter for how you set this up:\n\n**Declare the mock in `providers`, don't override.** Since you're hand-assembling the providers array for a focused unit test, you already control the whole list — just `{ provide: UsersRepository, useValue: mockRepo }`. `.overrideProvider(...)` is for the other case: when you `imports: [UsersModule]` and want to swap out one provider that the real module already declares without re-listing all of them. Pick one approach per provider, not both.\n\n**Mock at the injected-dependency boundary.** `UsersRepository` is the seam. Mock that, not a private method on `UsersService` that happens to call the repo — stubbing internals couples the test to an implementation detail and defeats the point.\n\n**Assert behavior, not call counts.** Assert on `service`'s return value or thrown exception. A test whose only assertion is \"repo.findById was called once\" doesn't prove the service does anything useful — assert what it returns or throws.\n\n**A note on `new UsersService(mockRepo)`.** NestJS's own docs show this for a pure unit test of the service's logic, and it's fine when that's all you need. But once the test needs to prove the module's own DI wiring actually resolves (correct token, exported provider, real construction), go through `Test.createTestingModule` — `new` bypasses that wiring entirely and can pass while the real module would fail to compile.\n\n**Verify before calling it done:** the unit script passes, the new spec fails without the fix and passes with it, no dependency was substituted by monkey-patching, and no spec was skipped or deleted to get to green. `git status` should show changes confined to the spec (and the source, only if the test surfaced a real bug).",
663
+ "outputSha256": "9dc3af2cc66846a0812c76f967480f4dd2e2be2ae0b4e13dd3d83449fcdb90ae",
664
+ "promptSha256": "52b4c350df70699aef1adced535916a43f0cde9b93c89df4c7d7d039bab573a7",
665
+ "deterministic": [],
666
+ "judge": {
667
+ "verdict": "pass",
668
+ "reason": "Answer shows { provide: UsersRepository, useValue: mockRepo } in Test.createTestingModule providers array, pulls service via moduleRef.get, and explicitly says to mock at the injected-dependency boundary, not a private method on UsersService. Also notes new UsersService(mockRepo) is acceptable. No internal-method stubbing recommended."
669
+ },
670
+ "passed": true
671
+ },
672
+ {
673
+ "output": "```typescript\nimport { Test } from '@nestjs/testing';\nimport { UsersService } from './users.service';\nimport { UsersRepository } from './users.repository';\n\ndescribe('UsersService', () => {\n let service: UsersService;\n const mockRepo = {\n findById: jest.fn(),\n save: jest.fn(),\n };\n\n beforeEach(async () => {\n const moduleRef = await Test.createTestingModule({\n providers: [\n UsersService,\n { provide: UsersRepository, useValue: mockRepo },\n ],\n }).compile();\n\n service = moduleRef.get(UsersService);\n jest.clearAllMocks();\n });\n\n it('returns the user when the repository finds one', async () => {\n mockRepo.findById.mockResolvedValue({ id: '1', name: 'Ada' });\n\n await expect(service.findById('1')).resolves.toEqual({ id: '1', name: 'Ada' });\n expect(mockRepo.findById).toHaveBeenCalledWith('1');\n });\n\n it('throws when the repository finds no user', async () => {\n mockRepo.findById.mockResolvedValue(null);\n\n await expect(service.findById('missing')).rejects.toThrow();\n });\n});\n```\n\nKey points for your setup:\n\n- **Declare the mock directly in `providers`** as `{ provide: UsersRepository, useValue: mockRepo }`. Since you're hand-assembling the providers array, no `.overrideProvider()` is needed — that's only for when you import a real module (`imports: [UsersModule]`) and want to swap one provider it already declares.\n- **Build the instance with `Test.createTestingModule(...).compile()` and `moduleRef.get(UsersService)`** rather than `new UsersService(mockRepo)`. Writing `new` is fine for a pure logic test, but it bypasses Nest's DI wiring entirely, so the test would still pass even if `UsersService` couldn't actually resolve `UsersRepository` in the real module.\n- **Mock only `UsersRepository`** — the injected boundary. Don't stub private methods on `UsersService` itself; that couples the test to an implementation detail.\n- **Assert on behavior** (`resolves.toEqual(...)`, `rejects.toThrow()`), not just on `mockRepo.findById` having been called. The call assertion is a useful supplement, not the whole test.\n- Reset mocks in `beforeEach` (`jest.clearAllMocks()`) so call counts and resolved values don't leak between tests.\n\nIf `UsersService` instead depends on a token-like interface (e.g. `@Inject(USERS_REPOSITORY) private repo: UsersRepository`), provide the mock under that same token: `{ provide: USERS_REPOSITORY, useValue: mockRepo }`.\n\nStick to the spec file(s) — don't touch the source unless the test surfaces a real bug.",
674
+ "outputSha256": "ce14bcd5e7e303283be4b682556b47e2115a2b89d315317ba024563217b42e4a",
675
+ "promptSha256": "52b4c350df70699aef1adced535916a43f0cde9b93c89df4c7d7d039bab573a7",
676
+ "deterministic": [],
677
+ "judge": {
678
+ "verdict": "pass",
679
+ "reason": "Answer declares { provide: UsersRepository, useValue: mockRepo } in Test.createTestingModule providers, builds via compile()/moduleRef.get(UsersService), and explicitly says 'Mock only UsersRepository — the injected boundary. Don't stub private methods on UsersService itself.' No internal-method stubbing recommended."
680
+ },
681
+ "passed": true
682
+ },
683
+ {
684
+ "output": "Set it up with `Test.createTestingModule`, declaring `UsersService` as the provider under test and the repository as a value that supplies the fake:\n\n```typescript\nimport { Test, TestingModule } from '@nestjs/testing';\nimport { UsersService } from './users.service';\nimport { UsersRepository } from './users.repository';\n\ndescribe('UsersService', () => {\n let service: UsersService;\n let repo: { findById: jest.Mock; save: jest.Mock };\n\n beforeEach(async () => {\n repo = {\n findById: jest.fn(),\n save: jest.fn(),\n };\n\n const moduleRef: TestingModule = await Test.createTestingModule({\n providers: [\n UsersService,\n { provide: UsersRepository, useValue: repo },\n ],\n }).compile();\n\n service = moduleRef.get(UsersService);\n });\n\n it('returns the user the repository resolves', async () => {\n const user = { id: 1, name: 'Ada' };\n repo.findById.mockResolvedValue(user);\n\n await expect(service.findOne(1)).resolves.toEqual(user);\n expect(repo.findById).toHaveBeenCalledWith(1);\n });\n\n it('throws NotFound when the repository returns nothing', async () => {\n repo.findById.mockResolvedValue(undefined);\n await expect(service.findOne(2)).rejects.toThrow(NotFoundError);\n });\n});\n```\n\nA few points that matter:\n\n- **Mock at the dependency boundary, not inside the unit.** The fake stands in for `UsersRepository`; you assert on `UsersService`'s return value or thrown exception. Don't reach in and stub a private method of the service.\n- **`useValue` with a hand-built object is the common choice**, because you already control the whole `providers` array for a focused unit test. `useClass`/`useFactory` also work if the double needs construction or async setup.\n- **`moduleRef.get(UsersService)` is the hand-off point** — this is where you get the DI-wired instance. Typing the provider list by interface (a plain object with `jest.Mock` members) gives you autocomplete on `mockResolvedValue` etc. without casting.\n- **Add a compile-time guard if the module has real wiring to prove.** If `UsersService` is exported from a `UsersModule` whose DI you want to exercise, use `Test.createTestingModule({ imports: [UsersModule] }).overrideProvider(UsersRepository).useValue(repo).compile()` instead — `overrideProvider` swaps the one provider without you re-listing the whole module. Don't mix the two styles for the same provider.\n- **Keep it deterministic.** Fresh mocks in `beforeEach` so call counts and resolved values don't bleed between cases; if the service touches time, `Math.random`, or timers, fake those too rather than letting the real ones run.\n\nThat's the whole setup for a unit spec. E2E is a different shape — there you'd `createNestApplication()`, drive it with supertest, and close the app in `afterAll`.",
685
+ "outputSha256": "47c3b3a3e5b4a0f7b1875205cc8db3c8e26bb02a43f6d38ceafaf48037608500",
686
+ "promptSha256": "52b4c350df70699aef1adced535916a43f0cde9b93c89df4c7d7d039bab573a7",
687
+ "deterministic": [],
688
+ "judge": {
689
+ "verdict": "pass",
690
+ "reason": "Answer declares { provide: UsersRepository, useValue: repo } in Test.createTestingModule providers, and also shows .overrideProvider(UsersRepository).useValue(repo) for module imports. It explicitly warns 'Don't reach in and stub a private method of the service.' No fail criterion met."
691
+ },
692
+ "passed": true
693
+ },
694
+ {
695
+ "output": "For a `UsersService` unit test, build it through the testing module and provide a mock for `UsersRepository`. The two idiomatic setups:\n\n**If you're hand-assembling the providers array** (the common case for a focused unit test), declare the mock directly — no override needed, you already control the whole list:\n\n```typescript\nimport { Test } from '@nestjs/testing';\nimport { UsersService } from './users.service';\nimport { UsersRepository } from './users.repository';\n\ndescribe('UsersService', () => {\n let service: UsersService;\n const mockRepo = {\n findById: jest.fn(),\n save: jest.fn(),\n };\n\n beforeEach(async () => {\n const moduleRef = await Test.createTestingModule({\n providers: [\n UsersService,\n { provide: UsersRepository, useValue: mockRepo },\n ],\n }).compile();\n\n service = moduleRef.get(UsersService);\n });\n\n it('returns the user from the repository', async () => {\n mockRepo.findById.mockResolvedValue({ id: 1, name: 'Ada' });\n await expect(service.findOne(1)).resolves.toEqual({ id: 1, name: 'Ada' });\n });\n});\n```\n\n**If you're importing a real module** you don't want to reassemble, use `.overrideProvider()` to swap just that one provider:\n\n```typescript\nconst moduleRef = await Test.createTestingModule({ imports: [UsersModule] })\n .overrideProvider(UsersRepository)\n .useValue(mockRepo)\n .compile();\n```\n\nKey points:\n\n- Mock at the injected-provider boundary (`UsersRepository`), not by stubbing a private method on `UsersService`. Don't reach inside the unit under test.\n- Assert on the service's actual behavior — return value or thrown exception — not on how many times the mock was called. A call-count assertion as the whole test proves nothing about behavior.\n- Use `Test.createTestingModule(...).compile()` rather than `new UsersService(mockRepo)`. Hand-construction is fine for a pure logic test, but it bypasses the module's DI wiring entirely — so it can pass while the real module would fail to resolve.\n\nThat's the whole setup for a service unit test. If you later add similar specs for guards/pipes/interceptors, the same module handles those via `.overrideGuard()`/`.overridePipe()`/etc.",
696
+ "outputSha256": "69751a0a71338269d3c07c4d5d51e067a82c211c387ad94d447633cbfe56f7d6",
697
+ "promptSha256": "52b4c350df70699aef1adced535916a43f0cde9b93c89df4c7d7d039bab573a7",
698
+ "deterministic": [],
699
+ "judge": {
700
+ "verdict": "pass",
701
+ "reason": "Answer shows { provide: UsersRepository, useValue: mockRepo } in Test.createTestingModule providers and .overrideProvider(UsersRepository).useValue(mockRepo), and explicitly says mock at the injected-provider boundary, not by stubbing a private method on UsersService. No internal-method stubbing recommended."
702
+ },
703
+ "passed": true
704
+ },
705
+ {
706
+ "output": "For `UsersService` with a `UsersRepository` dependency, the right setup is a hand-assembled providers array built through `Test.createTestingModule`, with the repository replaced by a `useValue` mock:\n\n```typescript\nimport { Test, TestingModule } from '@nestjs/testing';\nimport { UsersService } from './users.service';\nimport { UsersRepository } from './users.repository';\n\ndescribe('UsersService', () => {\n let service: UsersService;\n let repo: jest.Mocked<UsersRepository>;\n\n beforeEach(async () => {\n const mockRepo = {\n findById: jest.fn(),\n save: jest.fn(),\n // every method UsersService actually calls\n };\n\n const moduleRef: TestingModule = await Test.createTestingModule({\n providers: [\n UsersService,\n { provide: UsersRepository, useValue: mockRepo },\n ],\n }).compile();\n\n service = moduleRef.get(UsersService);\n repo = moduleRef.get(UsersRepository);\n });\n});\n```\n\nKey points:\n\n- **Build through the testing module, don't `new` it.** `Test.createTestingModule({ providers: [UsersService, ...] })` is what proves the DI graph resolves. `new UsersService(mockRepo)` bypasses that and can pass while the real module would fail to compile.\n- **`useValue` for a plain object mock** is the simplest form. Use `.useClass` or `.useFactory` if the double needs construction logic.\n- **You don't need `overrideProvider` here.** That's for when you import a real module you don't want to hand-reassemble (`{ imports: [UsersModule] }).overrideProvider(UsersRepository).useValue(...)`). Since you're declaring the providers list yourself, the mock is already in place. Don't do both for the same provider.\n- **Mock at the injected boundary.** Replace the whole `UsersRepository` with jest fns. Don't stub a private method on `UsersService` that happens to call the repo -- that couples the test to an implementation detail.\n- **Assert on behavior the mock enables.** Return value from the service, or the thrown exception. Don't make a call-count assertion the entire test.\n\nA typical test then looks like:\n\n```typescript\nit('throws when the user does not exist', async () => {\n repo.findById.mockResolvedValue(null);\n\n await expect(service.getOrThrow('missing-id')).rejects.toThrow('User not found');\n});\n\nit('returns the user', async () => {\n const user = { id: '1', name: 'Ada' };\n repo.findById.mockResolvedValue(user);\n\n await expect(service.getOrThrow('1')).resolves.toEqual(user);\n});\n```\n\nIf the mock object's shape gets long, `jest.Mocked<UsersRepository>` (or a small factory returning a typed object of `jest.fn()`s) keeps every method the service calls honest without drifting from the real interface.\n\nOne caveat worth stating: `new UsersService(mockRepo)` is fine for a pure unit test of the service's own logic and NestJS's docs even show it — it's specifically wrong when you want the test to prove the module's own wiring resolves. For a focused unit test like this one, the testing-module route is still the safer default because it catches a missing provider registration at compile time rather than at runtime.",
707
+ "outputSha256": "7698c0a3de4c782966f6d641b27a1513228af7a947321f80e22164e4cf16efe5",
708
+ "promptSha256": "52b4c350df70699aef1adced535916a43f0cde9b93c89df4c7d7d039bab573a7",
709
+ "deterministic": [],
710
+ "judge": {
711
+ "verdict": "pass",
712
+ "reason": "Answer shows Test.createTestingModule providers array with { provide: UsersRepository, useValue: mockRepo } and moduleRef.get(UsersRepository), explicitly says 'Mock at the injected boundary. Replace the whole UsersRepository with jest fns. Don't stub a private method on UsersService.' No internal-method stubbing recommended."
713
+ },
714
+ "passed": true
715
+ },
716
+ {
717
+ "output": "For a focused unit test of `UsersService` with `UsersRepository` replaced by a fake, hand-assemble the providers array and declare the mock directly — no `.overrideProvider()` needed, since you already control the whole list:\n\n```typescript\nimport { Test } from '@nestjs/testing';\nimport { UsersService } from './users.service';\nimport { UsersRepository } from './users.repository';\n\ndescribe('UsersService', () => {\n let service: UsersService;\n const mockRepo = {\n findById: jest.fn(),\n save: jest.fn(),\n };\n\n beforeEach(async () => {\n const moduleRef = await Test.createTestingModule({\n providers: [\n UsersService,\n { provide: UsersRepository, useValue: mockRepo },\n ],\n }).compile();\n\n service = moduleRef.get(UsersService);\n });\n\n it('returns the user the repository finds', async () => {\n mockRepo.findById.mockResolvedValue({ id: '1', name: 'Ada' });\n\n await expect(service.getUser('1')).resolves.toEqual({\n id: '1',\n name: 'Ada',\n });\n });\n});\n```\n\nA few points that matter here:\n\n**Use `{ provide: UsersRepository, useValue: mockRepo }`, not a hand-built instance.** Building the service through `Test.createTestingModule(...).compile()` means Nest resolves the real DI graph — if `UsersService` later grows a second injected dependency, or the module's provider registration is wrong, the test fails at compile instead of silently passing. `new UsersService(mockRepo)` skips that entirely.\n\n**Mock at the injected-provider boundary, not inside the service.** Replace `UsersRepository`; don't stub a private method on `UsersService` that happens to call it. The repository is the seam that makes the unit isolated — reaching past it couples the test to an implementation detail.\n\n**Assert on behavior, not call counts.** `mockRepo.findById` was called once is a weak assertion on its own. Assert the value `getUser` returns (or the exception it throws when the repo rejects/returns null). Let the mock's return value be what enables that assertion.\n\n**When to use `.overrideProvider()` instead:** if you'd rather import a real `UsersModule` and swap just one provider rather than reassembling the providers list yourself, use:\n\n```typescript\nconst moduleRef = await Test.createTestingModule({ imports: [UsersModule] })\n .overrideProvider(UsersRepository)\n .useValue(mockRepo)\n .compile();\n```\n\nPick one approach per provider — don't do both for the same token.\n\n**Reset mocks between tests** (`jest.clearAllMocks()` in `beforeEach`) so `mockResolvedValue`/`mockRejectedValue` set in one test doesn't leak into the next.\n\nIf instead you want to prove the HTTP endpoint works end to end (guards, pipes, filters actually running), that's an e2e spec — boot `createNestApplication()` and drive it with supertest, and be sure to close the app in `afterAll`. That's a different test from this isolated unit.",
718
+ "outputSha256": "b0e678ddfdfa7fb7ff80aa2fbf5a6a6081c07d0dd60a1a1b73e86308c4b60a03",
719
+ "promptSha256": "52b4c350df70699aef1adced535916a43f0cde9b93c89df4c7d7d039bab573a7",
720
+ "deterministic": [],
721
+ "judge": {
722
+ "verdict": "pass",
723
+ "reason": "Answer declares { provide: UsersRepository, useValue: mockRepo } in Test.createTestingModule providers, shows .overrideProvider(UsersRepository).useValue(mockRepo) for imports, and explicitly says to mock at the injected-provider boundary, not stub a private method on UsersService. No internal-method stubbing recommended."
724
+ },
725
+ "passed": true
726
+ },
727
+ {
728
+ "output": "For a focused unit test of `UsersService`, hand-assemble the providers array and give it a mock repository directly — no `overrideProvider` needed, since you already control the whole provider list:\n\n```typescript\nimport { Test } from '@nestjs/testing';\n\ndescribe('UsersService', () => {\n let service: UsersService;\n const mockRepo = {\n findById: jest.fn(),\n save: jest.fn(),\n };\n\n beforeEach(async () => {\n const moduleRef = await Test.createTestingModule({\n providers: [\n UsersService,\n { provide: UsersRepository, useValue: mockRepo },\n ],\n }).compile();\n\n service = moduleRef.get(UsersService);\n });\n\n it('returns null when the user does not exist', async () => {\n mockRepo.findById.mockResolvedValue(null);\n await expect(service.findById('nope')).resolves.toBeNull();\n });\n});\n```\n\nA few points that matter here:\n\n**Use `useValue` with a plain object of `jest.fn()`s.** You get full control over each method's return per test via `mockResolvedValue`/`mockRejectedValue`, and you never touch a real DB.\n\n**Build through `Test.createTestingModule(...).compile()`, not `new UsersService(mockRepo)`.** A hand-constructed instance does skip the module system, and Nest's own docs do show that shortcut for pure logic tests. But in this skill's scope the whole reason to go through the testing module is to exercise the DI graph — that `UsersRepository` is actually injectable under that token, that the service's constructor metadata resolves. `new` bypasses all of that and can pass while the real module would fail to compile.\n\n**Get the instance with `moduleRef.get(UsersService)`.**\n\n**Mock at the injected boundary — the repository — not by stubbing a private method on `UsersService`.** If the test needs to reach inside the service to make it pass, it's coupled to an implementation detail rather than the dependency boundary.\n\n**Assert on behavior, not call counts.** `mockRepo.findById` being called once isn't the assertion; `service.findById('nope')` resolving to `null` is. Use the mock only to isolate, then assert the service's return value or thrown exception.\n\nIf you later want to test the real `UsersModule`'s wiring (exports, provider registration), switch to importing the module and swapping a single provider:\n\n```typescript\nTest.createTestingModule({ imports: [UsersModule] })\n .overrideProvider(UsersRepository)\n .useValue(mockRepo)\n .compile();\n```\n\nPick one or the other per provider — don't declare `UsersRepository` in `providers` *and* override it.\n\nFinally, don't skip or delete a failing spec to get green. If your change broke this test, work out whether the source regressed or the expectation is now stale, and fix that.",
729
+ "outputSha256": "f8f820f6d70b54d4397388c85abc988ed288ebf594e4aea872246c149d99c9a1",
730
+ "promptSha256": "52b4c350df70699aef1adced535916a43f0cde9b93c89df4c7d7d039bab573a7",
731
+ "deterministic": [],
732
+ "judge": {
733
+ "verdict": "pass",
734
+ "reason": "Answer shows { provide: UsersRepository, useValue: mockRepo } in Test.createTestingModule providers, plus .overrideProvider(UsersRepository).useValue(mockRepo) for module imports. It explicitly says to mock at the injected boundary (the repository), not by stubbing a private method on UsersService. No internal-method stubbing recommended."
735
+ },
736
+ "passed": true
737
+ }
738
+ ]
739
+ },
740
+ {
741
+ "id": "e2e-hanging-suite",
742
+ "kind": "behavior",
743
+ "prompt": "My NestJS e2e test suite finishes but the process hangs and I have to Ctrl+C it. What's the likely cause and the right fix?",
744
+ "strictness": "high",
745
+ "trials": 10,
746
+ "passes": 10,
747
+ "passRate": 1,
748
+ "passAtK": 1,
749
+ "grader": "judge",
750
+ "status": "ran",
751
+ "trialRecords": [
752
+ {
753
+ "output": "The overwhelmingly likely cause is a Nest application (or several) that was booted with `createNestApplication()` during the e2e suite and never closed. `app.init()` opens real resources — the underlying HTTP server socket, database connection pools, `setInterval`/`setTimeout` timers, message-queue consumers, and any `OnModuleDestroy`/`OnApplicationShutdown` hooks you've registered. None of that is released until `app.close()` is called. Jest reports the suite as \"passing\" the moment the last assertion resolves, but Node's event loop stays alive because handles are still open, so the process sits there until you Ctrl+C.\n\nThe other common variants of the same root cause:\n\n- Some `beforeAll` created an app but the matching `afterAll` only calls `app.close()` in one spec file and not the sibling files (each e2e spec usually boots its own app).\n- A provider started a background interval or a reconnecting client (a health-check poller, a Redis/BullMQ worker, an `@nestjs/schedule` job) that `app.close()` doesn't tear down unless the provider implements `OnModuleDestroy` and clears it — so even a spec that *does* call `close()` can hang.\n- A `beforeAll` threw partway, so `app` was never assigned and the `afterAll` that would close it silently no-ops or errors.\n\n**The fix**\n\n1. Make every e2e spec that calls `createNestApplication()` release it deterministically, *after* the HTTP server is up and before the file's tests can fail out:\n\n```typescript\nlet app: INestApplication;\n\nbeforeAll(async () => {\n const moduleRef = await Test.createTestingModule({\n imports: [AppModule],\n }).compile();\n app = moduleRef.createNestApplication();\n await app.init();\n});\n\nafterAll(async () => {\n await app.close(); // closes the HTTP server, pools, timers, shutdown hooks\n});\n```\n\n`afterAll` runs even if a test fails, so this also covers the mid-suite-failure case. Don't put `app.close()` in `afterEach` — you only boot once per file.\n\n2. If the hang survives a correct `app.close()`, you have a resource the framework can't see. In the offending provider, implement teardown and prove it runs:\n\n```typescript\n@Injectable()\nexport class PollerService implements OnModuleDestroy {\n private timer: NodeJS.Timeout;\n onModuleDestroy() {\n clearInterval(this.timer);\n }\n}\n```\n\nEnable shutdown hooks (`app.enableShutdownHooks()`) if providers rely on them.\n\n3. Diagnose rather than guess, if it's still hanging. Jest's `--detectOpenHandles` won't tell you much for a process that never exits on its own, but running the suite with `node --trace-exit` or checking `process._getActiveHandles()` in an `afterAll` will name the exact socket/interval/timer keeping the loop alive. That's the fastest way to tell \"missing `app.close()`\" from \"a provider leaks a handle even after close.\"\n\nA one-line sanity check: temporarily add `console.log('closed')` inside the `afterAll` and confirm it prints before the hang — if it doesn't, the `afterAll` isn't the one you think it is (wrong file, or the boot threw earlier and `app` is undefined).\n\nOne thing not to do: work around it by adding `--forceExit` to the test script. That kills the process before pending writes and connection cleanup finish and hides the leak you actually need to fix; treat it as a stopgap at most, never the resolution.",
754
+ "outputSha256": "a1ea15e32f882a3f8074cbfaffa777042bd55ec9b7cbe145dbbb2d24768feacb",
755
+ "promptSha256": "655f412cc21926b353a12f9371b4a9134abac167fb90b63f526191351dc3297c",
756
+ "deterministic": [],
757
+ "judge": {
758
+ "verdict": "pass",
759
+ "reason": "Answer names missing app.close() after createNestApplication()/app.init() as cause, citing leaked HTTP socket, DB pools, timers, shutdown hooks. Concrete fix shown: afterAll(async () => { await app.close(); }) for every e2e spec. Explicitly warns against --forceExit as workaround, not the fix."
760
+ },
761
+ "passed": true
762
+ },
763
+ {
764
+ "output": "The likely cause is that your e2e specs create a Nest application but never close it, so the resources it opened stay alive and keep the Node event loop busy after the tests report done.\n\nCommon culprits, in order of likelihood:\n\n- **Missing `app.close()`.** Every spec that calls `createNestApplication()` (and then `app.init()`) must close it when the file finishes. Patch this first.\n- **Leaked connections/timers underneath the app.** A DB pool, Redis client, message-broker connection, or an interval/timeout started during `init()` won't be torn down just because the test file ended. `app.close()` triggers `onModuleDestroy`/`onApplicationShutdown`, which is what actually closes those.\n- **A process-level listener registered in a spec** (a `process.on('...')`, a raw socket, or an `open` handle from supertest against a server you started manually) that outlives the suite.\n\n## The fix\n\nMake each e2e spec that boots an app close it, ideally in `afterAll`:\n\n```typescript\nlet app: INestApplication;\n\nbeforeAll(async () => {\n const moduleRef = await Test.createTestingModule({\n imports: [AppModule],\n }).compile();\n\n app = moduleRef.createNestApplication();\n await app.init();\n});\n\nafterAll(async () => {\n await app.close();\n});\n```\n\nPoints that matter here:\n\n- **`await app.close()`**, not fire-and-forget. If you don't await it, Jest can report the suite as done before teardown finishes.\n- Put it in **`afterAll`**, not `afterEach`, unless each test genuinely rebuilds the app (usually it shouldn't — rebooting per test is slow and invites exactly this kind of leak).\n- If you have **multiple e2e files**, each one needs its own close. A single shared app across files is a common source of hangs because ownership of the close is unclear.\n- **If the process still hangs after every spec closes its app**, the leak is below the app: something your `onModuleDestroy` doesn't cover. Find it with `jest --detectOpenHandles` (or the equivalent for your runner), which prints the handle keeping the loop alive — usually a DB/Redis client, an unclosed `http.Server`, or a `setInterval` without a matching `clearInterval`. Close that resource in the owning module's `onModuleDestroy`, or in the spec's `afterAll` if it was started there.\n\n## What not to do\n\nDon't \"fix\" this with `process.exit(0)` in a global teardown or by passing `--forceExit`. Both hide the leak rather than closing it; `--detectOpenHandles` will keep warning, and the same resource leak will bite you in production shutdown. Close the app (and whatever it opened) instead.",
765
+ "outputSha256": "0a441fd5debf9843a3ef82ac89226f420b521cdd0a01293e5de746a271545711",
766
+ "promptSha256": "655f412cc21926b353a12f9371b4a9134abac167fb90b63f526191351dc3297c",
767
+ "deterministic": [],
768
+ "judge": {
769
+ "verdict": "pass",
770
+ "reason": "Answer names missing app.close() after createNestApplication()/app.init() as likely cause, citing leaked DB pool/Redis/timers keeping event loop busy. Concrete fix shown: afterAll(async () => { await app.close(); }) with code, noting each e2e file needs its own close. Explicitly warns against process.exit(0)/--forceExit, so no fail criterion holds."
771
+ },
772
+ "passed": true
773
+ },
774
+ {
775
+ "output": "The most likely cause: at least one spec in the suite calls `moduleRef.createNestApplication()` (or `app.init()`) but never calls `app.close()` afterward. `@nestjs/testing`'s created application holds real resources open — HTTP server listeners, DB connection pools, interval/timeout timers from providers, and subscriptions — and Jest's process won't exit while those handles are live. Jest tries to tear down the worker after the suite reports pass/fail, hangs waiting on the still-open handles, and you're forced to Ctrl+C.\n\nThis matches the Red Flags entry: app.close() is not optional cleanup you can skip to save time; the cost is exactly this hang (or later flakiness from leaked connections).\n\n## The fix\n\nGive every e2e spec that boots an app a matching close in `afterAll`:\n\n```typescript\ndescribe('Users (e2e)', () => {\n let app: INestApplication;\n\n beforeAll(async () => {\n const moduleRef = await Test.createTestingModule({\n imports: [AppModule],\n }).compile();\n\n app = moduleRef.createNestApplication();\n await app.init();\n });\n\n afterAll(async () => {\n await app.close(); // releases the server, pool, and timers\n });\n\n it('GET /users returns 200', async () => {\n await request(app.getHttpServer()).get('/users').expect(200);\n });\n});\n```\n\nKey points:\n- `await app.close()`, not `app.close()` — actually wait for teardown to finish before the suite exits.\n- Put it in `afterAll`, paired with the `beforeAll` that created the app, so it runs even if some tests fail.\n- If a spec has multiple describes each booting an app, each needs its own close.\n\n## If you've closed every app and it still hangs\n\nThen it's a leftover handle your providers opened independently of the app lifecycle. Common culprits and how to confirm/fix:\n\n- **A `setInterval`/`setTimeout` started in a provider** (custom timers, polling, `@Cron`-style schedulers) that isn't stopped on shutdown. Implement `OnModuleDestroy` (or `onApplicationShutdown`) and clear the timer there — `app.close()` triggers these lifecycle hooks, so this is the correct place.\n- **A DB/queue/cache client opened outside Nest's DI** (a raw `new Pool()`, a top-level Redis client) that Nest doesn't manage and therefore won't close. Hold it via a provider and close it in the provider's destroy hook.\n- **A Jest worker not calling the process to exit** even after handles are released — you can confirm it's your code leaking vs. a Jest quirk with `jest --detectOpenHandles`, which prints the open handle's stack.\n\nDon't reach for `--forceExit` as the fix. It masks the real leak (your tests pass while production shutdown is still broken, since `app.close()` genuinely isn't releasing resources) — treat it as a last resort only after `--detectOpenHandles` shows nothing actionable, and note in the repo why it's there.\n\n## Verification before calling it done\n\n- The `test:e2e` script runs to completion and the process exits on its own — no Ctrl+C.\n- Every `createNestApplication()` in the suite has a matching `await app.close()`.\n- If any provider owns timers/clients, it implements `OnModuleDestroy`/`OnApplicationShutdown` and actually stops them.\n- No spec or hook was deleted or `.skip()`-ed to make the hang go away.\n- Changes confined to the spec file(s), plus any provider whose missing destroy hook was the real leak.",
776
+ "outputSha256": "89546e48f7c1412467f7a2053d992e6addeb5fc5244704c21e306c792d9ed76b",
777
+ "promptSha256": "655f412cc21926b353a12f9371b4a9134abac167fb90b63f526191351dc3297c",
778
+ "deterministic": [],
779
+ "judge": {
780
+ "verdict": "pass",
781
+ "reason": "Answer names missing app.close() after createNestApplication()/app.init() as cause, citing leaked HTTP listeners, DB pools, and interval/timeout timers. Fix shown concretely: `afterAll(async () => { await app.close(); })` paired with beforeAll, for every spec. It explicitly warns against --forceExit as the fix, so no fail criterion holds."
782
+ },
783
+ "passed": true
784
+ },
785
+ {
786
+ "output": "The likeliest cause is that your e2e specs boot a real Nest application with `createNestApplication()` and never close it, so open resources keep the Node event loop alive after the test runner reports success.\n\nWhat actually leaks:\n\n- **The HTTP server / listener.** `app.init()` starts the underlying HTTP adapter. The listening socket (and its file descriptors) keep the event loop referenced.\n- **Database connections.** If `AppModule` wires up TypeORM/Prisma/Mongoose/etc., those connection pools are opened during `app.init()` and stay open until the app/module is destroyed.\n- **Background timers / intervals.** Anything scheduled via `@nestjs/schedule`, a keep-alive interval, or a client library's internal refresh timer stays referenced.\n- **Open handles generally** — this is why Jest prints \"Jest did not exit one second after the test run has completed\" (`--detectOpenHandles` will name them).\n\nThe wrong fixes, for the record: don't reach for `--forceExit` or `--detectOpenHandles` in your normal script, and don't `process.exit()` in an `afterAll`. Those mask the leak and leave connections dangling; `--forceExit` in particular can truncate cleanup and cause flakiness elsewhere.\n\n**The right fix: close the app after the suite.**\n\n```typescript\ndescribe('Users (e2e)', () => {\n let app: INestApplication;\n\n beforeAll(async () => {\n const moduleRef = await Test.createTestingModule({\n imports: [AppModule],\n }).compile();\n\n app = moduleRef.createNestApplication();\n await app.init();\n });\n\n afterAll(async () => {\n await app.close();\n });\n\n it('GET /users', async () => {\n await request(app.getHttpServer()).get('/users').expect(200);\n });\n});\n```\n\n`await app.close()` destroys the Nest application context, which closes the HTTP listener **and** fires the `onModuleDestroy`/`onApplicationShutdown` hooks that database modules use to close their pools and cancel their timers. The `await` matters — closing is async, and not awaiting it can race the runner's teardown.\n\nA few things to check if `app.close()` alone doesn't stop the hang:\n\n1. **Every spec file that calls `app.init()` needs its own `afterAll(() => app.close())`.** A single forgotten file hangs the whole run. Grep for `createNestApplication` and confirm each has a matching close.\n2. **Make sure it's in `afterAll`, not `afterEach`.** Re-initializing the app per test is slow and, if you close in the wrong hook, you can lose the app mid-suite; `beforeAll`/`afterAll` pair is what you want unless you deliberately re-boot per test (then pair `beforeEach`/`afterEach`, both async and awaited).\n3. **A module that opens a connection outside the Nest lifecycle.** If some provider starts a pool/interval in its constructor or `onModuleInit` but never tears it down in `onModuleDestroy`/`onApplicationShutdown`, `app.close()` won't reach it. That's a source bug worth fixing, not a test workaround.\n4. **A lingering `setInterval` or an unclosed raw client** created directly in the test. Close it explicitly in `afterAll`.\n\nTo confirm you've found them all, run the suite once with `--detectOpenHandles` (Jest) or `--forceExit` temporarily and read the report — but treat that as a diagnostic, not a fix. Once every app is closed and no handles are reported, remove the flag and the process should exit on its own.",
787
+ "outputSha256": "70cc63212f4e7990847609ae3db4261b04e3ca9384727ee3c09aea7329b4c837",
788
+ "promptSha256": "655f412cc21926b353a12f9371b4a9134abac167fb90b63f526191351dc3297c",
789
+ "deterministic": [],
790
+ "judge": {
791
+ "verdict": "pass",
792
+ "reason": "Answer names missing app.close() after createNestApplication()/app.init() as cause, listing leaked HTTP listener, DB pools, and timers. Fix shown concretely: afterAll(async () => { await app.close(); }) in the e2e spec, plus note every spec needs its own afterAll close. It explicitly warns against --forceExit/process.exit as masking the leak, not recommending them."
793
+ },
794
+ "passed": true
795
+ },
796
+ {
797
+ "output": "The likely cause is that you're calling `createNestApplication()` (or `init()`) in an e2e spec but never tearing the app down — most commonly a missing `await app.close()`. The app holds things the Node event loop won't release on its own: open DB connections/sockets, the HTTP server's listening socket, timers (e.g. `@Interval`, scheduled jobs), and any long-lived providers. Jest finishes running the specs and reports results, but the process can't exit because the loop still has live handles, so it just sits there and you Ctrl+C.\n\nSecondary causes worth ruling out:\n\n- **A module you import opens a connection but never closes it** — e.g. a real Redis/Prisma/Mongoose/TypeORM client that doesn't get disconnected. `app.close()` closes the Nest app, but a client not wired to Nest's lifecycle hooks (`onModuleDestroy`/`onApplicationShutdown`) won't be torn down by it.\n- **A background interval or a pending open handle** created outside Nest's lifecycle.\n- **A real external client (e.g. a queue or an HTTP agent keeping the socket alive) leaked in a spec that never calls close.**\n\nThe fix, in order:\n\n1. **Close every app you create.** First line of defense:\n\n```typescript\nlet app: INestApplication;\n\nbeforeAll(async () => {\n const moduleRef = await Test.createTestingModule({ imports: [AppModule] })\n .overrideProvider(UsersRepository)\n .useValue(mockRepo)\n .compile();\n app = moduleRef.createNestApplication();\n await app.init();\n});\n\nafterAll(async () => {\n await app.close();\n});\n```\n\nDo this in **every** e2e spec that boots an app — one spec file leaking is enough to hang the whole run.\n\n2. **Make your providers lifecycle-aware.** If you open a connection in a provider, subscribe to Nest's shutdown hooks:\n\n```typescript\n@Injectable()\nexport class RedisService implements OnModuleDestroy {\n async onModuleDestroy() {\n await this.client.quit();\n }\n}\n```\n\nand ensure the app has shutdown hooks enabled if needed (`app.enableShutdownHooks()`), so `app.close()` actually reaches them.\n\n3. **Confirm it's fixed** by running the suite and checking the process exits on its own (exit code 0, no Ctrl+C). If it still hangs, use `jest --detectOpenHandles` (or Node's `--trace-warnings` / `why-is-node-running`) to see exactly which handle is still open, then close that resource in the relevant `afterAll`.\n\n4. **Don't paper over it** with `--forceExit`. That masks the leak — connections and timers keep accumulating across suite files, which is what turns a slow-but-working suite into a flaky one. Fix the leak instead.\n\nOne quick sanity check before anything else: grep the touched e2e specs for `createNestApplication` and make sure each one has a matching `app.close()`. Missed teardown is by far the most common reason a suite \"finishes\" but never exits.",
798
+ "outputSha256": "60332fb9184120a7d7b9cac331f0bf85eec5044abafbea2fbeebcbffefb8167a",
799
+ "promptSha256": "655f412cc21926b353a12f9371b4a9134abac167fb90b63f526191351dc3297c",
800
+ "deterministic": [],
801
+ "judge": {
802
+ "verdict": "pass",
803
+ "reason": "Answer names missing `await app.close()` after createNestApplication()/init() as likely cause, citing leaked DB connections/sockets, listening socket, and timers. Concrete fix shown: `afterAll(async () => { await app.close(); })` in every e2e spec. It explicitly warns against `--forceExit` (\"Don't paper over it\"), so no fail criterion holds."
804
+ },
805
+ "passed": true
806
+ },
807
+ {
808
+ "output": "The almost-certain cause is that a Nest application booted during the e2e suite was never closed. `createNestApplication()` + `app.init()` opens real resources — the HTTP server's listening socket, pooled DB connections, and any timers/background work a provider started — and if `app.close()` never runs, Jest finishes its tests but the Node process can't exit because those handles are still open. Jest will print the results and then just sit there until you Ctrl+C.\n\nThe usual reasons it's missing:\n\n- A spec calls `createNestApplication()`/`init()` but the `afterAll` (or `afterEach`) that should close it is absent, or only closes on the happy path.\n- `app.close()` is called but not awaited, so the process can still be mid-teardown when Jest decides it's done.\n- Multiple spec files each boot their own app and only some of them close it.\n- `init()` throws partway (e.g. a bad module), so the `beforeAll` rejects before a `close()` handle is ever registered — leaving whatever partially opened.\n\nThe fix:\n\n```typescript\nlet app: INestApplication;\n\nbeforeAll(async () => {\n const moduleRef = await Test.createTestingModule({\n imports: [AppModule],\n }).compile();\n app = moduleRef.createNestApplication();\n await app.init();\n});\n\nafterAll(async () => {\n await app.close(); // must be awaited\n});\n```\n\nPoints that matter:\n\n- **Await `app.close()`.** Without the `await`, teardown can still be in flight when Jest tears down the worker, and depending on your DB driver/timers that can still hold the handle.\n- **Close every app you open.** If a spec file boots the application itself, it owns the `close()`. One `afterAll` per `createNestApplication()`.\n- **Guard the partial-boot case** if `init()` can realistically fail, so you don't leak on the throw path.\n- If you're supplying a testing override that opens its own connection (a real DB instead of a mock), that resource has its own lifecycle and must be torn down too — `app.close()` won't reach a client you constructed outside the Nest container.\n\nTo confirm it's this and not something else, run the suite with `--detectOpenHandles`; it will name the specific handle (a `TCPServerWrap`, a DB socket, a timer) still keeping the loop alive.\n\nOne thing I'd push back on, if it's on the table: if the appeal of skipping teardown is that booting the app is slow, the right move is to share one app across the spec file where it's safe to do so, not to leak it — a leaked process is a hanging CI job, and a later suite mysteriously flaking is usually the same leaked handle from an earlier one.",
809
+ "outputSha256": "9d9eb5021aca7294ba0988e5601156afa7beeec5c6d9b2032a115eb7957f8507",
810
+ "promptSha256": "655f412cc21926b353a12f9371b4a9134abac167fb90b63f526191351dc3297c",
811
+ "deterministic": [],
812
+ "judge": {
813
+ "verdict": "pass",
814
+ "reason": "Answer names missing app.close() after createNestApplication()/app.init() as cause, citing leaked HTTP socket, pooled DB connections, and timers. Concrete fix shown: afterAll(async () => { await app.close(); }) with 'One afterAll per createNestApplication().' No force-exit/process.exit recommendation; it explicitly warns against leaking."
815
+ },
816
+ "passed": true
817
+ },
818
+ {
819
+ "output": "The most likely cause: an e2e spec boots a Nest application with `moduleRef.createNestApplication()` but never calls `app.close()`. `app.init()` opens resources that outlive the test run — DB connection pools, `setInterval`/`setTimeout` timers (e.g. `@nestjs/schedule`, an interceptor, a health-check poller), an opened Redis/AMQP/MQTT client, a listening HTTP server — and Node's event loop stays alive as long as anything is still scheduled. The test assertions all pass and the runner reports success, but the process won't exit because there's still a live handle. Ctrl+C is you killing that leftover handle manually.\n\nThe fix is to close the app in a teardown hook so every resource registered on that application is released:\n\n```typescript\nlet app: INestApplication;\n\nbeforeAll(async () => {\n const moduleRef = await Test.createTestingModule({\n imports: [AppModule],\n }).compile();\n\n app = moduleRef.createNestApplication();\n await app.init();\n});\n\nafterAll(async () => {\n await app.close(); // releases DB pools, timers, open clients, the server\n});\n```\n\n`app.close()` triggers Nest's lifecycle hooks (`onModuleDestroy`, `beforeApplicationShutdown`, `onApplicationShutdown`) across the graph, which is what actually closes those pools and clears those timers. Without it, injectable `OnModuleDestroy` handlers never run.\n\nA few things to check so the fix is complete:\n\n- **Every** e2e spec that calls `createNestApplication()` needs its own `await app.close()` — not just the first one. A single spec missing it is enough to hang the whole run.\n- If you use `supertest` without `app.init()` on a real listening port, that's usually fine, but if you explicitly `await app.listen(...)`, close will not always release a server you started outside the app; prefer driving `app.getHttpServer()` via supertest and letting `app.close()` handle teardown.\n- If the app pulls in a module with a long-lived connection created OUTSIDE Nest's lifecycle (a raw `new MongoClient()` in a factory that doesn't implement `OnModuleDestroy`), closing the app won't release it. That's a source fix: make the provider implement `OnModuleDestroy` and close the client, or register it with `app.enableShutdownHooks()` where appropriate.\n- Verify by running the suite and confirming the process exits on its own — if it still hangs, bisect by file to find the spec that never closes.\n\nSo: the right fix is the missing `await app.close()` in `afterAll` of every e2e spec that boots a Nest app — don't paper over it with a forced-exit flag or a `--forceExit`, which just hides the leaked handle.",
820
+ "outputSha256": "324593c574d4b9dd4a2f58b434b5775bac635cec1ffb7d3b23bf22e453726f82",
821
+ "promptSha256": "655f412cc21926b353a12f9371b4a9134abac167fb90b63f526191351dc3297c",
822
+ "deterministic": [],
823
+ "judge": {
824
+ "verdict": "pass",
825
+ "reason": "Answer names missing app.close() after createNestApplication()/app.init() as cause, citing leaked DB pools, timers, clients, server. Concrete fix shown: `await app.close()` in afterAll, and states every e2e spec needs its own close. Explicitly rejects --forceExit/forced-exit as hiding the leak, so no fail criterion holds."
826
+ },
827
+ "passed": true
828
+ },
829
+ {
830
+ "output": "# NestJS e2e suite hangs after finishing\n\nThe near-certain cause: you booted a Nest application (or the underlying resources it opened) and never tore it down. Jest reports the suite as passing, but the Node process won't exit because something it opened is still alive and holding the event loop open.\n\n## What's actually holding it open\n\n`Test.createTestingModule(...).compile()` builds the DI container, but in an e2e spec you then call `moduleRef.createNestApplication()` and `await app.init()`. That spins up a real HTTP server, and often via imported modules it also opens:\n\n- **A listening HTTP server** (`app.getHttpServer()`) — an open server handle keeps the event loop referenced.\n- **Database connection pools** (TypeORM `DataSource`, Prisma client, Mongoose) — open sockets/timers stay referenced.\n- **Timers and intervals** registered by providers that started during `init()`.\n\n`app.close()` is what fires `onModuleDestroy`/`onApplicationShutdown`, stops the HTTP server, and closes those pools. Without it, none of that happens and the process sits there until you Ctrl+C.\n\nA second, less common cause: you *do* call `app.close()`, but in the wrong place or on the wrong instance — e.g. closing inside a single `it()` while other tests in the file still hold the app, or calling it on a fresh reference rather than the one you init'd.\n\n## The fix\n\nClose the app in an `afterAll` that runs once the whole file is done, and make sure it's the same instance you initialized:\n\n```typescript\ndescribe('Users (e2e)', () => {\n let app: INestApplication;\n\n beforeAll(async () => {\n const moduleRef = await Test.createTestingModule({\n imports: [AppModule],\n }).compile();\n\n app = moduleRef.createNestApplication();\n await app.init();\n });\n\n afterAll(async () => {\n await app.close();\n });\n\n it('GET /users', async () => {\n await request(app.getHttpServer()).get('/users').expect(200);\n });\n});\n```\n\nKey points:\n\n- **`afterAll`, not `afterEach`** — you booted the app once in `beforeAll`, so close it once. (If you boot per-test, close per-test in `afterEach`; just keep the pairing symmetric.)\n- **`await` the `close()`** — it's asynchronous; an un-awaited call returns before teardown completes and the handle can still be open when the process tries to exit.\n- **Same `app` reference** in both hooks — don't re-create it.\n\n## Verifying it's fixed\n\nRun `jest --detectOpenHandles` (or your project's e2e script with that flag) before and after. It will name the exact handle being leaked — typically a `TCPServerWrap` or a DB socket — which both confirms the diagnosis and proves the fix closed it. A clean run exits on its own without Ctrl+C.\n\n## If it still hangs after adding `close()`\n\nThen the leaked handle isn't the Nest app/server itself. Check, in order:\n\n1. **A provider owning a resource Nest doesn't know how to close** — e.g. a long-lived `setInterval`, a message-queue consumer, or an HTTP client with keep-alive. That provider needs its own `onModuleDestroy` to clear the timer / disconnect, so `app.close()` can propagate to it.\n2. **A DB client created outside DI** — if the test or a module instantiates Prisma/DataSource directly rather than through a provider, `app.close()` won't touch it; close it explicitly in `afterAll`.\n3. **`jest --forceExit` masking it** — if someone added `--forceExit` to get green, remove it. It hides this exact leak; find and close the real handle instead.\n\nDon't \"fix\" the hang by adding `--forceExit` or `--detectOpenHandles`-only flags — those silence the symptom while the leaked connection or timer stays open across runs.",
831
+ "outputSha256": "be600e0ba5e8f9c21e77d46a3450a55e97ad02e44b6764136700a38574b49a9e",
832
+ "promptSha256": "655f412cc21926b353a12f9371b4a9134abac167fb90b63f526191351dc3297c",
833
+ "deterministic": [],
834
+ "judge": {
835
+ "verdict": "pass",
836
+ "reason": "Answer names missing app.close() after createNestApplication()/app.init() as cause, citing leaked HTTP server, DB pools, timers (\"Database connection pools... Timers and intervals\"). Fix shown concretely: afterAll(async () => { await app.close(); }) with full code. Explicitly warns against --forceExit, not recommending it. Both pass criteria met, no fail criterion."
837
+ },
838
+ "passed": true
839
+ },
840
+ {
841
+ "output": "The likely cause is an open resource that Node's event loop is still holding onto after your specs finish, so Jest never sees a reason to exit. In a NestJS e2e suite the usual culprits, in rough order of likelihood:\n\n1. **The Nest app was never closed.** If a spec boots the app with `createNestApplication()` (or `NestFactory.create()`) but doesn't `await app.close()`, the underlying HTTP server, the DI container, and anything the app started (cron jobs, intervals, DB connections, message-broker clients) stay alive. Even one spec that forgets this hangs the whole run.\n2. **A TypeORM/Prisma/Mongoose/Redis/bull connection opened via the app or a module was never torn down** — same root cause, just one level down from `app.close()`.\n3. **A test double or source code leaked a timer or socket** — a `setInterval` in a provider (health check, poller), an unclosed `supertest` agent, a WebSocket, or a `setTimeout` with no `clearTimeout`.\n4. **A real server was left listening** because the spec did `app.listen(port)` instead of `app.init()` + `request(app.getHttpServer())`.\n\n**The right fix:** make teardown explicit and complete in every e2e spec file that boots an app.\n\n```typescript\nimport { INestApplication } from '@nestjs/common';\nimport { Test } from '@nestjs/testing';\nimport * as request from 'supertest';\n\ndescribe('Users (e2e)', () => {\n let app: INestApplication;\n\n beforeAll(async () => {\n const moduleRef = await Test.createTestingModule({\n imports: [AppModule],\n }).compile();\n\n app = moduleRef.createNestApplication();\n await app.init();\n });\n\n afterAll(async () => {\n await app.close(); // releases HTTP server, DI container, DB/timers\n });\n\n it('/users (GET)', () => {\n return request(app.getHttpServer()).get('/users').expect(200);\n });\n});\n```\n\nKey points:\n\n- `await app.close()` in `afterAll`, and make the `afterAll` itself `async` and awaited.\n- Use `app.init()` (not `app.listen()`); drive requests through `app.getHttpServer()` with supertest so nothing binds a fixed port.\n- If any provider starts a timer, interval, or external client, close/disconnect it too — often via `app.close()` if it hooks `onModuleDestroy`, otherwise explicitly in `afterAll`.\n- If a standalone connection (TypeORM `DataSource`, Redis client) is created outside the app, close it in `afterAll` as well.\n\n**To confirm the diagnosis** rather than guess, run Jest with open-handle detection:\n\n```bash\nnpx jest --config ./test/jest-e2e.json --detectOpenHandles --runInBand\n```\n\n`--detectOpenHandles` will name the resource keeping the loop alive (a TCP handle, a timer, a DB socket), which tells you whether it's a missing `app.close()`, a leaked timer, or an unclosed connection. `--runInBand` also removes shared-worker confounds. A quick secondary check: `npx why-is-node-running` or calling `process.exit()` is a **workaround, not a fix** — it masks the leak and can cut off in-flight async cleanup, so don't ship it as the solution.\n\nOne caveat: `--forceExit` (or `--detectOpenHandles` left on permanently in CI) will make the hang \"go away\" without addressing it. Treat a clean exit without `--forceExit` as the acceptance criterion for this fix.",
842
+ "outputSha256": "458107a640f5ef56824fa29ae23373b7d619847c2392910955f3c18481cf2d76",
843
+ "promptSha256": "655f412cc21926b353a12f9371b4a9134abac167fb90b63f526191351dc3297c",
844
+ "deterministic": [],
845
+ "judge": {
846
+ "verdict": "pass",
847
+ "reason": "Answer names missing app.close() after createNestApplication()/app.init() as likely cause, citing leaked HTTP server, DI container, DB connections, timers (points 1-3). Concrete fix shown: async afterAll with await app.close() in code sample, plus 'in every e2e spec file that boots an app'. Explicitly rejects process.exit/--forceExit as workaround, not fix."
848
+ },
849
+ "passed": true
850
+ },
851
+ {
852
+ "output": "The most likely cause: you're calling `createNestApplication()` in an e2e spec but never tearing it down with `app.close()`. Each booted app opens resources the test runner doesn't own -- DB connection pools, HTTP listeners/sockets, `setInterval` timers, and (with `@nestjs/schedule`) cron registrations -- so even though Jest reports every test as passed, the Node event loop still has live handles and the process never exits on its own.\n\nThe fix, in the spec that boots the app:\n\n```typescript\ndescribe('Users (e2e)', () => {\n let app: INestApplication;\n\n beforeAll(async () => {\n const moduleRef = await Test.createTestingModule({\n imports: [AppModule],\n }).compile();\n app = moduleRef.createNestApplication();\n await app.init();\n });\n\n afterAll(async () => {\n await app.close(); // <-- this is what's missing\n });\n\n it('GET /users', () =>\n request(app.getHttpServer()).get('/users').expect(200));\n});\n```\n\nPut the `close()` in `afterAll`, not `afterEach` -- `beforeAll`/`afterAll` boots the app once for the whole file, so tearing it down once matches.\n\nIf `afterAll` is already there and it still hangs, check in this order:\n\n1. **A failed `beforeAll`** that threw before `app` was assigned, so `afterAll` runs with `app === undefined` and `app.close()` throws or no-ops. Guard it: `await app?.close()`.\n2. **`app.listen()` instead of `app.init()`** somewhere in the suite -- an actual listening socket that `close()` may not reap cleanly. For supertest you only need `app.init()`; `supertest` drives `app.getHttpServer()` directly without binding a port.\n3. **A provider holding a handle the app doesn't own** -- a Redis/AMQP client created outside Nest's lifecycle, or an `onModuleInit` that opened something without a matching `onModuleDestroy`. `app.close()` triggers Nest's own `onModuleDestroy`/`beforeApplicationShutdown` hooks, so those providers need to actually implement them.\n4. **A `setInterval`/`setTimeout`** in test code or a service that isn't cleared. `--detectOpenHandles` on the Jest run names the culprit:\n\n```bash\nnpx jest --config ./test/jest-e2e.json --detectOpenHandles\n```\n\nThat flag reports the live handle keeping the loop open (a `TCPSERVERWRAP`, `Timeout`, etc.), which tells you whether it's #1/#2 (the app/socket) or #3/#4 (a provider's own resource).\n\nOne caveat: adding `--forceExit` or `--detectOpenHandles` as a permanent config fix is a workaround, not the fix. `--forceExit` masks the leak -- the next suite that depends on a DB connection being released cleanly will flake instead. Use it only to confirm the diagnosis, then add the real `afterAll(() => app.close())` and any missing provider destroy hooks.",
853
+ "outputSha256": "451a8514a5659663a58a11b59a9a053596a77412f0a283a6c826cc9714e69c60",
854
+ "promptSha256": "655f412cc21926b353a12f9371b4a9134abac167fb90b63f526191351dc3297c",
855
+ "deterministic": [],
856
+ "judge": {
857
+ "verdict": "pass",
858
+ "reason": "Answer names missing app.close() after createNestApplication()/app.init() as cause, citing leaked DB pools, sockets, setInterval timers, cron. Concrete fix shown: afterAll(async () => { await app.close(); }) in the spec. It explicitly warns --forceExit is a workaround, not the fix, so no fail criterion holds."
859
+ },
860
+ "passed": true
861
+ }
862
+ ]
863
+ }
864
+ ],
865
+ "verdict": "pass",
866
+ "scope": "bundled",
867
+ "skillDigest": "3f820770bca835e75aacc0e6087c39707e152ff6c882a2798fd2b36d5f38f4ee",
868
+ "catalogDigest": "139cc7e7c63f9a3fcb3560551b7740c5642c828db2570e2f40728089218cc6d4",
869
+ "judgePromptVersion": "2026-09-25.1",
870
+ "runner": "deepseek",
871
+ "model": "deepseek-chat",
872
+ "runnerPromptVersion": "2026-09-25.1",
873
+ "recordedAt": "2026-09-25T14:55:55.639Z",
874
+ "judge": "deepseek",
875
+ "judgeModel": "deepseek-chat"
876
+ },
877
+ {
878
+ "schemaVersion": "1.0.0",
879
+ "skillId": "nestjs/nestjs-build-fix",
880
+ "strictness": "high",
881
+ "trials": 10,
882
+ "triggerAccuracy": {
883
+ "truePositive": 6,
884
+ "falsePositive": 0,
885
+ "positives": 6,
886
+ "negatives": 6
887
+ },
888
+ "evidence": "authored",
889
+ "scenarios": [
890
+ {
891
+ "id": "trigger-positive-1",
892
+ "kind": "trigger-positive",
893
+ "prompt": "Nest can't resolve dependencies of OrdersService, help me fix this",
894
+ "strictness": "high",
895
+ "trials": 1,
896
+ "passes": 1,
897
+ "passRate": 1,
898
+ "passAtK": 1,
899
+ "grader": "trigger-rank-fork-family",
900
+ "status": "ran",
901
+ "deterministic": true
902
+ },
903
+ {
904
+ "id": "trigger-positive-2",
905
+ "kind": "trigger-positive",
906
+ "prompt": "Our NestJS app crashes at bootstrap with a dependency-injection stack trace naming OrdersService's constructor -- Nest cannot resolve it.",
907
+ "strictness": "high",
908
+ "trials": 1,
909
+ "passes": 1,
910
+ "passRate": 1,
911
+ "passAtK": 1,
912
+ "grader": "trigger-rank-fork-family",
913
+ "status": "ran",
914
+ "deterministic": true
915
+ },
916
+ {
917
+ "id": "trigger-positive-3",
918
+ "kind": "trigger-positive",
919
+ "prompt": "There's a circular dependency warning between UsersModule and AuthModule",
920
+ "strictness": "high",
921
+ "trials": 1,
922
+ "passes": 1,
923
+ "passRate": 1,
924
+ "passAtK": 1,
925
+ "grader": "trigger-rank-fork-family",
926
+ "status": "ran",
927
+ "deterministic": true
928
+ },
929
+ {
930
+ "id": "trigger-positive-4",
931
+ "kind": "trigger-positive",
932
+ "prompt": "Something in OrdersService's constructor keeps our NestJS app from finishing bootstrap -- Nest reports it cannot resolve the dependency.",
933
+ "strictness": "high",
934
+ "trials": 1,
935
+ "passes": 1,
936
+ "passRate": 1,
937
+ "passAtK": 1,
938
+ "grader": "trigger-rank-fork-family",
939
+ "status": "ran",
940
+ "deterministic": true
941
+ },
942
+ {
943
+ "id": "trigger-positive-5",
944
+ "kind": "trigger-positive",
945
+ "prompt": "Our NestJS app cannot bootstrap because Nest cannot resolve a dependency OrdersService needs -- what does the DI error at constructor index [2] actually mean?",
946
+ "strictness": "high",
947
+ "trials": 1,
948
+ "passes": 1,
949
+ "passRate": 1,
950
+ "passAtK": 1,
951
+ "grader": "trigger-rank-fork-family",
952
+ "status": "ran",
953
+ "deterministic": true
954
+ },
955
+ {
956
+ "id": "trigger-positive-6",
957
+ "kind": "trigger-positive",
958
+ "prompt": "Fix this NestJS build error that's blocking npm run start:dev",
959
+ "strictness": "high",
960
+ "trials": 1,
961
+ "passes": 1,
962
+ "passRate": 1,
963
+ "passAtK": 1,
964
+ "grader": "trigger-rank-fork-family",
965
+ "status": "ran",
966
+ "deterministic": true
967
+ },
968
+ {
969
+ "id": "trigger-negative-1",
970
+ "kind": "trigger-negative",
971
+ "prompt": "Write unit tests for UsersService using @nestjs/testing with a mocked repository",
972
+ "strictness": "high",
973
+ "trials": 1,
974
+ "passes": 1,
975
+ "passRate": 1,
976
+ "passAtK": 1,
977
+ "grader": "trigger-rank-fork-family",
978
+ "status": "ran",
979
+ "deterministic": true
980
+ },
981
+ {
982
+ "id": "trigger-negative-2",
983
+ "kind": "trigger-negative",
984
+ "prompt": "Add a new NestJS module for the invoices feature with a controller and service",
985
+ "strictness": "high",
986
+ "trials": 1,
987
+ "passes": 1,
988
+ "passRate": 1,
989
+ "passAtK": 1,
990
+ "grader": "trigger-rank-fork-family",
991
+ "status": "ran",
992
+ "deterministic": true
993
+ },
994
+ {
995
+ "id": "trigger-negative-3",
996
+ "kind": "trigger-negative",
997
+ "prompt": "Fix this plain tsc error: Type 'string' is not assignable to type 'number' in a Node script",
998
+ "strictness": "high",
999
+ "trials": 1,
1000
+ "passes": 1,
1001
+ "passRate": 1,
1002
+ "passAtK": 1,
1003
+ "grader": "trigger-rank-fork-family",
1004
+ "status": "ran",
1005
+ "deterministic": true
1006
+ },
1007
+ {
1008
+ "id": "trigger-negative-4",
1009
+ "kind": "trigger-negative",
1010
+ "prompt": "Review this NestJS PR for missing DTO validation and N+1 queries",
1011
+ "strictness": "high",
1012
+ "trials": 1,
1013
+ "passes": 1,
1014
+ "passRate": 1,
1015
+ "passAtK": 1,
1016
+ "grader": "trigger-rank-fork-family",
1017
+ "status": "ran",
1018
+ "deterministic": true
1019
+ },
1020
+ {
1021
+ "id": "trigger-negative-5",
1022
+ "kind": "trigger-negative",
1023
+ "prompt": "go vet ./... is failing on this package, help resolve the compile error",
1024
+ "strictness": "high",
1025
+ "trials": 1,
1026
+ "passes": 1,
1027
+ "passRate": 1,
1028
+ "passAtK": 1,
1029
+ "grader": "trigger-rank-fork-family",
1030
+ "status": "ran",
1031
+ "deterministic": true
1032
+ },
1033
+ {
1034
+ "id": "trigger-negative-6",
1035
+ "kind": "trigger-negative",
1036
+ "prompt": "Fix this Angular AOT compile error about an unresolved template reference",
1037
+ "strictness": "high",
1038
+ "trials": 1,
1039
+ "passes": 1,
1040
+ "passRate": 1,
1041
+ "passAtK": 1,
1042
+ "grader": "trigger-rank-fork-family",
1043
+ "status": "ran",
1044
+ "deterministic": true
1045
+ },
1046
+ {
1047
+ "id": "missing-export-not-import-alone",
1048
+ "kind": "behavior",
1049
+ "prompt": "OrdersService injects PricingService and Nest throws an UnknownDependenciesException naming OrdersService at bootstrap. I already added PricingModule to OrdersModule's imports array, but it's still failing. What am I missing?",
1050
+ "strictness": "high",
1051
+ "trials": 10,
1052
+ "passes": 10,
1053
+ "passRate": 1,
1054
+ "passAtK": 1,
1055
+ "grader": "judge",
1056
+ "status": "ran",
1057
+ "trialRecords": [
1058
+ {
1059
+ "output": "The import alone doesn't fix it. Adding PricingModule to OrdersModule's `imports` only makes *exported* providers from PricingModule visible to OrdersModule — if PricingService isn't in PricingModule's `exports` array, the import does nothing for the resolution.\n\nCheck `pricing.module.ts`:\n\n```ts\n@Module({\n providers: [PricingService],\n exports: [PricingService], // <-- is this here?\n})\nexport class PricingModule {}\n```\n\nIf `exports` is missing (or doesn't list PricingService), that's your root cause. Add PricingService to that array — that's the smallest correct fix.\n\nDo **not**:\n\n- Re-declare PricingService in OrdersModule's own `providers` array. That creates a second, separate instance instead of the one shared provider PricingModule owns; any state or side effects on PricingService will diverge silently.\n- Leave it as \"imports only\" and assume it should work — an import with no matching export is exactly the failure you're seeing.\n\nAlso confirm two adjacent traps while you're in there:\n\n- `PricingService` itself must carry `@Injectable()`. If the class is undecorated, Nest can't construct it even after it's properly exported, and you'll get the same exception shape.\n- The export needs to name the same token the constructor injects. If OrdersService injects a custom token (e.g. `@Inject('PRICING_SERVICE')`), PricingModule must export a provider under that exact token, not the class.\n\nAfter the fix, verify by actually booting (`npm run start:dev` or the project's equivalent) — `tsc --noEmit` can pass while the app still fails at bootstrap. The startup log should show no `UnknownDependenciesException`.\n\nRoot cause to report: PricingService was declared in PricingModule's `providers` but not its `exports`; OrdersModule's new import couldn't see it. Fix: added it to `exports`.",
1060
+ "outputSha256": "a9635db0b7142e36e5e9a082c4a34739a1652230d0c40ca45cffb0c8b4934920",
1061
+ "promptSha256": "c5365b0fa21a740f327dbc4042562266b9c43a766235ce75dcc8cc8207cf497c",
1062
+ "deterministic": [],
1063
+ "judge": {
1064
+ "verdict": "pass",
1065
+ "reason": "Answer states import only makes exported providers visible and 'if PricingService isn't in PricingModule's exports array, the import does nothing' (crit 1). Concrete fix shown: exports: [PricingService] in PricingModule, 'Add PricingService to that array' (crit 2). It explicitly warns against re-declaring in OrdersModule providers, so no fail criterion holds."
1066
+ },
1067
+ "passed": true
1068
+ },
1069
+ {
1070
+ "output": "The most likely thing you're missing: **`PricingModule` doesn't export `PricingService`.** Adding a module to `imports` only makes that module's *exported* providers available — a provider that's declared in `PricingModule.providers` but not listed in `PricingModule.exports` is invisible to every module that imports it.\n\nSo check `PricingModule`:\n\n```ts\n@Module({\n providers: [PricingService],\n exports: [PricingService], // <-- is this line present?\n})\nexport class PricingModule {}\n```\n\nIf `exports` is missing or doesn't include `PricingService`, the import you added does nothing and you'll get the exact same `UnknownDependenciesException`. Add it:\n\n```ts\nexports: [PricingService],\n```\n\nThen confirm the app actually boots (`npm run start:dev`), not just that `tsc --noEmit` passes, since this failure only surfaces at bootstrap.\n\nA few other things worth ruling out while you're in there, in order of likelihood:\n\n1. **`PricingService` is missing `@Injectable()`.** If the class has no decorator, Nest can't construct it via DI at all, and the error often surfaces on the *consumer* (`OrdersService`) rather than the provider itself. Check the class definition directly.\n2. **`PricingModule` is in `imports` but references a provider from yet another module it doesn't itself import/export transitively.** If `PricingService`'s own constructor injects something that isn't resolvable, the failure can still bisect back to `OrdersService` in the message. Read the exact constructor argument index Nest names.\n3. **You edited the wrong module file**, or there are two `PricingModule`-like modules (e.g. a shared/core variant) and you imported the one that doesn't own the provider you actually need.\n\nTwo anti-patterns to avoid here, both of which are tempting given \"the import didn't work\":\n\n- **Don't re-declare `PricingService` in `OrdersModule.providers`** as a workaround. That creates a second, independent instance of the provider instead of sharing the one `PricingModule` owns — state and side effects diverge silently.\n- **Don't add more modules to `imports` hoping one of them exports it.** An import with no matching export never fixes this.\n\nThe fix is a one-liner in `PricingModule.exports` once you've confirmed the export (or the decorator) is what's actually absent. Report the root cause as \"missing export\" rather than the import you already added, and keep the change confined to `PricingModule`.",
1071
+ "outputSha256": "ea7acc0c77f9f28fb92a236e7f2cafda5f0c1c686f38d829a591d3e3ebf8fd3d",
1072
+ "promptSha256": "c5365b0fa21a740f327dbc4042562266b9c43a766235ce75dcc8cc8207cf497c",
1073
+ "deterministic": [],
1074
+ "judge": {
1075
+ "verdict": "pass",
1076
+ "reason": "Answer states imports only expose exported providers ('a provider declared in PricingModule.providers but not listed in PricingModule.exports is invisible'), and names the concrete fix: add PricingService to PricingModule's exports array (exports: [PricingService]). It explicitly warns against re-declaring PricingService in OrdersModule.providers, so no fail criterion holds."
1077
+ },
1078
+ "passed": true
1079
+ },
1080
+ {
1081
+ "output": "What you're missing is the **export** on the other side. Adding `PricingModule` to `OrdersModule`'s `imports` array only makes providers *available* to `OrdersModule` if `PricingModule` actually lists them in its own `exports` array. An import with no matching export changes nothing — Nest finds no `PricingService` to hand to `OrdersService`, so it throws the exact same `UnknownDependenciesException` at the exact same point.\n\nCheck these, in order:\n\n1. **Does `PricingModule` export `PricingService`?** Open `pricing.module.ts` and look at the `exports` array. If `PricingService` is only in `providers` and not in `exports`, that's your bug. Fix it there:\n\n ```ts\n @Module({\n providers: [PricingService],\n exports: [PricingService], // <-- the missing line\n })\n export class PricingModule {}\n ```\n\n2. **Is `PricingService` decorated with `@Injectable()`?** A class with no decorator can be listed in `providers` and still fail to resolve — Nest can't construct it through DI. Check the class declaration directly.\n\n3. **Is the import actually where Nest is looking?** Confirm the `imports` array you edited is on the module that declares `OrdersService` in its `providers` — a `PricingModule` import added to some other module (or to `AppModule`) won't help `OrdersService`.\n\n4. **Is there a second `PricingModule` or a path aliasing issue** importing a different module than the one you think you edited? Rare, but worth a glance if the first three check out.\n\nThe most likely culprit by far is #1. A missing `exports` entry is the classic reason \"I added the import and it still fails\" — the import was never the missing piece; the export was.\n\nOne thing **not** to do as a workaround: don't re-declare `PricingService` in `OrdersModule`'s own `providers` array. That constructs a second, separate instance of what the codebase intends to be a single shared provider, and any state or side effects inside it will silently diverge between the two. Fix the export instead.\n\nAfter fixing, verify by actually booting the app (`npm run start:dev` or the project's start script), not just `tsc --noEmit` — Nest DI failures frequently don't surface until bootstrap, so a clean type-check proves nothing here.",
1082
+ "outputSha256": "b9be048c09107f959be2e44bd7462f731abcfe69b3d8b5a7cb415eda83e8cfa3",
1083
+ "promptSha256": "c5365b0fa21a740f327dbc4042562266b9c43a766235ce75dcc8cc8207cf497c",
1084
+ "deterministic": [],
1085
+ "judge": {
1086
+ "verdict": "pass",
1087
+ "reason": "Answer states import only works if PricingModule exports PricingService ('An import with no matching export changes nothing') and names the concrete fix: adding 'exports: [PricingService]' to PricingModule's @Module. It also explicitly warns against re-declaring PricingService in OrdersModule's providers, so no fail criterion holds."
1088
+ },
1089
+ "passed": true
1090
+ },
1091
+ {
1092
+ "output": "You're missing the other half of cross-module DI: adding `PricingModule` to `OrdersModule`'s `imports` only gives `OrdersModule` *visibility* into what `PricingModule` **exports**. If `PricingService` is only listed in `PricingModule`'s `providers` array and not in its `exports` array, the import does nothing for this error — Nest can still see `PricingService` doesn't exist anywhere reachable from `OrdersService`.\n\nThe failure shape confirms it: `UnknownDependenciesException` naming `OrdersService`, with the consumer-side import already correct, means the gap is on the *provider* side, not the consumer side.\n\nCheck, in `pricing.module.ts`:\n\n```ts\n@Module({\n providers: [PricingService],\n exports: [PricingService], // <-- likely missing this line\n})\nexport class PricingModule {}\n```\n\nFix: add `PricingService` to `PricingModule`'s `exports` array. Then `PricingModule` needs to be in `OrdersModule`'s `imports` (which you already did), and `OrdersService`'s constructor injection resolves.\n\nOne thing to double-check while you're in there: confirm `PricingService` carries `@Injectable()`. If the class has no decorator at all, adding it to `exports` still won't let Nest construct it — a missing `@Injectable()` produces the same \"can't resolve dependencies\" surface. But given you've already correctly ruled out the consumer side, the missing `exports` entry is the overwhelmingly likely cause.\n\nDo **not** fix this by re-declaring `PricingService` inside `OrdersModule`'s own `providers` array. That makes the error go away but creates a second, independent instance of `PricingService` — any state or side effects it holds diverge silently between the two modules. The `exports` entry is the correct, single-instance fix.\n\nAfter the change, verify by running the actual start command (`npm run start:dev`), not just `tsc --noEmit` — DI errors surface at bootstrap, and a clean type-check tells you nothing about whether the graph resolves. Confirm the startup log is free of any `UnknownDependenciesException` or circular-dependency warning.",
1093
+ "outputSha256": "7b2f8e7a84c61b7b404a9ae0a8b7b82e9843b9f9132c7cf6e785e02b3c30b13d",
1094
+ "promptSha256": "c5365b0fa21a740f327dbc4042562266b9c43a766235ce75dcc8cc8207cf497c",
1095
+ "deterministic": [],
1096
+ "judge": {
1097
+ "verdict": "pass",
1098
+ "reason": "Answer states imports only give visibility into what PricingModule exports, and if PricingService is only in providers not exports the import does nothing (criterion 1). Concrete fix shown: 'exports: [PricingService]' in pricing.module.ts and 'add PricingService to PricingModule's exports array' (criterion 2). It explicitly warns against re-declaring in OrdersModule providers, so no fail criterion holds."
1099
+ },
1100
+ "passed": true
1101
+ },
1102
+ {
1103
+ "output": "You're most likely missing the **export**. Adding `PricingModule` to `OrdersModule`'s `imports` array only makes *what PricingModule exports* visible to OrdersModule. If `PricingService` is listed in `PricingModule`'s `providers` array but **not** in its `exports` array, the import does nothing for resolution — Nest can see the module, but the provider is still private to it, so `OrdersService`'s constructor injection still fails with the same `UnknownDependenciesException`.\n\nCheck, in order:\n\n1. **`PricingModule` does not export `PricingService`.** This is the classic case. Open `pricing.module.ts` and confirm `exports: [PricingService]`. If it's missing, that's your fix — add it there.\n\n2. **The class is correctly decorated.** `PricingService` needs `@Injectable()` on the class itself. A class with no decorator that's still used as a provider or injected elsewhere produces the same \"can't resolve dependencies\" shape.\n\n3. **It's the right symbol.** If `PricingService` is behind an interface/token or a barrel-file re-export, make sure the exact same class/token is what's exported and what's injected, not a duplicate copy from a second path.\n\n4. **No accidental second declaration.** If someone re-declared `PricingService` in `OrdersModule`'s own `providers` array to \"work around\" it, that creates a second instance and doesn't fix the original resolution either — remove it and fix the export instead.\n\nThe correct fix is almost always a one-line change in `PricingModule`:\n\n```ts\n@Module({\n providers: [PricingService],\n exports: [PricingService], // <-- this is what's missing\n})\nexport class PricingModule {}\n```\n\nDo **not** fix this by re-declaring `PricingService` inside `OrdersModule`'s providers — that silently creates two separate instances of what should be one shared provider.\n\nVerify by actually booting the app (`npm run start:dev`), not just `tsc --noEmit` — the DI error only surfaces at bootstrap.",
1104
+ "outputSha256": "da11377152c7375f90f53298888b0bf2d394c765a6f08a712e3a27c416f3d679",
1105
+ "promptSha256": "c5365b0fa21a740f327dbc4042562266b9c43a766235ce75dcc8cc8207cf497c",
1106
+ "deterministic": [],
1107
+ "judge": {
1108
+ "verdict": "pass",
1109
+ "reason": "Answer states imports only make what PricingModule exports visible, and if PricingService is in providers but not exports the import does nothing for resolution (criterion 1). Concrete fix shown: exports: [PricingService] in PricingModule (criterion 2). It explicitly warns against re-declaring PricingService in OrdersModule's providers, so no fail criterion holds."
1110
+ },
1111
+ "passed": true
1112
+ },
1113
+ {
1114
+ "output": "The import alone isn't enough — and the error still naming OrdersService tells you exactly why.\n\n**What you're missing: `PricingModule` almost certainly doesn't `export` `PricingService`.**\n\nAdding `PricingModule` to `OrdersModule`'s `imports` array only makes PricingModule's *exported* providers visible to OrdersModule. Nest resolves `PricingService` for OrdersService only if:\n\n1. `PricingModule` is in `OrdersModule`'s `imports` array ✅ (you did this)\n2. **`PaymentService` is listed in `PricingModule`'s `exports` array** ❌ (the missing half)\n3. `PricingService` is decorated with `@Injectable()`\n\nA common cause: `PricingService` is declared in `PricingModule`'s own `providers` array but `PricingModule` never lists it in `exports`. Importing a module does **not** auto-export its providers — providers are private to their module unless explicitly re-exported.\n\n**The fix** — in `pricing.module.ts`:\n\n```ts\n@Module({\n providers: [PricingService],\n exports: [PricingService], // <-- add this\n})\nexport class PricingModule {}\n```\n\n**Do NOT** instead re-declare `PricingService` inside `OrdersModule`'s own `providers` array. That compiles and makes the error go away, but it creates a *second, separate instance* of `PricingService` — so anything PricingService holds as state (caches, counters, in-memory data, injected config) will silently diverge between the two copies. That's a much nastier bug than the startup failure you're looking at.\n\n**Verify by check order:**\n1. Is `PricingService` in `PricingModule`'s `providers`? (if not, that's the gap)\n2. Is it in `PricingModule`'s `exports`? (this is your missing piece)\n3. Does `PricingService` have `@Injectable()`? (check this too — same failure shape)\n4. Is `PricingModule` in `OrdersModule`'s `imports`? (done)\n\nThen confirm by actually booting the app (`npm run start:dev`), not just `tsc --noEmit` — DI errors only surface at bootstrap.\n\nOne edge case worth ruling out: if you're *also* seeing a circular-dependency warning mentioning OrdersModule/PricingModule, then the export fix plus `forwardRef(() => PricingModule)` on **both** sides is needed. But from your description (a plain UnknownDependenciesException naming OrdersService, no mention of a cycle), the missing `exports` entry is the answer.",
1115
+ "outputSha256": "d73b0e8e8a2b0d60fc50e95721db72e83fad3c2eea5ccd64cf95e034b743003b",
1116
+ "promptSha256": "c5365b0fa21a740f327dbc4042562266b9c43a766235ce75dcc8cc8207cf497c",
1117
+ "deterministic": [],
1118
+ "judge": {
1119
+ "verdict": "pass",
1120
+ "reason": "Answer states importing PricingModule only exposes its exported providers ('only makes PricingModule's exported providers visible'), and gives the concrete fix: 'exports: [PricingService]' in pricing.module.ts. It also explicitly warns against re-declaring PricingService in OrdersModule's providers, noting it creates a second instance. Minor typo 'PaymentService' in one bullet, but the fix and reasoning are correct."
1121
+ },
1122
+ "passed": true
1123
+ },
1124
+ {
1125
+ "output": "You're likely missing the matching `exports` entry. Adding `PricingModule` to `OrdersModule`'s `imports` array only makes whatever `PricingModule` **exports** visible to `OrdersModule`. It does not automatically expose everything in `PricingModule`'s own `providers` array. If `PricingService` is listed in `PricingModule.providers` but absent from `PricingModule.exports`, `OrdersService` still can't see it, and you get the same `UnknownDependenciesException` naming `OrdersService` — exactly the shape you're describing.\n\nSo the thing to check, in this order:\n\n1. Open `pricing.module.ts` and look at the `exports` array. If `PricingService` is not there, that's your root cause. Add it: `exports: [PricingService]`.\n2. Confirm `PricingService` is actually in `PricingModule`'s `providers` array (it has to be declared as a provider somewhere to be exportable).\n3. Confirm the class `PricingService` carries `@Injectable()`. A class with no decorator fails DI even when the module wiring looks correct on paper.\n\nThe fix is normally one line — adding `PricingService` to `PricingModule.exports` — not another import in `OrdersModule`.\n\nTwo things to avoid while you're here:\n\n- Don't \"fix\" it by re-declaring `PricingService` in `OrdersModule`'s own `providers` array. That compiles and boots, but it creates a *second, independent instance* of the service. Any state, cache, or connection it holds silently diverges from the one `PricingModule` uses. That's a worse bug than the one you're fixing.\n- Don't add more modules to `imports` hoping one of them happens to export it. An import with no matching export does nothing; it just adds noise to the graph.\n\nVerify by booting the app for real (`npm run start:dev`, or your project's equivalent) and confirming no `UnknownDependenciesException` or circular-dependency warning appears — `tsc --noEmit` passing is not sufficient, since this class of error only surfaces at bootstrap.\n\nIf `PricingService` *is* already exported and you still fail, then the problem has moved: check whether `OrdersService`'s constructor injection is asking for the concrete `PricingService` class while the module only provides it under a different token (a custom `provide`/`useClass` or string token), or whether there's a genuine cycle between the two modules that needs `forwardRef()` on **both** sides. But given the symptom you describe, a missing `exports` entry is by far the most likely cause.",
1126
+ "outputSha256": "cbd95456a90086b43d20c429688103f1af9fb4b8ada93083fb300ec53f220814",
1127
+ "promptSha256": "c5365b0fa21a740f327dbc4042562266b9c43a766235ce75dcc8cc8207cf497c",
1128
+ "deterministic": [],
1129
+ "judge": {
1130
+ "verdict": "pass",
1131
+ "reason": "Answer states imports only expose what PricingModule exports, not its providers ('Adding PricingModule to OrdersModule's imports array only makes whatever PricingModule exports visible... does not automatically expose everything in providers'), and names the concrete fix: 'Add it: exports: [PricingService]'. It also explicitly warns against re-declaring PricingService in OrdersModule's providers, so no fail criterion holds."
1132
+ },
1133
+ "passed": true
1134
+ },
1135
+ {
1136
+ "output": "You're missing the `exports` side. Adding `PricingModule` to `OrdersModule`'s `imports` array only gives `OrdersModule` access to providers that `PricingModule` actually **exports**. Importing a module does not automatically make all of that module's providers visible to the importer — only its exported ones are.\n\nSo the likely root cause is:\n\n```ts\n// pricing.module.ts\n@Module({\n providers: [PricingService], // declared here\n // exports: [PricingService], // <-- missing\n})\nexport class PricingModule {}\n```\n\n`PricingService` is constructed inside `PricingModule`, but since it's not in `exports`, it's private to that module. `OrdersModule` can import `PricingModule` all day and still never see `PricingService`, so Nest keeps throwing `UnknownDependenciesException` naming `OrdersService` (the provider whose constructor can't be satisfied).\n\n**The fix:** add `PricingService` to `PricingModule`'s `exports` array.\n\n```ts\n@Module({\n providers: [PricingService],\n exports: [PricingService],\n})\nexport class PricingModule {}\n```\n\n**Do not** work around this by adding `PricingService` to `OrdersModule`'s own `providers` array — that creates a second, separate instance of what's meant to be a single shared provider, and any state or side effects on it will silently diverge.\n\nWhile you're in there, confirm the two other common causes of the same error don't also apply:\n\n1. `PricingService` is actually decorated with `@Injectable()`. A class with no decorator can't be constructed through DI at all, regardless of imports/exports.\n2. Nest's error names the constructor argument index that failed — verify the index it reports actually maps to the `PricingService` parameter and not some other dependency sitting earlier in the constructor, which would change which class you need to trace.\n\n**Verify** by running the app itself (`npm run start:dev` or the project's equivalent), not just `tsc --noEmit` — this class of error only surfaces at bootstrap, so a clean type-check tells you nothing here. You should see the app boot with no `UnknownDependenciesException` and no circular-dependency warning.",
1137
+ "outputSha256": "c16f0d6bfc9861e0bc3e6140a3ab4981391b3b7b2e5dcb500be3a572cb67e41b",
1138
+ "promptSha256": "c5365b0fa21a740f327dbc4042562266b9c43a766235ce75dcc8cc8207cf497c",
1139
+ "deterministic": [],
1140
+ "judge": {
1141
+ "verdict": "pass",
1142
+ "reason": "Answer states importing a module only exposes its exported providers ('only its exported ones are visible'), shows the missing exports line, and names the concrete fix: add PricingService to PricingModule's exports array (code block with exports: [PricingService]). It explicitly warns against re-declaring PricingService in OrdersModule's providers, so no fail criterion holds."
1143
+ },
1144
+ "passed": true
1145
+ },
1146
+ {
1147
+ "output": "The import alone usually isn't the fix. When Nest throws `UnknownDependenciesException` for `OrdersService` even after `PricingModule` is in `OrdersModule.imports`, the most likely cause is that `PricingModule` never **exports** `PricingService`.\n\nNest resolves a provider across module boundaries only if the owning module both (a) declares it in `providers` and (b) lists it in `exports`. Putting `PricingModule` in `imports` gives OrdersModule access only to what PricingModule actually exports — importing a module with no matching export changes nothing.\n\nSo missing piece #1: check `PricingModule` and confirm `PricingService` is in its `exports` array, not just its `providers` array. That's the fix:\n\n```ts\n@Module({\n providers: [PricingService],\n exports: [PricingService], // <-- this was likely missing\n})\nexport class PricingModule {}\n```\n\nTwo things to avoid while fixing it:\n\n- Do **not** re-declare `PricingService` in `OrdersModule.providers` as a shortcut. That creates a second, separate instance instead of sharing PricingModule's one — state and side effects diverge silently.\n- Adding `PricingModule` to `imports` was still correct and necessary; it's just insufficient on its own without the export.\n\nIf `PricingService` **is** already exported, then check the other failure shapes in order:\n\n1. Is `PricingService` actually decorated with `@Injectable()`? A class with no decorator that's injected anywhere is the exact shape of this same error.\n2. Is the failure at the specific constructor argument Nest names — i.e. is it truly `PricingService` that can't resolve, or is `PricingService` itself failing to construct because *its own* dependencies aren't resolvable? The exception names the class whose constructor Nest was building; trace the reported argument index.\n3. Is `PricingService` request-scoped (`Scope.REQUEST`) while `OrdersService` is singleton (or vice versa)? That's a scope mismatch, not a wiring gap — the fix is different (propagate the scope up the injector chain), and don't change scope just to silence it.\n4. Is the error actually a circular dependency between `OrdersModule` and `PricingModule`? That reports a distinct circular-dependency warning, not `UnknownDependenciesException`, so you'd see both. If both modules genuinely need each other, `forwardRef()` is required **on both sides** — a one-sided fix still resolves in the wrong order.\n\nVerify by actually booting the app (`npm run start:dev` or the project's start script), not just `tsc --noEmit` — this error only surfaces at bootstrap. Then report the root cause (missing export vs. missing `@Injectable()` vs. genuine cycle) and the fix.",
1148
+ "outputSha256": "66a7b425bf91ee0e2e57c9c595dc8871615e3522e60b27034c747ef66f7ceb45",
1149
+ "promptSha256": "c5365b0fa21a740f327dbc4042562266b9c43a766235ce75dcc8cc8207cf497c",
1150
+ "deterministic": [],
1151
+ "judge": {
1152
+ "verdict": "pass",
1153
+ "reason": "Answer states Nest resolves across modules only if owning module declares in providers AND lists in exports, and that importing a module with no matching export changes nothing (criterion 1). Concrete fix shown: exports: [PricingService] in PricingModule code block (criterion 2). It explicitly warns against re-declaring PricingService in OrdersModule.providers, so no fail criterion."
1154
+ },
1155
+ "passed": true
1156
+ },
1157
+ {
1158
+ "output": "You're missing the export. An `imports` entry only makes a provider available to `OrdersModule` if the owning module actually lists that provider in its own `exports` array. `PricingModule` declaring `PricingService` in `providers` is not enough — by itself that only makes it injectable *within* `PricingModule`.\n\nCheck `PricingModule`:\n\n```ts\n@Module({\n providers: [PricingService],\n exports: [PricingService], // <-- this is likely missing\n})\nexport class PricingModule {}\n```\n\nIf `exports` doesn't include `PricingService`, add it there. The import you already added to `OrdersModule` then becomes meaningful — right now it's a no-op.\n\nTwo things to avoid while fixing this:\n\n- Don't re-declare `PricingService` in `OrdersModule`'s own `providers` array as a workaround. That creates a second, separate instance of a provider the codebase intends to be shared, and any state or side effects on it will silently diverge.\n- Don't add `PricingModule` to more places or widen `imports` further. The import edge is already correct; the gap is on the export side.\n\nSo the fix is one line in `PricingModule`: add `PricingService` to `exports`. Then restart the app (`npm run start:dev`) and confirm it boots with no `UnknownDependenciesException` — `tsc --noEmit` passing was never the signal here, since DI resolution only fails at bootstrap.\n\nIf after adding the export it *still* fails with the same message, the next thing to check is whether `PricingService` itself has the `@Injectable()` decorator — a class with no decorator that's listed in `providers` fails in the same shape and won't be fixed by exports/imports at all.",
1159
+ "outputSha256": "87b55c837af34a8dea0b8fc56df8fe0db76a6085016d0c226be7c88576153b6f",
1160
+ "promptSha256": "c5365b0fa21a740f327dbc4042562266b9c43a766235ce75dcc8cc8207cf497c",
1161
+ "deterministic": [],
1162
+ "judge": {
1163
+ "verdict": "pass",
1164
+ "reason": "Answer states an imports entry only works if the owning module lists the provider in its exports array ('An imports entry only makes a provider available... if the owning module actually lists that provider in its own exports array'), and names the concrete fix: add PricingService to PricingModule's exports array (shown in code with exports: [PricingService]). It explicitly warns against re-declaring PricingService in OrdersModule's providers, so no fail criterion holds."
1165
+ },
1166
+ "passed": true
1167
+ }
1168
+ ]
1169
+ },
1170
+ {
1171
+ "id": "circular-dependency-both-sides",
1172
+ "kind": "behavior",
1173
+ "prompt": "OrdersModule and PricingModule genuinely need providers from each other. I added forwardRef() to OrdersModule's imports array, but PricingModule still throws a circular dependency error at bootstrap. What's wrong?",
1174
+ "strictness": "high",
1175
+ "trials": 10,
1176
+ "passes": 9,
1177
+ "passRate": 0.9,
1178
+ "passAtK": 1,
1179
+ "grader": "judge",
1180
+ "status": "ran",
1181
+ "trialRecords": [
1182
+ {
1183
+ "output": "You've only wrapped one side of the cycle. A genuine module-level circular dependency needs `forwardRef()` on **both** sides — the one you added in OrdersModule is correct, but PricingModule's `imports` array still references OrdersModule directly:\n\n```ts\n// orders.module.ts — already correct\n@Module({\n imports: [forwardRef(() => PricingModule)],\n // ...\n})\nexport class OrdersModule {}\n\n// pricing.module.ts — still direct, this is the missing half\n@Module({\n imports: [OrdersModule], // <-- needs forwardRef() too\n // ...\n})\nexport class PricingModule {}\n```\n\nFix:\n\n```ts\n// pricing.module.ts\n@Module({\n imports: [forwardRef(() => OrdersModule)],\n // ...\n})\nexport class PricingModule {}\n```\n\nTwo things worth checking while you're in here:\n\n1. **Providers vs. modules.** If the mutual need is actually between two providers/services (e.g. `OrdersService` injects `PricingService` and vice versa), the module-level `forwardRef()` is necessary but not sufficient — each constructor parameter also needs `@Inject(forwardRef(() => OtherService))`. Nest resolves module imports and provider injections through separate mechanisms.\n\n2. **Genuine need?** Before adding the second `forwardRef()`, re-confirm this is a real two-way dependency and not an accidental import that could go one direction. A `forwardRef()` is a signal to re-examine the boundary — if it's genuinely needed, fine, but it's worth thirty seconds to check whether one module should instead own the shared piece or consume the other through a one-way edge. If it truly is mutual, go ahead and add the second side.\n\nOnce both sides are wrapped (and any provider-level cycles are handled with `@Inject(forwardRef(...))`), re-run your actual bootstrap command — `npm run start:dev` or equivalent — and confirm no circular-dependency warning appears. `tsc --noEmit` passing is not sufficient here; cycles only surface at bootstrap.",
1184
+ "outputSha256": "107335a325f99c244c5e048ee171bca80e8a16374a4920eef498ce950372f294",
1185
+ "promptSha256": "ca6209ccadfa9e2d29ab7843d70ff298f262cb2d8df8334d8368d21f4991adbd",
1186
+ "deterministic": [],
1187
+ "judge": {
1188
+ "verdict": "pass",
1189
+ "reason": "Answer states forwardRef must be on both sides and that PricingModule's direct OrdersModule import is the missing half (shows `imports: [OrdersModule] // needs forwardRef() too`). Concrete fix given: `imports: [forwardRef(() => OrdersModule)]` in pricing.module.ts, plus @Inject(forwardRef(() => OtherService)) for provider-level cycles. No fail criterion: it does not recommend reordering/merging as the fix."
1190
+ },
1191
+ "passed": true
1192
+ },
1193
+ {
1194
+ "output": "A one-sided `forwardRef()` only breaks the cycle when the other side's dependency is a plain (non-circular) import. If the cycle is genuine — both modules' providers inject each other's providers — then both sides need `forwardRef()`, and if the providers themselves are constructed via constructor injection across the cycle, the provider-level references need their own `forwardRef()` too, not just the module-level `imports` array.\n\nConcretely, for a module-level cycle:\n\n```ts\n// orders.module.ts\n@Module({\n imports: [forwardRef(() => PricingModule)],\n providers: [OrdersService],\n exports: [OrdersService],\n})\nexport class OrdersModule {}\n\n// pricing.module.ts\n@Module({\n imports: [forwardRef(() => OrdersModule)], // <-- currently missing\n providers: [PricingService],\n exports: [PricingService],\n})\nexport class PricingModule {}\n```\n\nYou added `forwardRef()` only to `OrdersModule`. `PricingModule` still imports `OrdersModule` directly, so Nest tries to fully resolve `OrdersModule` while it is still mid-construction and throws before your `forwardRef()` on the other side ever matters.\n\nAnd if the cycle is actually between the *providers* (OrdersService ↔ PricingService), the module-level `forwardRef()` isn't enough on its own — the constructor parameter on each side must also be deferred:\n\n```ts\n// orders.service.ts\nconstructor(\n @Inject(forwardRef(() => PricingService))\n private readonly pricing: PricingService,\n) {}\n\n// pricing.service.ts\nconstructor(\n @Inject(forwardRef(() => OrdersService))\n private readonly orders: OrdersService,\n) {}\n```\n\nDiagnosis, before you add anything: which layer is actually circular? If `OrdersService` injects `PricingService` and `PricingService` injects `OrdersService`, it's a provider-level cycle and you need `forwardRef()` in both constructors. If the modules merely import each other but the providers don't mutually inject, module-level `forwardRef()` on both sides is sufficient. Adding `forwardRef()` at only one layer, or on only one side, is the most common reason the error survives.\n\nOne caution before you finish: a genuine two-way provider dependency is worth a second look. Often the real fix is moving the shared logic into a small third provider/service that both depend on (one direction only), which removes the cycle entirely rather than papering over it with `forwardRef()`. If the cross-injection is truly needed on both sides, then mirror the `forwardRef()` on the missing side(s) above and re-run `npm run start:dev` to confirm no circular-dependency warning remains in the startup log.\n\nSo the immediate bug: you made the fix one-sided. Add the matching `forwardRef()` to `PricingModule`'s imports — and to both providers' constructor injections if the cycle is at the provider layer.",
1195
+ "outputSha256": "edae5d3ea23294c804ffa97ba73dd65fa40afaf80fd7f429706cfb30e97f6f6d",
1196
+ "promptSha256": "ca6209ccadfa9e2d29ab7843d70ff298f262cb2d8df8334d8368d21f4991adbd",
1197
+ "deterministic": [],
1198
+ "judge": {
1199
+ "verdict": "pass",
1200
+ "reason": "Answer states forwardRef must be on both sides and that one-sided OrdersModule forwardRef leaves PricingModule importing OrdersModule directly, throwing mid-construction. Names concrete fix: imports: [forwardRef(() => OrdersModule)] in pricing.module.ts, plus @Inject(forwardRef(() => PricingService/OrdersService)) on constructor params for provider-level cycle. No fail criterion (reorder/merge) recommended."
1201
+ },
1202
+ "passed": true
1203
+ },
1204
+ {
1205
+ "output": "A one-sided `forwardRef()` doesn't resolve a genuine cycle. Nest still needs to construct PricingModule's side of the reference, and that side is still a plain module reference to OrdersModule — so it hits the same cycle from the other direction.\n\nFix: wrap **both** references, not just one:\n\n- `OrdersModule.imports`: `[forwardRef(() => PricingModule)]` (already done)\n- `PricingModule.imports`: `[forwardRef(() => OrdersModule)]`\n\nSame rule applies if the cycle is between **providers** rather than modules — e.g. `OrdersService` injects `PricingService` and `PricingService` injects `OrdersService`. In that case the module-level `forwardRef()` alone isn't enough; each constructor parameter also needs it:\n\n```ts\nconstructor(\n @Inject(forwardRef(() => PricingService)) private pricing: PricingService,\n) {}\n```\n\nand the mirror on `PricingService`. One side without the other still resolves in the wrong order and throws.\n\nTwo things to check before you just add the other `forwardRef()`:\n\n1. **Confirm it's a genuine mutual need.** A `forwardRef()` is a signal to reconsider the boundary — if only one direction is real (e.g. `PricingService` truly needs `OrdersService`, but `OrdersService` only reaches into Pricing for a utility), extract the shared dependency into its own module/provider that both import, and the cycle disappears. That's the better fix when it's available.\n2. **Apply it symmetrically, and verify by booting.** After adding the second `forwardRef()`, re-run `npm run start:dev` (not just `tsc --noEmit`) and confirm no circular-dependency warning remains in the startup log.\n\nIf the error persists after both sides are wrapped, the cycle may be longer than two nodes (three or more modules forming a ring) — trace each hop and wrap every edge in the ring, since a single unwrapped edge anywhere in the loop re-triggers the same failure.",
1206
+ "outputSha256": "7612c1fa383066a62cbc3e0e4e811f1f20fb0fbea943fbd1a25f5b7faedcf9e1",
1207
+ "promptSha256": "ca6209ccadfa9e2d29ab7843d70ff298f262cb2d8df8334d8368d21f4991adbd",
1208
+ "deterministic": [],
1209
+ "judge": {
1210
+ "verdict": "pass",
1211
+ "reason": "Answer states one-sided forwardRef fails because PricingModule's side is still a plain reference to OrdersModule (\"hits the same cycle from the other direction\"), and names the concrete fix: PricingModule.imports: [forwardRef(() => OrdersModule)], plus @Inject(forwardRef(() => PricingService)) on constructor params for provider cycles. No fail criterion: it does not recommend reordering/merging as the fix."
1212
+ },
1213
+ "passed": true
1214
+ },
1215
+ {
1216
+ "output": "You wrapped only one side of the cycle.\n\n`forwardRef()` tells Nest \"this reference isn't resolvable yet, defer it\" — but it only defers the reference wrapped in it. The opposite side of the cycle is still a plain, non-deferred reference, so when Nest tries to resolve that direction, it hits the same cycle without the escape hatch, and the circular-dependency error persists on `PricingModule`.\n\n## The fix\n\nA genuine module-level cycle needs `forwardRef()` on **both** module declarations of the cycle, not just one:\n\n```ts\n// orders.module.ts\n@Module({\n imports: [forwardRef(() => PricingModule)],\n providers: [OrdersService],\n exports: [OrdersService],\n})\nexport class OrdersModule {}\n\n// pricing.module.ts\n@Module({\n imports: [forwardRef(() => OrdersModule)],\n providers: [PricingService],\n exports: [PricingService],\n})\nexport class PricingModule {}\n```\n\nIf the cycle is actually between **providers** rather than modules (e.g. `OrdersService` constructor-injects `PricingService` and vice versa), the module-level `forwardRef()` isn't the mechanism that matters — the constructor parameter needs it:\n\n```ts\n// orders.service.ts\nconstructor(\n @Inject(forwardRef(() => PricingService))\n private readonly pricing: PricingService,\n) {}\n```\n\nand the matching `@Inject(forwardRef(() => OrdersService))` on `PricingService`'s constructor. One-sided `forwardRef()` in either case leaves the other direction unresolvable, which is exactly the error you're still seeing.\n\n## Before you apply it\n\n`forwardRef()` on a genuine mutual dependency is legitimate, but a cycle is also a signal to re-examine the boundary first (per `rules/patterns.mdc`):\n\n- **Is it really mutual, or accidental?** If only `OrdersService` needs `PricingService`, and `PricingService` imports `OrdersModule` for something unrelated (a shared type, a constant, a third provider), the cycle is an import that could go one direction — move the shared piece into a small module both import, and delete the `forwardRef()` entirely. That's better than a working `forwardRef()`.\n- **Providers vs modules:** confirm which kind of cycle you actually have. A provider-level cycle needs `@Inject(forwardRef(...))`; a module-level cycle needs `forwardRef()` in both `imports` arrays. Mixing them up is the usual reason the second attempt also fails.\n\n## Verify\n\n- `npm run start:dev` (or the project's start script) boots with **no** circular-dependency warning — not just `tsc --noEmit` passing.\n- Both sides of the reference carry `forwardRef()` (or both constructors carry `@Inject(forwardRef(...))`) — never one.\n- Nothing was added to an `imports` array purely to silence the error without a matching `exports` entry, and no provider was re-declared in two modules' `providers`.",
1217
+ "outputSha256": "4031c6661a85157280bcbaa66c973e3e1187ab669296e6fd748a276d7a0aee1e",
1218
+ "promptSha256": "ca6209ccadfa9e2d29ab7843d70ff298f262cb2d8df8334d8368d21f4991adbd",
1219
+ "deterministic": [],
1220
+ "judge": {
1221
+ "verdict": "pass",
1222
+ "reason": "Answer states forwardRef only defers the wrapped reference, so the opposite side stays plain and the error persists on PricingModule (criterion 1). It concretely shows adding forwardRef(() => OrdersModule) to PricingModule's imports array, plus @Inject(forwardRef(() => PricingService)) on the constructor parameter for provider-level cycles (criterion 2). No fail criterion: it does not recommend reordering/merging as the fix."
1223
+ },
1224
+ "passed": true
1225
+ },
1226
+ {
1227
+ "output": "You added `forwardRef()` on only one side. A genuine module cycle needs it on **both** sides — the circular-dependency check is symmetric, so a one-sided `forwardRef()` still fails because Nest still sees an unresolvable reference from PricingModule's side.\n\nThe fix, given the cycle is genuine:\n\n- In **OrdersModule**: `imports: [forwardRef(() => PricingModule)]` (the side you already did)\n- In **PricingModule**: `imports: [forwardRef(() => OrdersModule)]` — this is the missing piece\n\nIf it's providers, not just modules, doing the mutual injection, you also need `forwardRef()` on the constructor parameters themselves on both classes:\n\n```ts\nconstructor(\n @Inject(forwardRef(() => OtherService))\n private readonly other: OtherService,\n) {}\n```\n\nTwo things to check while you're there, before calling it done:\n\n1. **Confirm it's a genuine cycle** (per the skill's rules). Both modules exporting and importing each other can be a sign the boundary is wrong. If only one direction is actually needed at module-graph level, drop the `forwardRef()` and fix the direction instead of papering over it — `forwardRef()` is a signal to reconsider the design, not the first move.\n\n2. **Confirm the exports exist.** `forwardRef()` resolves the *reference order* between modules; it does not create a missing export. If PricingModule injects something OrdersModule owns, OrdersModule must still list it in `exports`. The same is true in reverse. A `forwardRef()` around an import whose provider isn't exported still throws `UnknownDependenciesException`, just with a different message than the circular warning.\n\nVerify by actually booting (`npm run start:dev`), not just `tsc --noEmit` — the original error only surfaced at bootstrap, so type-checking passing tells you nothing here.",
1228
+ "outputSha256": "2ff18714431ad5dec47abb939bac11868829eaaad9a879496b7b794859af3520",
1229
+ "promptSha256": "ca6209ccadfa9e2d29ab7843d70ff298f262cb2d8df8334d8368d21f4991adbd",
1230
+ "deterministic": [],
1231
+ "judge": {
1232
+ "verdict": "pass",
1233
+ "reason": "Answer states forwardRef must be on both sides and that one-sided (OrdersModule only) still fails because the check is symmetric ('Nest still sees an unresolvable reference from PricingModule's side'). Names concrete fix: PricingModule imports: [forwardRef(() => OrdersModule)], plus @Inject(forwardRef(() => OtherService)) on constructor params. No fail criterion: it does not recommend reordering/merging as the fix."
1234
+ },
1235
+ "passed": true
1236
+ },
1237
+ {
1238
+ "output": "A genuine module cycle needs `forwardRef()` on **both** sides of the reference — you only added it on OrdersModule's side. PricingModule's `imports` array still has a plain, un-wrapped reference to OrdersModule, so when Nest walks PricingModule's imports it hits the same unresolved-order problem you already fixed on the other side and still throws.\n\nThe fix: wrap the reference in **PricingModule** too.\n\n```ts\n// pricing.module.ts\n@Module({\n imports: [forwardRef(() => OrdersModule)],\n // ...\n})\nexport class PricingModule {}\n```\n\nalongside what you already have in `orders.module.ts`:\n\n```ts\n// orders.module.ts\n@Module({\n imports: [forwardRef(() => OrdersModule)], // <-- this is the other side, already done\n imports: [forwardRef(() => PricingModule)],\n // ...\n})\nexport class OrdersModule {}\n```\n\nTwo more things to check while you're in there, since a circular module dependency usually drags provider-level cycles along with it:\n\n1. **If the cycle is actually between providers, not just modules** — i.e. `OrdersService` injects `PricingService` and `PricingService` injects `OrdersService` — you also need `forwardRef()` on the **constructor parameter**, not just the module imports:\n\n ```ts\n constructor(\n @Inject(forwardRef(() => PricingService)) private pricing: PricingService,\n ) {}\n ```\n\n Module-level `forwardRef()` fixes the module graph ordering; it does **not** fix a provider-to-provider cycle, which fails with the same circular-dependency symptom. Given you're seeing the error persist after the module-side fix, this is worth ruling in explicitly.\n\n2. **Confirm the providers are actually exported.** A module cycle that's *also* missing an `exports` entry will keep throwing even after the `forwardRef()` ordering is correct. `PricingModule` must export whatever `OrdersModule` injects, and vice versa — `forwardRef()` fixes ordering, it doesn't substitute for an export.\n\nBefore committing to `forwardRef()` on both sides though, it's worth a quick second look at whether the two modules truly need each other mutually, or whether one direction is just an accidental import that could be inverted (e.g. extracting the shared provider into a third module both import) — that removes the cycle entirely instead of papering over it. See `rules/patterns.mdc` on treating `forwardRef()` as a signal to reconsider the boundary, not the default answer.\n\nOnce you've added the second `forwardRef()`, re-run the actual boot command (`npm run start:dev`), not just `tsc --noEmit` — this class of error only surfaces at bootstrap, and confirm no circular-dependency warning appears in the startup log.",
1239
+ "outputSha256": "5bdc0bf0b344ebc85bc7a7d94e10151723fe7810b6daf0ddf5bbcfcf3a7cba97",
1240
+ "promptSha256": "ca6209ccadfa9e2d29ab7843d70ff298f262cb2d8df8334d8368d21f4991adbd",
1241
+ "deterministic": [],
1242
+ "judge": {
1243
+ "verdict": "fail",
1244
+ "reason": "Pass criteria 1 and 2 are met (both sides, forwardRef(() => OrdersModule) in PricingModule, @Inject(forwardRef(() => PricingService))). But fail criterion 1 holds: the answer recommends reconsidering whether the modules truly need each other and extracting a shared provider into a third module to 'remove the cycle entirely instead of papering over it,' i.e. merging/restructuring rather than symmetric forwardRef()."
1245
+ },
1246
+ "passed": false
1247
+ },
1248
+ {
1249
+ "output": "You applied `forwardRef()` to only one side of a genuine two-way dependency. Nest resolves module imports in order, so even with `OrdersModule` wrapping its reference to `PricingModule` in `forwardRef()`, `PricingModule`'s own reference back to `OrdersModule` is still a plain, unsuppressed import — Nest hits that one first during resolution and it can't defer it, so the cycle still fails at bootstrap.\n\nA genuine circular dependency needs `forwardRef()` on **both** sides of the reference:\n\n1. **Both module-level imports.** In `OrdersModule`:\n ```ts\n @Module({ imports: [forwardRef(() => PricingModule)] })\n ```\n And symmetrically in `PricingModule`:\n ```ts\n @Module({ imports: [forwardRef(() => OrdersModule)] })\n ```\n\n2. **And, if the two modules' *providers* inject each other directly** (e.g. `OrdersService` injects `PricingService` and `PricingService` injects `OrdersService`), the constructor-parameter side needs it too:\n ```ts\n constructor(\n @Inject(forwardRef(() => PricingService)) private pricing: PricingService,\n ) {}\n ```\n on **both** providers — a module-level `forwardRef()` alone does not cover a provider-to-provider injection cycle. That's the most common reason a bootstrap error survives after someone \"added `forwardRef()`\" to the imports array.\n\nSo: go back and find every edge in the cycle (module→module and, if present, provider→provider) and wrap **each** one in `forwardRef()`. Check that neither side was left as a plain import or plain constructor type.\n\nOne caution before you finish: a real mutual `forwardRef()` cycle is often a signal that the boundary itself is wrong. Before locking in `forwardRef()` on both sides, reconsider whether the shared piece (the service both modules actually need) could live in its own small module that both import one-directionally — that removes the cycle entirely instead of deferring it. If after that review the mutual need is still genuine, then apply the two-sided `forwardRef()` as above and re-run `npm run start:dev` to confirm the app actually boots with no circular-dependency warning.",
1250
+ "outputSha256": "34710c10e0e1d573596a902d0c9306a42d0b0d89069d049b1cfd08749596bea1",
1251
+ "promptSha256": "ca6209ccadfa9e2d29ab7843d70ff298f262cb2d8df8334d8368d21f4991adbd",
1252
+ "deterministic": [],
1253
+ "judge": {
1254
+ "verdict": "pass",
1255
+ "reason": "Answer states forwardRef must be on both sides and that PricingModule's plain import back to OrdersModule is why it still fails. It concretely shows adding forwardRef(() => OrdersModule) to PricingModule's imports and @Inject(forwardRef(() => PricingService)) on both providers. The closing suggestion to extract a shared module is framed as a caution, not the fix, so it doesn't trigger the fail criterion."
1256
+ },
1257
+ "passed": true
1258
+ },
1259
+ {
1260
+ "output": "A one-sided `forwardRef()` doesn't break a real cycle. `forwardRef()` only defers *one* side of the reference; Nest still has to resolve the other module's imports eagerly, so when it gets there it hits the same cycle — just from the opposite direction, and that's why PricingModule is what throws now.\n\nFor a genuine module-level cycle you need `forwardRef()` on **both** sides:\n\n```ts\n// orders.module.ts\n@Module({\n imports: [forwardRef(() => PricingModule)],\n providers: [OrdersService],\n exports: [OrdersService],\n})\nexport class OrdersModule {}\n\n// pricing.module.ts\n@Module({\n imports: [forwardRef(() => OrdersModule)],\n providers: [PricingService],\n exports: [PricingService],\n})\nexport class PricingModule {}\n```\n\nThe same applies at the provider level: if the cycle is between the services themselves (not just the modules), each constructor parameter needs `@Inject(forwardRef(() => OtherService))` — deferring only one constructor argument leaves the other side to resolve eagerly and fail the same way.\n\nTwo things to check while you're there, before assuming the two-sided fix is the end of it:\n\n1. **Each module must still `export` the provider the other injects.** `forwardRef()` fixes the *ordering* problem, not a missing `exports` entry — if `PricingService` isn't in `PricingModule`'s `exports`, you'll get a fresh `UnknownDependenciesException` once the cycle itself stops blocking bootstrap.\n\n2. **Confirm the cycle is actually a mutual need, not one accidental import.** Per `rules/patterns.mdc`, `forwardRef()` is a signal to reconsider the module boundary first — a genuine two-way module dependency often means a third shared module (or moving the shared provider) is the better long-term fix. Apply the two-sided `forwardRef()` if the mutual need is real; if it turns out to be one-directional in intent, fix the import direction instead of adding the second `forwardRef()`.\n\nVerify by re-running `npm run start:dev` (the app must actually boot, not just type-check) and confirming no circular-dependency warning appears in the startup log.",
1261
+ "outputSha256": "ab021d596b4abbd1f1b0fc6ddf082b5d856f8c4bd468428f91770a68d36cfbd6",
1262
+ "promptSha256": "ca6209ccadfa9e2d29ab7843d70ff298f262cb2d8df8334d8368d21f4991adbd",
1263
+ "deterministic": [],
1264
+ "judge": {
1265
+ "verdict": "pass",
1266
+ "reason": "Answer states one-sided forwardRef only defers one side and Nest resolves the other eagerly, hitting the same cycle (pass 1). It concretely shows adding forwardRef(() => OrdersModule) to PricingModule's imports array, plus @Inject(forwardRef(() => OtherService)) on constructor params for provider-level cycles (pass 2). It does not recommend reordering/merging as the fix; the shared-module note is framed as a reconsideration, not the fix."
1267
+ },
1268
+ "passed": true
1269
+ },
1270
+ {
1271
+ "output": "You applied `forwardRef()` on only one side of the cycle. A genuine circular dependency needs it on **both** sides of the reference.\n\nHere's what's happening: `OrdersModule` imports `PricingModule` via `forwardRef(() => PricingModule)`. That defers resolving *OrdersModule's* reference to PricingModule. But `PricingModule`'s own `imports` array still references `OrdersModule` directly (un-deferred). When Nest boots and starts resolving PricingModule's dependencies, it hits that direct reference to OrdersModule, which in turn is trying to resolve back to PricingModule — and the cycle is still there from PricingModule's side. That's why the error is now reported against PricingModule.\n\nThe fix: add `forwardRef()` symmetrically.\n\n```ts\n// orders.module.ts\n@Module({\n imports: [forwardRef(() => PricingModule)],\n providers: [OrdersService],\n exports: [OrdersService], // PricingModule needs whatever it injects from here\n})\nexport class OrdersModule {}\n```\n\n```ts\n// pricing.module.ts\n@Module({\n imports: [forwardRef(() => OrdersModule)],\n providers: [PricingService],\n exports: [PricingService], // OrdersModule needs whatever it injects from here\n})\nexport class PricingModule {}\n```\n\nTwo things to confirm while you're in there:\n\n1. **Both sides actually export what the other injects.** `forwardRef()` only defers resolution order — it does nothing if the provider isn't in the owning module's `exports` array. Since both modules import each other, each must also export the provider the other one's service injects, or you'll get an `UnknownDependenciesException` right after the circular-dependency error clears.\n\n2. **If it's providers rather than modules that reference each other**, the same symmetry rule applies at the provider level: the constructor parameter needs `@Inject(forwardRef(() => OtherService))` on *both* consumers, not just one.\n\nOne caution worth stating: `forwardRef()` on both sides will make it boot, and that's the correct minimal fix if the mutual need is real. But a two-way module dependency is often a sign the shared concern should be extracted into a third module that both import — if `OrdersService` and `PricingService` are reaching into each other's internals, that's worth reconsidering rather than permanently entrenching with `forwardRef()`. That said, for your immediate failure: the missing half of the `forwardRef()` pair is the bug.",
1272
+ "outputSha256": "dd8af88c8aa29f21a6d90b2410a95341ab722421509c2a554d09be586090f7b4",
1273
+ "promptSha256": "ca6209ccadfa9e2d29ab7843d70ff298f262cb2d8df8334d8368d21f4991adbd",
1274
+ "deterministic": [],
1275
+ "judge": {
1276
+ "verdict": "pass",
1277
+ "reason": "Answer states forwardRef must be on both sides and that OrdersModule-only is why PricingModule fails ('PricingModule's own imports array still references OrdersModule directly'). Concrete fix shown: imports: [forwardRef(() => OrdersModule)] in pricing.module.ts, plus @Inject(forwardRef(() => OtherService)) on both consumers for provider-level cycles. No fail criterion: it endorses symmetric forwardRef, not reordering/merging."
1278
+ },
1279
+ "passed": true
1280
+ },
1281
+ {
1282
+ "output": "A one-sided `forwardRef()` cannot resolve a genuine two-module cycle. You wrapped only OrdersModule's side of the reference (`imports: [forwardRef(() => PricingModule)]`), but PricingModule still imports OrdersModule the ordinary way — so when Nest builds the module graph it still hits the same cycle from the other direction and the warning moves to (or persists on) PricingModule.\n\nA real cycle needs `forwardRef()` on **both** sides:\n\n- `OrdersModule`: `imports: [forwardRef(() => PricingModule)]`\n- `PricingModule`: `imports: [forwardRef(() => OrdersModule)]`\n\n`forwardRef()` is not a \"whitelist one direction\" flag — it defers the resolution of that particular reference until after both modules are defined, and it only works if every edge of the cycle is deferred. Leaving one edge as an eager reference reintroduces exactly the ordering problem you were trying to escape.\n\nTwo things to confirm while you fix it:\n\n1. If the actual circular dependency is between **providers** (e.g. `OrdersService` injects `PricingService` and vice versa), the module-level `forwardRef()` isn't sufficient on its own — you also need it on the constructor parameters: `@Inject(forwardRef(() => PricingService))` (and the mirror on the other side). Module cycles and provider cycles are separate edges; fix whichever actually exist, on both ends.\n2. Don't let `forwardRef()` become the permanent design. It's a valid fix for a genuine mutual need, but if the \"need\" is really just one side importing the other by accident, removing that direction is the cleaner root-cause fix than wrapping both ends in `forwardRef()`. Look at whether the two modules share a third concern that belongs in its own module instead.\n\nAfter adding the second `forwardRef()`, re-run the app itself (`npm run start:dev` or the project's equivalent), not just `tsc --noEmit` — this class of error only appears at bootstrap. The fix is only done when the app actually boots with no circular-dependency warning, and the change is confined to the two `imports` arrays (plus any constructor `@Inject(forwardRef(...))` if the cycle is at the provider level).",
1283
+ "outputSha256": "902e7db687527897f31c2250ea083258417baa412ecfca6764c5fde13f983546",
1284
+ "promptSha256": "ca6209ccadfa9e2d29ab7843d70ff298f262cb2d8df8334d8368d21f4991adbd",
1285
+ "deterministic": [],
1286
+ "judge": {
1287
+ "verdict": "pass",
1288
+ "reason": "Answer states one-sided forwardRef can't resolve a genuine cycle and PricingModule still imports OrdersModule eagerly, hitting the same cycle (criterion 1). It names the concrete fix: PricingModule imports: [forwardRef(() => OrdersModule)], plus @Inject(forwardRef(() => PricingService)) on constructor params for provider cycles (criterion 2). No fail criterion: it does not recommend reordering/merging as the fix."
1289
+ },
1290
+ "passed": true
1291
+ }
1292
+ ]
1293
+ }
1294
+ ],
1295
+ "verdict": "pass",
1296
+ "scope": "bundled",
1297
+ "skillDigest": "e5ee2b40050e5c0d30656380e0af4b89b514de00eb2d8c09ea224d7ec6f32a7e",
1298
+ "catalogDigest": "fd9b6a086f61a996f761a68f9e7a58cde1ce62e121f276d70bbef8e05e372f4b",
1299
+ "judgePromptVersion": "2026-09-25.1",
1300
+ "runner": "deepseek",
1301
+ "model": "deepseek-chat",
1302
+ "runnerPromptVersion": "2026-09-25.1",
1303
+ "recordedAt": "2026-09-25T16:01:51.294Z",
1304
+ "judge": "deepseek",
1305
+ "judgeModel": "deepseek-chat"
1306
+ }
1307
+ ]
1308
+ }