Problem explored: AI agents generate thousands of lines per hour, but discard all their reasoning at commit time. The reviewer stares at a diff with zero context for why choices were made. What if the agent briefed the human — not as a diff summary, but as a first-person account of its architectural decisions, alternatives considered, and what it flagged for human judgment?

Brief source:
Agent-generated
AI-inferred
Open AI-generated
Migrate auth to shared middleware layer
+291 / −56 lines 8 files changed branch: feat/auth-middleware
Agent Brief
I made 4 architectural decisions while implementing this. I'm confident in 3 of them. I've flagged 1 decision specifically for your judgment — it involves an assumption I cannot verify from the codebase alone.
3 high confidence
1 flagged for review
Decisions reviewed: 0 / 4
1
Architecture High confidence
Auth moved from individual routes to shared middleware

23 routes required explicit @requireAuth decorators. Any new route added without it would silently be unauthenticated. Middleware makes the secure path the default — routes must opt out, not opt in.

Decorators + a custom ESLint rule to catch missing ones. Rejected — linter rules are bypassable, don't run at runtime, and fail open (the route is accessible if the linter isn't run).

View relevant code — middleware/auth.ts +47 −0
middleware/auth.ts (new file)
+import { Request, Response, NextFunction } from 'express';
+import { verifyToken } from '../lib/jwt';
+import { PUBLIC_ROUTES } from '../config/routes';
+
+export function authMiddleware(
+ req: Request, res: Response, next: NextFunction
+) {
+ if (PUBLIC_ROUTES.includes(req.path)) return next();
+ const token = req.headers.authorization?.split(' ')[1];
+ if (!token) return res.status(401).json({ error: 'Unauthorized' });
+ try {
+ req.user = verifyToken(token);
+ next();
+ } catch {
+ return res.status(401).json({ error: 'Invalid token' });
+ }
+}
2
Interface High confidence
PUBLIC_ROUTES config added as explicit allowlist

Any route that should be publicly accessible (/health, /docs, /auth/login) must be listed explicitly. I chose an allowlist over a denylist because a denylist fails open — forgetting to deny a route is a security gap. Forgetting to allow a route just returns 401, which is recoverable.

Route-level @public decorator for each public route. Same coverage, but requires touching each route file and is easy to forget on new routes. Rejected in favor of a single config location.

View relevant code — config/routes.ts +12 −0
config/routes.ts (new file)
+/**
+ * Routes that bypass auth middleware.
+ * Prefer allowlisting here over @public decorators per-route.
+ */
+export const PUBLIC_ROUTES = [
+ '/health',
+ '/status',
+ '/docs',
+ '/auth/login',
+ '/auth/register',
+] as const;
3
Cleanup High confidence
Removed 23 per-route @requireAuth decorators

With middleware in place, per-route decorators are now redundant — auth runs twice if both are present. I removed all 23 instances. Each was verified against the PUBLIC_ROUTES allowlist before removal to ensure no route became unprotected.

The @adminOnly and @roleRequired decorators are not removed — those express authorization (who can use a route), not authentication (whether you're logged in). They're layered on top of auth and remain unchanged.

View relevant code — routes/users.ts (representative)
routes/users.ts
import { Router } from 'express';
-import { requireAuth } from '../middleware/requireAuth';
import { UserController } from '../controllers/user';
const router = Router();
-router.get('/profile', requireAuth, UserController.getProfile);
-router.put('/profile', requireAuth, UserController.updateProfile);
-router.delete('/account', requireAuth, UserController.deleteAccount);
+router.get('/profile', UserController.getProfile);
+router.put('/profile', UserController.updateProfile);
+router.delete('/account', UserController.deleteAccount);
4
Infrastructure Flagged for review
Session storage changed from in-memory to Redis
⚠️
⚠️
This decision requires your judgment. I changed the session storage mechanism, but I don't have visibility into your deployment environment. Please verify before approving.

Replaced the in-memory Map<string, Session> with Redis. In-memory sessions don't survive server restarts and don't work across multiple instances. Redis solves both.

I don't know your Redis deployment setup. If Redis is unavailable at startup, the server will throw and fail to boot. If Redis goes down in production, all active sessions fail silently — users are logged out. I don't know if either of these is acceptable, and I can't determine it from the codebase.

View relevant code — lib/session.ts
lib/session.ts
-import { Session } from './types';
+import { createClient } from 'redis';
+import { Session } from './types';
-const sessions = new Map<string, Session>();
+const redis = createClient({ url: process.env.REDIS_URL });
+await redis.connect();
-export async function getSession(id: string): Promise<Session | null> {
- return sessions.get(id) ?? null;
-}
+export async function getSession(id: string): Promise<Session | null> {
+ const raw = await redis.get(`session:${id}`);
+ return raw ? JSON.parse(raw) : null;
+}
Review complete
You evaluated the decision surface of this PR in under 3 minutes — not by reading 347 lines, but by adjudicating 4 architectural choices.
Open AI-generated
Migrate auth to shared middleware layer
+291 / −56 lines 8 files changed
config/routes.ts
+12−0
lib/session.ts
+38−14
middleware/auth.ts
+47−0
routes/admin.ts
+2−12
routes/api.ts
+3−10
routes/users.ts
+3−12
server.ts
+8−4
tests/auth.test.ts
+178−4
Where do you start? 8 files. 347 lines. Alphabetical order. No context for what changed or why.

Is the Redis change intentional? Did all 23 decorator removals check out? Is there anything in server.ts worth worrying about?

Switch to "With Brief" to see the same PR with the agent's reasoning.