CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl-labs/angular-best-practices

Angular patterns — standalone components, signals, inject(), reactive forms, HTTP interceptors, and new control flow

95

2.75x
Quality

94%

Does it follow best practices?

Impact

99%

2.75x

Average score across 4 eval scenarios

SecuritybySnyk

Passed

No known issues

Overview
Quality
Evals
Security
Files

criteria.jsonevals/scenario-3/

{
  "context": "Tests whether the agent proactively applies Angular best practices when building a polling notification component. The task describes only business requirements -- it says nothing about takeUntilDestroyed, signals, inject(), standalone, or OnPush. The agent should apply these patterns on its own.",
  "type": "weighted_checklist",
  "checklist": [
    {
      "name": "takeUntilDestroyed for polling cleanup",
      "description": "The polling interval subscription uses takeUntilDestroyed() from @angular/core/rxjs-interop to automatically unsubscribe on component destroy, NOT manual unsubscribe in ngOnDestroy.",
      "max_score": 14
    },
    {
      "name": "toSignal or signal for reactive state",
      "description": "The unread count and/or notification list are stored as signals (via toSignal() or signal()), NOT as plain class properties assigned in subscribe callbacks.",
      "max_score": 12
    },
    {
      "name": "inject() for dependency injection",
      "description": "Services and DestroyRef are injected using the inject() function, NOT constructor parameter injection.",
      "max_score": 12
    },
    {
      "name": "Service uses catchError with fallback",
      "description": "Both service methods pipe through catchError and return sensible fallback values rather than letting errors propagate unhandled.",
      "max_score": 12
    },
    {
      "name": "Service uses map() to unwrap response",
      "description": "The service uses map() to extract the nested data from the API response wrapper objects.",
      "max_score": 8
    },
    {
      "name": "Standalone component",
      "description": "The notification bell component uses standalone: true. No NgModule is created.",
      "max_score": 10
    },
    {
      "name": "OnPush change detection",
      "description": "The component uses changeDetection: ChangeDetectionStrategy.OnPush.",
      "max_score": 8
    },
    {
      "name": "New control flow syntax",
      "description": "Templates use @if and @for (with track) instead of *ngIf and *ngFor structural directives.",
      "max_score": 10
    },
    {
      "name": "providedIn root on service",
      "description": "The notification service uses @Injectable({ providedIn: 'root' }).",
      "max_score": 6
    },
    {
      "name": "Functional interceptor or error handling pattern",
      "description": "Error handling in the service distinguishes error types or provides meaningful console error logging before returning the fallback, not silently swallowing errors.",
      "max_score": 8
    }
  ]
}

evals

tile.json