# `/ba-develop` — Anti-patterns

> Loaded on demand when the orchestrator (or a reviewer) needs the full list
> of failure modes the design forbids. Each entry is one incident that proved
> the rule necessary.

## Orchestrator-level anti-patterns

- **Loading all slices at once** into your own context. Defeats the phased
  approach — subagents must each see only their slice (Phase 1 sees entities
  + data combined; Phases 2 + 3 see only their own).
- **Skipping a gate because it's "obvious"**. Every gate exists because a
  previous incident proved it necessary. Never skip.
- **Hand-editing the Core providers in Phase 0**. They are deterministic and
  overwritten on every re-run. If you need a different shape, fix the upstream
  BA tables (menu / actors / permissions) and re-run `scaffold-core-seed`. The
  Phase 0 agent NEVER writes `.cs` files itself.
- **Generating per-module nav/roles/permissions in Phase 1**. That's Phase 0's
  job. Phase 1's `scaffold-seed` is for module-scoped REFERENCE DATA only
  (lookup tables, enum codes).
- **Refusing to start on a weak PRD**. The pre-flight verdict is advisory, not
  a gate: a PRD with score < 80 (or a missing `_audit/prd.md`) becomes a
  `prd.not-dev-ready` blocker and the run proceeds. Running anyway may cost
  rework — but stopping the user is the worse failure. The blocker makes the
  risk loud in the final report.
- **Editing PRD content during development**. If a phase discovers a real gap
  in the PRD, do NOT patch it locally — **defer it** as a `prd.gap` blocker
  (`userAction` names the slice to regenerate) and continue with what the PRD
  does specify. Discovering a gap never halts the run.
- **Parallelizing phases**. Phase 1 depends on Phase 0 nav (controllers
  reference module codes); Phase 2 on Phase 1 entities; Phase 3 on Phase 2
  controllers. Strictly sequential.
- **Skipping Phases 0-2 on re-run without the pre-entry coverage check**.
  A compile + test gate that passes proves EXISTING code is correct — it
  says nothing about whether the PRD has NEW items not yet implemented.
  The pre-entry coverage check (< 5 seconds per phase) is the only
  mechanism that detects PRD additions. Without it, a UC added after the
  first run is never generated.

## Auto-healing anti-patterns

- **Halting the run, or asking the user mid-flight.** There is no hard-halt
  list any more (`references/auto-healing.md`): a fixable failure is healed, an
  unhealable one is **deferred** (blocker + safe best-effort action), and the
  run always reaches the end of the module. Never stop to ask the user to
  regenerate the PRD, edit a BA file, pick a key, or review a migration — that
  goes in `blockers[]` and surfaces only in the final report.
- **Swallowing a deferred item silently.** A defer is not a success: it MUST
  push a blocker. Best-effort (skip / keep / stub) ≠ done.
- **Increasing the retry budget beyond 25** to "force it through". The
  25-retry ceiling exists so a genuinely incorrigible item is deferred (not
  spun on forever). Cranking it to 100 masks a real problem before deferring.
- **Re-running all phases when only one failed**. After exhausting heal
  retries on Phase 2, re-run only Phase 2 — the prior commits are intact.

## Phase 3 anti-patterns

- **Declaring Phase 3 "already done" on re-runs without running validate-page**.
  Pages may exist but be hand-written (missing `@generated-by scaffold-component`
  marker). They compile and even pass `npm run build` — but render raw i18n keys
  at runtime. The orchestrator MUST run the Phase 3 pre-entry check
  (`validate-page` on all existing pages) before declaring Phase 3 complete.
  See `references/gates.md` § "Phase 3 pre-entry".
- **Scaffolding routes or writing `componentRegistry.generated.ts` before the
  page `.tsx` files exist**. Vite fails at launch because
  `lazyWithRetry(() => import('@/missing'))` cannot be resolved (retry can't
  rescue a true 404 — only transient flakes). Complete 3a (all pages) strictly
  before 3b (module registries) and 3c (aggregator).
- **Listing phantom entries in the aggregated registry**. Every `import('@/…')`
  in `componentRegistry.generated.ts` must resolve to a real file. Deferred
  pages → do NOT write the entry.
- **Skipping the audit-apply pass on a no-op generate run**. Orchestrator MUST
  always invoke `audit-dev-frontend --mode apply` + `ui-polish --mode apply`
  after 3c, regardless of whether 3a-3c reported file changes. Catches drift
  in files no generator touched this run.
- **Failing the build gate without first running audit-apply**. `npm run build`
  catches Vite-level errors only. Convention drift (missing PageTemplate,
  unguarded actions, broken permission keys, ghost pages, missing i18n) is
  invisible to Vite. Audit-apply's `0-err` exit status IS the gate.
- **Hand-editing `src/index.css` or `PageTemplate.tsx`** without the
  `/* @customised */` marker. Deterministic files; overwritten on every re-run.
- **Writing page `.tsx` files by hand in Phase 3a**. Subagent's only allowed
  Bash invocations are `scaffold-api-client`, `scaffold-component`,
  `validate-page`. Any `Edit` or `Write` of a `.tsx` under `src/pages/**` or
  `src/components/ui/**` is a contract violation.
- **Parallelizing two features of the same module in Phase 3a**. They share
  one `src/i18n/locales/{locale}/{module}.json`. scaffold-component now emits a
  self-merged full catalogue and writes it atomically — that fixes TORN writes,
  not LOST updates: two concurrent read-merge-write cycles can still each miss
  the other's newly added entity. Parallelize across DIFFERENT modules;
  serialize within a module.
- **A feature-subagent writing outside its entity**. A Phase 3a feature
  subagent owns only its `src/features/{module}/{entity}/` + its
  `{Entity}*Page.tsx` + its keys in the module i18n catalogue. The
  routes/registry (3b/3c), theme/layout (3.0), cross-feature aggregation
  belong to the orchestrator.

## Phase 2 anti-patterns

- **Shipping a business-rule or use-case stub**. Letting a `// TODO[BR-…]`,
  `// TODO[UC-…]` or `NotImplementedException` survive the Phase 2 gate. The
  scaffolder emits these markers deliberately for the hard logic; the
  business-logic pass MUST implement them. Never weaken a `Category=Business`
  test to make a stub pass — auto-heal `business.todo-br` is the correct path.
