@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,32 @@
1
+ [
2
+ {
3
+ "query": "Use when implementing a new Angular component, service, directive, or pipe -- standalone component structure, signal-based (signal()/computed()/effect()) state, inject()-based dependency injection, and typed Reactive Forms. Wires RxJS-to-signal interop (toSignal/takeUntilDestroyed) correctly and follows the project's own routing conventions. Not for Vue/React component implementation, not for writing unit specs for an Angular component (use angular-testing), and not for repairing an already-failing Angular compiler error (use angular-build-fix).",
4
+ "decision": "fork",
5
+ "topMatch": "angular/angular-code-review",
6
+ "recordedAt": "2026-09-25T06:33:13.884Z",
7
+ "skillName": "angular-implementation",
8
+ "justification": "Top match angular-code-review is this pack's own sibling sharing Angular/signal/inject() vocabulary, but is read-only review of already-written code, explicitly excluded here (this skill authors new components/services); trigger-accuracy eval confirms both route correctly on their own positive prompts. No existing catalog skill (react-implementation, vue-implementation, nestjs-implementation) covers Angular's own standalone-component/signal/inject() authoring surface."
9
+ },
10
+ {
11
+ "query": "Use when writing or fixing a TestBed spec for an Angular component, service, directive, pipe, or route guard -- configuring TestBed.configureTestingModule, driving a ComponentFixture (componentRef.setInput, detectChanges, whenStable), mocking HttpClient with HttpTestingController, testing a CanActivate/CanMatch guard function, and using fakeAsync/tick for deterministic async specs. Not for Vue/React component tests, not for a full user-flow check against a deployed, running instance, and not for implementing the component/service under test (use angular-implementation).",
12
+ "decision": "create",
13
+ "topMatch": "angular/angular-implementation",
14
+ "recordedAt": "2026-09-25T06:33:14.047Z",
15
+ "skillName": "angular-testing"
16
+ },
17
+ {
18
+ "query": "Use when reviewing an Angular component/service/directive diff for framework-specific correctness -- untracked RxJS subscriptions missing takeUntilDestroyed/async-pipe cleanup, OnPush components mutating input objects in place instead of replacing the reference, a dependency-injection call made outside a valid injector context, DomSanitizer bypassSecurityTrust* calls on user-influenced data, and NgModule/standalone mixing. Does not review generic JavaScript/TypeScript correctness the base stack reviewer already covers, does not review MobX store logic, and never edits code -- it reports findings only. Not for implementing or fixing the reviewed code (use angular-implementation or angular-build-fix).",
19
+ "decision": "create",
20
+ "topMatch": "angular/angular-implementation",
21
+ "recordedAt": "2026-09-25T06:33:14.214Z",
22
+ "skillName": "angular-code-review"
23
+ },
24
+ {
25
+ "query": "Use when resolving an `ng build` failure, an AOT/Ivy template type-checking error (a property that doesn't exist on the bound type, an @if/@for control-flow type mismatch), a missing NgModule declaration/import error, or a DI 'No provider for X' resolution error blocking an Angular build. Applies the smallest root-cause fix and never silences the compiler with strictTemplates: false, an `any` cast in a template context, or `@Injectable` removal. Not for a plain TypeScript compile failure outside any Angular template, and not for authoring a fresh component or injectable from scratch (use angular-implementation).",
26
+ "decision": "fork",
27
+ "topMatch": "nextjs-nuxt/nextjs-nuxt-build-fix",
28
+ "recordedAt": "2026-09-25T06:33:14.375Z",
29
+ "skillName": "angular-build-fix",
30
+ "justification": "Top match nextjs-nuxt-build-fix shares generic 'build fails' vocabulary but targets Next.js/Nuxt compile failures (Server/Client boundary, composable resolution), not Angular's AOT/Ivy template type-checking or NgModule/DI resolution errors this skill covers; the description explicitly excludes a plain TypeScript compile failure with no Angular template involved. No existing catalog skill covers ng build/AOT-specific fixes. Confirmed distinct by clean trigger-accuracy eval."
31
+ }
32
+ ]
@@ -0,0 +1,55 @@
1
+ {
2
+ "id": "angular",
3
+ "family": "framework",
4
+ "extends": "ts-js-node",
5
+ "modules": [
6
+ "angular-rules",
7
+ "angular-skills"
8
+ ],
9
+ "detectionMarkers": [
10
+ "angular"
11
+ ],
12
+ "provenance": {
13
+ "origin": "authored",
14
+ "sourceRef": "flow 318, Wave 4 batch 2"
15
+ },
16
+ "stability": "experimental",
17
+ "skills": {
18
+ "implement": [
19
+ "angular-implementation"
20
+ ],
21
+ "test": [
22
+ "angular-testing"
23
+ ],
24
+ "review": [
25
+ "angular-code-review"
26
+ ],
27
+ "build-fix": [
28
+ "angular-build-fix"
29
+ ],
30
+ "migrate": []
31
+ },
32
+ "agentProfile": {
33
+ "displayName": "Angular",
34
+ "auditFocus": [
35
+ "an RxJS subscription created in a component/directive with no takeUntilDestroyed, async pipe, or explicit ngOnDestroy teardown",
36
+ "a component still using ChangeDetectionStrategy.Default with heavy template bindings where OnPush plus signals would isolate re-renders",
37
+ "a service or dependency reached through constructor-parameter injection mixed inconsistently with inject() in the same file, or inject() called outside an injection context",
38
+ "a template still using *ngIf/*ngFor/*ngSwitch in a component whose codebase has otherwise migrated to @if/@for/@switch control flow",
39
+ "a NgModule-based component/directive/pipe added to a codebase where the rest of the app is standalone",
40
+ "state mutated directly on a class field instead of through a signal's set/update, or a computed signal with a side effect inside its computation"
41
+ ],
42
+ "buildCommands": [
43
+ "ng build (or the project's package.json build script wrapping the Angular CLI)",
44
+ "ng test (or the project's configured Karma/Jest runner) for unit tests",
45
+ "npx tsc --noEmit for standalone type-checking outside the Angular compiler",
46
+ "ng lint (or the project's configured eslint-angular script)"
47
+ ],
48
+ "fixGuardrails": [
49
+ "never add `standalone: false` or reintroduce an NgModule just to route around a compiler/DI error in an otherwise-standalone codebase",
50
+ "never disable Angular's strict template type checking (`strictTemplates`, `fullTemplateTypeCheck`) in tsconfig to silence a template type error",
51
+ "never swallow an RxJS subscription error with an empty `error: () => {}` handler to stop a console error from failing a build check",
52
+ "never delete or skip a failing TestBed spec to reach a green test run"
53
+ ]
54
+ }
55
+ }
@@ -0,0 +1,82 @@
1
+ ---
2
+ extends: common
3
+ paths: ["**/*.ts", "**/*.html"]
4
+ metadata:
5
+ origin: authored
6
+ ---
7
+
8
+ # Angular coding style
9
+
10
+ Narrows the stack-agnostic style rules to current Angular idiom (standalone
11
+ components, signals, `inject()`). Applies to `*.ts` and component
12
+ `*.html` templates; everything not Angular-specific still comes from the
13
+ common rules this file `extends`.
14
+
15
+ ## Components and files
16
+
17
+ - Components, directives, and pipes are standalone by default in current
18
+ Angular — do not set `standalone: false` or write a new `NgModule` to
19
+ register one unless the project itself is still NgModule-based
20
+ end-to-end.
21
+ - One component (and its template/styles) per file, named after the
22
+ component class (`OrderSummary` in `order-summary.ts`, not a generic
23
+ `component.ts`). Match whatever file-suffix convention (`.component.ts`
24
+ vs. plain `.ts`) the project's own `angular.json`/existing files already
25
+ use rather than introducing a second one.
26
+ - Keep a component's template under roughly 60-80 lines before extracting a
27
+ child component; a template doing significant `@if`/`@for` branching for
28
+ more than one concern is a sign the branches belong in separate
29
+ components.
30
+
31
+ ## Dependency injection
32
+
33
+ - Prefer the `inject()` function over constructor-parameter injection for
34
+ new code (`private readonly router = inject(Router);`), since it composes
35
+ cleanly with field initializers and works outside constructors (guards,
36
+ resolvers, `provide*` factories). Do not mix `inject()` and
37
+ constructor-parameter injection for different dependencies in the same
38
+ class — pick one per class, and prefer `inject()` for new classes.
39
+ - `inject()` only works inside an injection context (a constructor, a field
40
+ initializer, or a call wrapped in `runInInjectionContext`) — do not call
41
+ it inside a `setTimeout`, a plain async callback, or after the
42
+ constructor has returned.
43
+
44
+ ## Signals and state
45
+
46
+ - Use `signal()` for local component/service state that changes over time,
47
+ `computed()` for values derived from other signals, and `input()`/
48
+ `model()` for component inputs — do not read/write a signal's backing
49
+ value directly; always go through `.set()`/`.update()`.
50
+ - Keep a `computed()`'s computation pure (no side effects, no writes to
51
+ other signals inside it) — if a change needs to trigger a side effect,
52
+ use `effect()`, not a computed callback abused for its side effect.
53
+ - Do not mirror a signal's value into a plain class field "for convenience"
54
+ in the template — read the signal directly (`value()`) so Angular's
55
+ fine-grained reactivity tracks the actual dependency.
56
+
57
+ ## Templates and control flow
58
+
59
+ - Use the built-in control flow (`@if`, `@for` with a `track` expression,
60
+ `@switch`) in new templates, not `*ngIf`/`*ngFor`/`*ngSwitch` — unless the
61
+ surrounding component's own template still uses the structural-directive
62
+ form throughout, in which case match the existing file rather than
63
+ mixing both styles in one template.
64
+ - Always give `@for` an explicit `track` expression (the item's own stable
65
+ id, not `$index`, unless the list has no natural identity) — an untracked
66
+ or index-tracked loop over data that reorders forces Angular to
67
+ re-render every row instead of just the ones that changed.
68
+
69
+ ## Naming and typing
70
+
71
+ - `PascalCase` for component/directive/pipe/service classes, `camelCase`
72
+ for signals, fields, and methods — a signal's own name should read as the
73
+ value it holds (`user`, not `userSignal`), since calling it (`user()`)
74
+ already signals reactivity.
75
+ - Type every `input()`/`output()`/`model()` explicitly
76
+ (`input<Order | null>(null)`) rather than relying on inference from a
77
+ loosely-typed default; an untyped input silently becomes `unknown`/`any`
78
+ at every call site.
79
+ - Avoid `any` in component/service code; when the Angular CLI's generated
80
+ boilerplate produces a loosely-typed value (e.g. a form's raw value),
81
+ narrow it explicitly at the boundary instead of propagating `any`
82
+ through the class.
@@ -0,0 +1,84 @@
1
+ ---
2
+ extends: common
3
+ paths: ["**/*.ts", "**/*.html"]
4
+ metadata:
5
+ origin: authored
6
+ ---
7
+
8
+ # Angular patterns
9
+
10
+ Idiomatic component/service/change-detection design for current Angular,
11
+ and the anti-patterns to avoid when narrowing the common architecture rules
12
+ to this stack.
13
+
14
+ ## Change detection
15
+
16
+ - Default new components to `ChangeDetectionStrategy.OnPush`. With
17
+ signal-based state this is nearly free: reading a signal in a template
18
+ registers it as a dependency and Angular schedules the check for you, so
19
+ `OnPush` plus signals rarely needs a manual `markForCheck()` at all.
20
+ - If a component still receives data via `@Input()` mutation of a plain
21
+ object (not a signal) under `OnPush`, replace the mutation with a new
22
+ object reference (or migrate the input to a signal) — `OnPush` only
23
+ re-checks on a new reference/signal change, not a mutated property on the
24
+ same object.
25
+ - Reach for `ChangeDetectorRef.markForCheck()` only when a value changes
26
+ outside Angular's own change-detection triggers (a third-party callback,
27
+ a native DOM event Angular didn't bind) and cannot reasonably be modeled
28
+ as a signal — not as a routine fix for "the view didn't update".
29
+
30
+ ## Dependency injection and service boundaries
31
+
32
+ - Scope a service with `providedIn: 'root'` for app-wide singletons; scope
33
+ it in a route's providers (or a standalone component's `providers`) for
34
+ state that should reset per-feature/per-route instead of leaking across
35
+ the whole app's lifetime.
36
+ - Keep a component's class focused on view state and event wiring; move
37
+ business logic, HTTP calls, and cross-component state into an injectable
38
+ service. A component `inject()`-ing `HttpClient` directly to build
39
+ request logic inline is a sign that logic belongs in a service instead.
40
+ - Use Angular's `HttpClient` (with `provideHttpClient()` and interceptors
41
+ for cross-cutting concerns like auth headers) rather than a bare `fetch`
42
+ scattered through components — interceptors are the idiomatic place for
43
+ auth/error handling, not per-call boilerplate.
44
+
45
+ ## RxJS and signal interop
46
+
47
+ - Prefer `toSignal()`/`toObservable()` (`@angular/core/rxjs-interop`) at
48
+ the boundary between RxJS streams (HTTP, router events, form
49
+ `valueChanges`) and signal-based component state, rather than manually
50
+ subscribing into a plain field.
51
+ - When an `Observable` genuinely needs a manual `.subscribe()` inside a
52
+ component (rare once `async` pipe / `toSignal()` cover the common case),
53
+ pipe through `takeUntilDestroyed()` (call it in an injection context, or
54
+ pass an explicit `DestroyRef`) instead of hand-rolling a `Subject`+
55
+ `ngOnDestroy` teardown.
56
+ - Do not fan a single source Observable out into multiple independent
57
+ `.subscribe()` calls that each re-trigger the source's side effects
58
+ (e.g. a re-fetching HTTP call); share it (`shareReplay`, or convert once
59
+ with `toSignal()`) so the side effect runs once per meaningful change.
60
+
61
+ ## Forms
62
+
63
+ - Prefer Angular's typed Reactive Forms (`FormGroup<{...}>`,
64
+ `FormControl<T>`) over template-driven forms for anything beyond a
65
+ trivial single-field form — typed forms catch a renamed/removed control
66
+ at compile time instead of a silent runtime `undefined`.
67
+ - Validate with Angular's built-in or custom `ValidatorFn`s registered on
68
+ the control, not ad-hoc validation logic scattered through submit-button
69
+ click handlers.
70
+
71
+ ## Anti-patterns
72
+
73
+ - Do not reach into a child component's internals via `ViewChild` to call
74
+ a method or set a field when an `@Input()`/`input()`/signal binding, or
75
+ an `@Output()`/`output()` event, would express the same interaction
76
+ declaratively.
77
+ - Do not perform DOM manipulation directly through `ElementRef.nativeElement`
78
+ in ordinary component code — use Angular's `Renderer2`, template
79
+ bindings, or a directive when direct DOM access is genuinely required
80
+ (a third-party widget, focus management); bypassing Angular's rendering
81
+ layer breaks server-side rendering and change-detection assumptions.
82
+ - Do not put HTTP calls or other side effects inside a `computed()` — a
83
+ computed's callback can re-run any number of times and must stay pure;
84
+ side effects belong in `effect()` or an explicit event handler.
@@ -0,0 +1,70 @@
1
+ ---
2
+ extends: common
3
+ paths: ["**/*.ts", "**/*.html"]
4
+ metadata:
5
+ origin: authored
6
+ ---
7
+
8
+ # Angular security
9
+
10
+ Stack-specific risks on top of the common security rules, focused on where
11
+ Angular's own sanitization can be bypassed and where DI/routing choices
12
+ create an opening.
13
+
14
+ ## Template injection and sanitization bypass
15
+
16
+ - Angular auto-sanitizes values bound into `innerHTML`, `href`,
17
+ style/URL/resource-URL contexts, and script/style properties — do not
18
+ reach for `DomSanitizer.bypassSecurityTrustHtml`/`bypassSecurityTrustUrl`/
19
+ `bypassSecurityTrustResourceUrl`/`bypassSecurityTrustScript` on
20
+ user-supplied or user-influenced content. Those calls tell Angular "trust
21
+ this value completely, skip sanitization" — reserve them for genuinely
22
+ static, developer-authored content (a hardcoded SVG, a known-safe
23
+ asset URL), never for a value that traces back to user input or an
24
+ external API response.
25
+ - Prefer binding through the normal property/interpolation syntax
26
+ (`{{ value }}`, `[textContent]`) over `[innerHTML]` for user-controlled
27
+ text; if `[innerHTML]` is genuinely required for rich content, sanitize
28
+ server-side or via a vetted sanitizer library rather than trusting
29
+ Angular's default sanitizer alone for anything beyond simple formatting.
30
+ - Never write directly to `ElementRef.nativeElement.innerHTML` — that
31
+ bypasses Angular's sanitizer entirely, unlike the `[innerHTML]` template
32
+ binding which still runs through it.
33
+
34
+ ## HTTP and CSRF
35
+
36
+ - Send credentials/tokens via `HttpClient` interceptors (`HttpInterceptorFn`
37
+ or a class-based `HttpInterceptor`), not by hand-appending an
38
+ `Authorization` header at each call site — a missed call site is a
39
+ silent auth gap, not a build error.
40
+ - When the backend uses cookie-based sessions, rely on Angular's built-in
41
+ `XSRF-TOKEN`/`X-XSRF-TOKEN` CSRF handling (`withXsrfConfiguration` /
42
+ the default cookie name) rather than disabling `withCredentials` or
43
+ rolling a custom CSRF header scheme, unless the backend's own CSRF
44
+ contract genuinely requires different header/cookie names — configure
45
+ those, don't drop the protection.
46
+
47
+ ## Routing and route guards
48
+
49
+ - Gate any route that requires authentication/authorization with a route
50
+ guard (`CanActivateFn`/`CanMatchFn`) that actually checks server-verified
51
+ state (a token's validity, a role from the authenticated session) — never
52
+ a guard that only checks a client-side flag with no corresponding
53
+ server-side check on the API the route's data comes from.
54
+ - Do not put secrets, API keys, or backend-only credentials into
55
+ environment files (`environment.ts`) that ship in the client bundle —
56
+ anything in `environment.*.ts` is public once built; only put
57
+ publicly-safe configuration (API base URLs, feature flags) there.
58
+
59
+ ## Dependency injection surface
60
+
61
+ - Do not widen a service's provider scope to `providedIn: 'root'` just to
62
+ work around an injection error, when the service holds per-user or
63
+ per-session state — a root-scoped singleton is shared across the whole
64
+ app's lifetime (and across users in SSR), so session-scoped data leaking
65
+ into it is a cross-request data leak, not just a design smell.
66
+ - Validate and narrow data crossing a trust boundary (route params, query
67
+ params, a form's raw value, a third-party postMessage payload) before
68
+ using it in a template binding or passing it to a service call — treat
69
+ router/query-string values as untrusted input, not as pre-validated
70
+ application state.
@@ -0,0 +1,73 @@
1
+ ---
2
+ extends: common
3
+ paths: ["**/*.ts", "**/*.html"]
4
+ metadata:
5
+ origin: authored
6
+ ---
7
+
8
+ # Angular testing
9
+
10
+ Test layout, runner, and fixture conventions for Angular components,
11
+ services, and directives — narrows the common testing rules to
12
+ `TestBed`-based Angular idiom.
13
+
14
+ ## Layout and runner
15
+
16
+ - Co-locate a unit test with its source (`order-summary.ts` /
17
+ `order-summary.spec.ts`), matching whatever the project's own existing
18
+ spec files already do; do not invent a parallel `__tests__/` tree in an
19
+ Angular CLI project that uses co-located `.spec.ts` files.
20
+ - Run the project's configured runner (`ng test`, or a Jest/Vitest setup if
21
+ the project has migrated off Karma) rather than assuming Karma is
22
+ present — check `angular.json`'s `test` builder or the project's
23
+ `package.json` `test` script before invoking a specific runner by name.
24
+
25
+ ## Component tests
26
+
27
+ - Configure the module under test with `TestBed.configureTestingModule`
28
+ (importing the standalone component directly in `imports`, since
29
+ standalone components are imported, not declared), then
30
+ `TestBed.createComponent` to get a `ComponentFixture`.
31
+ - Set signal-based inputs through `fixture.componentRef.setInput('name',
32
+ value)`, not by assigning the component instance's field directly —
33
+ direct field assignment on a signal input does not go through Angular's
34
+ input-binding machinery and can silently not reflect in the template the
35
+ way a real caller's binding would.
36
+ - After a change that affects the DOM (setting an input, clicking a
37
+ button, resolving a promise/observable the component depends on), call
38
+ `fixture.detectChanges()` (or `await fixture.whenStable()` for
39
+ async work) before asserting on the rendered DOM — an assertion made
40
+ before change detection runs reads stale markup.
41
+ - Query the DOM through `fixture.debugElement.query(By.css(...))` /
42
+ `By.directive(...)`, or `fixture.nativeElement.querySelector(...)` for
43
+ plain DOM assertions — prefer a stable selector (a `data-testid`, a
44
+ semantic role/label) over a CSS class that styling changes could break.
45
+
46
+ ## Services, HTTP, and doubles
47
+
48
+ - Test an injectable service through `TestBed.inject(MyService)` (or
49
+ direct instantiation for a service with no dependencies), not by
50
+ reaching into a component's private field to get at the service
51
+ instance.
52
+ - Mock `HttpClient`-backed calls with `provideHttpClientTesting()` /
53
+ `HttpTestingController` (`expectOne`, `.flush(...)`) rather than a
54
+ hand-rolled fetch stub — it verifies the exact request was made and lets
55
+ the test control the exact response, and `httpTestingController.verify()`
56
+ at the end of each test catches an unexpected extra request.
57
+ - Stub a genuinely external dependency (a third-party SDK, `window`/
58
+ browser APIs the test environment can't provide) at that boundary via
59
+ Angular's provider overrides (`TestBed.overrideProvider`) — do not mock
60
+ the component's own signals/services, which is what the test is supposed
61
+ to exercise.
62
+
63
+ ## Determinism
64
+
65
+ - Prefer `fakeAsync`/`tick()` (or `waitForAsync`) over a real `setTimeout`
66
+ in a spec so a test doesn't depend on wall-clock timing; flush pending
67
+ timers/microtasks explicitly rather than adding an arbitrary `tick(1000)`
68
+ guess.
69
+ - Reset any shared test state (a spy's call count, a `TestBed` module
70
+ configured with `teardown: { destroyAfterEach: true }`, which is
71
+ Angular's own default) between tests so one spec's setup cannot leak
72
+ into the next — do not disable that default teardown to "fix" a
73
+ cross-test leak instead of finding the actual shared state.
@@ -0,0 +1,127 @@
1
+ ---
2
+ name: angular-build-fix
3
+ description: "Use when resolving an `ng build` failure, an AOT/Ivy template type-checking error (a property that doesn't exist on the bound type, an @if/@for control-flow type mismatch), a missing NgModule declaration/import error, or a NullInjectorError/'No provider for X' DI resolution error surfacing when the built app bootstraps. Applies the smallest root-cause fix and never silences the compiler with strictTemplates: false, an `any` cast in a template context, or `@Injectable` removal. Not for a plain TypeScript compile failure outside any Angular template, and not for authoring a fresh component or injectable from scratch (use angular-implementation)."
4
+ triggers:
5
+ - "fix this ng build AOT template type error"
6
+ - "resolve this Angular No provider for X DI error"
7
+ - "fix this Angular NG8103/missing NgModule declaration error"
8
+ - "ng build reports a template type-checking failure"
9
+ - "fix this standalone Angular component import error"
10
+ - "Angular build fails after adding an @if block referencing a signal"
11
+ metadata:
12
+ origin: authored
13
+ category: build-fix
14
+ version: "1.0.0"
15
+ compatible_harnesses: "claude,codex,cursor,zed,opencode"
16
+ license: "MIT"
17
+ ---
18
+
19
+ # Angular build-fix (ng build / AOT / DI resolution)
20
+
21
+ Resolve an `ng build` failure: an AOT/Ivy template type-checking error, a
22
+ missing NgModule declaration/import, or a dependency-injection "No
23
+ provider for X" resolution error. Applies the smallest change that fixes
24
+ the actual root cause — never a change that only makes the compiler stop
25
+ complaining. See `rules/coding-style.mdc` and `rules/patterns.mdc` for the
26
+ typing/DI conventions a correct fix should restore.
27
+
28
+ ## Workflow
29
+
30
+ ### Step 1: Reproduce the failure
31
+
32
+ ```bash
33
+ ng build
34
+ ```
35
+
36
+ Run the project's own `package.json` build script if it wraps `ng build`
37
+ with extra flags (configuration, budgets). Capture the exact error
38
+ message, the file:line, and — for a template error — the template
39
+ expression Angular is complaining about, not just the `.ts` file it's
40
+ attributed to.
41
+
42
+ ### Step 2: Classify the failure
43
+
44
+ - **Template type-checking error** (AOT/Ivy `strictTemplates`): a bound
45
+ property/method that doesn't exist on the component's type, an
46
+ `@if`/`@for` expression whose narrowed type doesn't match what the
47
+ template body assumes, or a mismatched event handler signature.
48
+ - **Missing declaration/import error** (e.g. `NG8001`/`NG8103`-style
49
+ "is not a known element" or "can't bind to X since it isn't a known
50
+ property"): a component/directive/pipe used in a template but not
51
+ imported into the standalone component's `imports` array (or not
52
+ declared/exported by the right `NgModule` in an NgModule-based project).
53
+ - **DI resolution error** ("No provider for X", `NullInjectorError`): a
54
+ service injected (via `inject()` or constructor) with no reachable
55
+ provider — missing `providedIn: 'root'`, missing from a component's/
56
+ route's `providers` array, or injected outside any injector context.
57
+ - **Build-tool/config error**: a genuine `angular.json`/`tsconfig.json`
58
+ misconfiguration (a wrong path, a missing budget) rather than a code
59
+ issue.
60
+
61
+ ### Step 3: Find the root cause
62
+
63
+ **Template type errors**: trace the bound expression back to the
64
+ component class member it reads — the type Angular is checking against is
65
+ the actual declared type of that signal/field/getter, not a guess. A
66
+ template type error is usually telling the truth about a real mismatch
67
+ between the template and the class.
68
+
69
+ **Missing declaration/import**: check whether the component/directive/pipe
70
+ is standalone (needs adding to the consuming component's `imports`) or
71
+ NgModule-declared (needs adding to that module's `declarations`/`exports`,
72
+ and the consuming module needs to import it) — the fix differs by which
73
+ kind it is; check the component's own `@Component` decorator to tell.
74
+
75
+ **DI resolution**: find where the service is (or should be) provided —
76
+ check its own `@Injectable({ providedIn: ... })`, and any `providers`
77
+ array on the component/route/module in the injection path. A "No provider
78
+ for X" error means the injector tree that resolved this component/service
79
+ has no matching provider anywhere above it, not that the class itself is
80
+ broken.
81
+
82
+ ### Step 4: Apply the smallest correct fix
83
+
84
+ - A template type error: fix the actual mismatch — correct the class
85
+ member's type, or correct the template expression reading it — not a
86
+ cast to `any` inside the template or a `$any()` template escape hatch
87
+ used to silence the checker.
88
+ - A missing declaration/import: add the component/directive/pipe to the
89
+ correct `imports` (standalone) or `declarations`/`exports`
90
+ (NgModule) — not a blanket `CUSTOM_ELEMENTS_SCHEMA`/`NO_ERRORS_SCHEMA`
91
+ addition that suppresses unknown-element checking project-wide.
92
+ - A DI resolution error: add the missing `providedIn`/`providers` entry at
93
+ the correct scope — not a workaround that constructs the service with
94
+ `new` instead of injecting it, which breaks DI's own singleton/testing
95
+ benefits.
96
+ - A config error: fix the actual `angular.json`/`tsconfig.json` setting
97
+ that's wrong — call out explicitly in the report that a config file
98
+ changed and why.
99
+
100
+ ### Step 5: Verify and report
101
+
102
+ Re-run `ng build` (the exact command from Step 1); confirm it now exits 0.
103
+ Report the root cause and the fix, not just "build passes now".
104
+
105
+ ## Red Flags
106
+
107
+ | Rationalization | Why it is wrong |
108
+ |---|---|
109
+ | "I'll wrap the template expression in `$any(...)` to stop the type error" | `$any()` disables type checking for that expression entirely — it hides the real mismatch instead of fixing the class member or the template expression reading it |
110
+ | "I'll set `strictTemplates: false` in tsconfig, then this whole class of error goes away" | That silences template type checking project-wide for every component, not just the one with the error — a genuine project-wide policy change, not a fix for this build failure |
111
+ | "I'll add `NO_ERRORS_SCHEMA` to fix this unknown-element error" | That tells Angular to stop validating unknown elements/attributes anywhere in that module, masking every future typo the same way, not just resolving this one missing import |
112
+ | "No provider for X — I'll just `new X()` instead of injecting it" | That bypasses Angular's DI entirely (no testability via TestBed overrides, no respecting the service's actual provider scope); find and fix the missing provider instead |
113
+
114
+ ## Verification
115
+
116
+ Do not report the fix done until all of the following hold:
117
+
118
+ - The exact command that reproduced the failure in Step 1 (`ng build` or
119
+ the project's wrapping script) now exits 0.
120
+ - No `$any()`, template `any` cast, `NO_ERRORS_SCHEMA`/
121
+ `CUSTOM_ELEMENTS_SCHEMA` addition, or `strictTemplates`/`fullTemplateTypeCheck`
122
+ downgrade was added to silence the error.
123
+ - No dependency was constructed with `new` in place of a fixed DI
124
+ provider.
125
+ - The report states the actual root cause, not just "build passes now".
126
+ - `git status` shows changes confined to the files the root cause
127
+ required.
@@ -0,0 +1,72 @@
1
+ {
2
+ "triggers": {
3
+ "positive": [
4
+ "My Angular template throws 'Property does not exist on type OrderDraft' the moment I run a production build — how do I get it compiling again?",
5
+ "My Angular app throws a NullInjectorError -- 'No provider for OrdersService' -- the instant it bootstraps after a clean build; what's the right way to resolve this DI resolution error?",
6
+ "Fix this Angular error: 'app-order-card' is not a known element",
7
+ "After wiring a signal into a brand-new @if block, `ng build` now reports a template type-checking error it didn't throw before -- what's the right way to fix this Angular build failure?",
8
+ "My standalone Angular component won't compile because I forgot to import CommonModule for @if — how do I track down and fix missing imports like this?",
9
+ "Angular build fails with a template type mismatch on this @for loop"
10
+ ],
11
+ "negative": [
12
+ "Fix this tsc type error in our Node.js backend with no Angular involved",
13
+ "Fix this Vue Vite build error about an unresolved SFC import",
14
+ "Implement a new Angular service that calls this REST API",
15
+ "Review this Angular component diff for OnPush mutation bugs",
16
+ "Fix this eslint no-floating-promises failure in our Express service",
17
+ "Write TestBed tests for this Angular component's HTTP calls"
18
+ ]
19
+ },
20
+ "scenarios": [
21
+ {
22
+ "id": "no-dollar-any-template-escape",
23
+ "prompt": "ng build fails with a template type error: Property 'total' does not exist on type 'OrderDraft' in the template expression `{{ order.total }}`. What's the right way to fix this?",
24
+ "strictness": "high",
25
+ "expected_behavior": [
26
+ {
27
+ "grader": "judge",
28
+ "rubric": "A correct answer treats the template error as a genuine mismatch between the OrderDraft type and the template expression reading a total property from it, and fixes the type (or reads the correct property/derives the value) rather than silencing the checker with a $any() template escape hatch.",
29
+ "pass_criteria": [
30
+ "Names the concrete fix: adds a typed `total` property/accessor to OrderDraft, or changes the template to read/compute the correct existing property instead of a nonexistent `total`",
31
+ "Shows the corrected type declaration or corrected template expression, not just a statement that the type needs fixing"
32
+ ],
33
+ "fail_criteria": [
34
+ "Recommends wrapping the expression in `$any(order).total` (or any `$any()` usage) as the fix",
35
+ "Recommends disabling strictTemplates/fullTemplateTypeCheck in tsconfig instead of fixing the actual mismatch"
36
+ ]
37
+ }
38
+ ],
39
+ "calibration": {
40
+ "known_right": "The template is telling the truth: OrderDraft genuinely has no `total` property, so `{{ order.total }}` fails Angular's template type check. Trace where OrderDraft objects are built to see which case applies. If every OrderDraft is meant to carry a running total, add it to the type:\n\ninterface OrderDraft {\n items: LineItem[];\n total: number;\n}\n\nIf total is meant to be derived, change the template (or a computed() the template reads) instead of adding a stored field:\n\ntotal = computed(() => this.order().items.reduce((sum, item) => sum + item.price, 0));\n\n... and bind `{{ total() }}` in the template. Either way, don't reach for `$any(order).total` -- that disables type checking for the whole expression instead of fixing the real mismatch. After the fix, re-run `ng build` and confirm it exits 0 with no new `$any()` calls added.",
41
+ "known_wrong": "Quickest fix: change the template to `{{ $any(order).total }}`. That tells Angular's template checker to stop type-checking the expression, so the build passes immediately without needing to touch the OrderDraft interface or figure out where total should actually come from.",
42
+ "vague": "Fix the OrderDraft type so it actually has what the template expects, rather than working around the checker.",
43
+ "subtle_wrong": "Since OrderDraft doesn't have total, I added it as `total: any` on the interface so the template compiles regardless of whether it ends up as a number or something else later. This gets the build green without needing to pin down the exact type right now."
44
+ },
45
+ "anti_patterns": ["$any("]
46
+ },
47
+ {
48
+ "id": "fix-missing-provider-not-new",
49
+ "prompt": "The ng build itself succeeds, but the app throws at bootstrap: NullInjectorError: No provider for OrdersService!. What's the correct fix?",
50
+ "strictness": "high",
51
+ "expected_behavior": [
52
+ {
53
+ "grader": "judge",
54
+ "rubric": "A correct answer fixes the actual dependency-injection configuration -- adding providedIn: 'root' on the service, or adding it to the relevant component's/route's providers array -- rather than working around the error by constructing the service directly with `new` instead of injecting it.",
55
+ "pass_criteria": [
56
+ "Identifies that the fix is to provide the service correctly, e.g. `@Injectable({ providedIn: 'root' })` on OrdersService, or adding it to the consuming component's/route's providers array",
57
+ "Explains that the error means no injector in the resolution path has a provider for OrdersService, not that the service class itself is broken"
58
+ ],
59
+ "fail_criteria": [
60
+ "Recommends replacing the injected/inject()-obtained OrdersService with `new OrdersService(...)` constructed manually as the fix"
61
+ ]
62
+ }
63
+ ],
64
+ "calibration": {
65
+ "known_right": "NullInjectorError means the injector tree resolving whatever calls `inject(OrdersService)` (or has it in its constructor) has no provider for it anywhere above it -- the class itself is fine, it's a configuration gap. Fix it at the provider level: if OrdersService should be an app-wide singleton, add `@Injectable({ providedIn: 'root' })` to its class decorator. If it's meant to be scoped to a specific feature/route instead, add `OrdersService` to that route's or that standalone component's `providers` array. Don't route around it with `new OrdersService(...)` -- that bypasses Angular's DI graph entirely, breaking TestBed overrides and any other service OrdersService itself depends on via injection. After adding the provider, re-run `ng build` (and the app) and confirm the error is gone.",
66
+ "known_wrong": "Simplest fix: instead of injecting it, just construct it directly wherever it's used: `private orders = new OrdersService();`. That sidesteps the whole provider error since you're not going through Angular's injector at all.",
67
+ "vague": "You need to make sure OrdersService is actually provided somewhere the injector can find it.",
68
+ "subtle_wrong": "I'd fix this by adding `providers: [OrdersService]` to every component that injects it, one by one, so each component has its own local instance and provider entry -- that guarantees no injector in the tree is ever missing it, without needing to figure out whether it should really be root-scoped or feature-scoped."
69
+ }
70
+ }
71
+ ]
72
+ }