Skip to content

factory-pitfalls

Synced from factory-kit/skills/factory-pitfalls.md at v0.1.2. The source of truth is the factory-kit repo.

The skills are now structured Principle → Why → Recipe → Failure mode, with each anti-pattern co-located with the principle it violates. This file is a flat scan across those failure modes plus process-level pitfalls that don’t fit any one skill.

  • At project kickoff. Read this index; ensure the starting setup avoids the top-tier pitfalls (no test coverage, no DECISIONS.md, hardcoded allowlist).
  • In code review. Scan recent diffs for matches; link the relevant skill section in the PR comment.
  • After incidents. Add the failure mode to the skill where its principle lives (not here); if it doesn’t fit any skill, add a process pitfall below.

Each entry: one line, pointing at the skill section that owns it.

  • Mixed tRPC + server actionsfactory-api.md §API style — pick one
  • Custom auth adapter when an official one existsfactory-auth.md §Better Auth — plugin composition
  • Triple-fallback auth surface (Clerk → token → header)factory-auth.md §The wrapper interface
  • No auth at all (publicProcedure everywhere)factory-auth.md §Auth from day one
  • Hardcoded email allowlistfactory-auth.md §Hardcoded email allowlists
  • Admin client at module scopefactory-auth.md §Admin client — always wrapped
  • Monolithic 1,500-line formfactory-forms.md §Modular section files from day one
  • Two-way state-DB syncfactory-frontend.md §One direction of truth
  • Currency formatting drift across viewsfactory-frontend.md §Format helpers
  • Querying inside JSONB at app speedfactory-data-layer.md §Custom attributes as JSONB
  • Raw SQL with hand-mapped row→objectfactory-data-layer.md §ORM pick
  • Mixed migration-file namingfactory-data-layer.md §Migration file naming
  • Pre-built libs/py-libs/ before second consumerfactory-data-pipelines.md §Don't pre-build shared libs
  • Pydantic models copy-pasted across entry pointsfactory-data-pipelines.md §Three-entry-point pattern
  • Pydantic state for LangGraphfactory-llm-workflows.md §State shape
  • No versioning on editable content (chat vs claims)factory-llm-workflows.md §Version anything editable later
  • In-memory rate limiter on serverlessfactory-security.md §Rate limiting
  • PHI in email without runtime BAA checkfactory-security.md §PHI in email/SMS
  • AI-generated code without a review queuefactory-security.md §AI-generated code — read-only by default
  • Migrations at runtime (in Cloud Run CMD)factory-deployment.md §Migrations — CI, never runtime
  • Regenerated trace IDs at service hopsfactory-observability.md §Trace ID — propagate, don't regenerate
  • Commits with no Linear linkagefactory-commits.md §Tie every commit to a Linear issue

These are kit-shape and project-shape failures that don’t fit any one skill’s domain. They live here.

Three competing solutions for the same problem

Section titled “Three competing solutions for the same problem”

Legacy applicationProgress.ts, intermediate sectionProgress.ts, and unified progress-calculator.ts all live in the same repo. The newer file is the source of truth but the older ones never got deleted.

Right move: when you write a unifier, delete the inputs in the same PR. Half-finished refactors are worse than untouched code — they imply the newer file is the truth while leaving the older ones as plausible alternatives that future contributors will pull from.

A production-grade CRUD repo with zero test coverage. Nothing to extract as a “testing skill” because tests have to be authored from scratch.

Right move: Vitest + a smoke test for each feature folder from project setup. Add to the project’s DECISIONS.md as a layer-3 commitment.

Decision-criteria choices (which auth, which UI lib, which API style) get relitigated each session. The kit’s factory-stack.md documents the criteria; the project’s DECISIONS.md records the picks.

Right move: every new project starts with a DECISIONS.md containing one-line entries per decision-criteria choice from factory-stack.md. Update on every architectural call.

Implies intent without value. New contributors interpret the empty directory as “this is where convention lives” and put unrelated things there.

Right move: delete empty stubs. If intent matters, write the placeholder explicitly with TODO: so future-you knows what was planned.

CLAUDE.md describing the architecture you wish you had, not the one the code actually has. New contributors get the wrong mental model. AI agents read it and propose work against a fiction.

Right move: treat CLAUDE.md as code. Update in the same PR as the refactor. If you write an AGENTS.md or CLAUDE.md, make it load-bearing or delete it.

Inconsistent CLAUDE.md formats across repos

Section titled “Inconsistent CLAUDE.md formats across repos”

Each new project relitigates the format. The kit’s template (see CLAUDE.md in the kit’s root) is the canonical shape — extend it per project, don’t reinvent.

Right move: copy the kit’s CLAUDE.md template into the project’s root, fill in the project-specific bits (domain, decisions, layout). Same shape every time.