.agents/skills/deep-review/references/dimensions/ai-coding-bad-habits.md
Detect locally plausible but mechanically incomplete code: changes that compile in isolation while ignoring semantic scope, static type information, refactor closure, explanatory comments, or repository precedent. "AI coding" names the recurring implementation habits, not the author or provenance — review observable code and never speculate about who wrote it.
This dimension is not a license to report personal taste. Every finding must identify a concrete cost: misleading reading flow, duplicated policy, stale names, redundant runtime work, a missed compatibility boundary, or divergence from an established repository pattern.
Use this dimension for the specifically mechanical pattern: code that is locally plausible but
globally unfinished. If the same root cause is fully covered by code-style (an isolated
readability issue) or reuse-architecture (a proven duplicate, wrong layer, or bypassed extension
seam), report it there instead; never emit the same finding twice.
type, status, or mode; keep variant policy in its owning layer or make the
exceptional condition explicit at the decision point.const newName = oldName remains even
though no caller needs it. Complete the semantic rename across the affected unit, following the
repository's file-naming convention.typeof, in, isRecord, defensive
optional chaining, or cast-and-check logic revalidates values whose static type and callers
already guarantee the shape. Confirm the type with LSP/type definitions first. For genuinely
untrusted structured input, validate once at the boundary — prefer an existing schema (often Zod
in this repo) over scattered ad-hoc guards.Use these examples to recognize the shape of a bad habit, not as keyword-matching rules. Verify the declared types, callers, repository convention, and compatibility boundary before reporting.
const getBlockErrorType = (reason: string) =>
reason === 'IMAGE_PROHIBITED_CONTENT' ? ErrorType.ContentPolicyViolation : undefined;
// Inside a shared stream parser:
type: getBlockErrorType(finishReason);
type and getBlockErrorType read like the generic owner of error classification, but the helper
only hides one image-generation condition. Keep the condition explicit at the decision point when
that is clearest, or move the policy into the image/provider adapter that owns it.
// register-file-work.ts
export const registerWork = async () => {
// ...
};
export const registerFileWork = registerWork;
If no released caller needs compatibility, rename the file, tests, imports, and adjacent concepts according to repository convention, then remove the alias. Renaming only the export leaves two names for one concept and makes readers search for a migration that does not exist.
interface Work {
id: string;
}
const getWorkId = (work: Work) =>
isRecord(work) && typeof work.id === 'string' ? work.id : undefined;
work.id is already guaranteed by the in-process type. Use it directly. If the value came from
JSON, an SDK, or another trust boundary, parse it once with the existing WorkSchema and pass the
validated Work onward instead of repeating guards at every use.
// First check whether the cache has a value.
// If it does, return it.
if (cached) return cached;
Delete narration that merely restates control flow. Keep a comment when it explains the durable
reason, for example: // Ignore v1 cache entries because they lack the workspace isolation key.
useEffect(() => {
lambdaClient.work.list.query().then(setWorks);
}, []);
If same-kind features in the repository use a store SWR hook → service → lambdaClient pipeline,
the direct component call is precedent-blind even though it works locally. Follow the established
route, or document the constraint that makes this feature different.
AGENTS.md / CLAUDE.md — repository-wide naming, comment, and workflow conventions.agents/skills/typescript/SKILL.md — static typing, runtime validation, and type-guard conventions.agents/skills/project-overview/SKILL.md — ownership and layer boundariestesting, drizzle, trpc-router, zustand,
builtin-tool, etc.) — use its established pattern as the primary precedentRun five focused passes: