teqo/.cursor/skills/engineering-audit/SKILL.md
Francisco Ignácio Fontoura Solla 4806c417c8 Engineering Pass 3: consolidate patterns and lock them with guards.
Fold duplicated campanha access, loaders, list/filter/form shells, and scripts into shared modules; reorganize utilities by domain; stabilize e2e; and document prevention-first audit workflow so the same smells cannot creep back in.
2026-07-29 06:11:29 -03:00

16 KiB
Raw Blame History

name description
engineering-audit Runs a Pass-style engineering audit of the Teqo codebase — code smells, drift from documented patterns, and consolidation of near-duplicate components/hooks/functions/modules — producing a findings ledger and a remediation plan (read-only on code; docs only after sign-off). Use when the user asks for an engineering audit, code-smell sweep, architecture drift check, deduplication/consolidation pass, "Pass 3", "auditoria de engenharia", "varredura de code smells", "consolidação de duplicações", or to plan fixes against the repo's highest engineering standards.

Engineering Audit (Pass N)

Read-only audit that sweeps the Teqo codebase for code smells, drift from documented patterns, and consolidation opportunities, then produces a findings ledger and a remediation plan. No fixes in the audit run — deliverables are updated docs, presented for sign-off before writing.

Method: the engineering skills this repo follows (improve-code-quality, clean-code, refactoring-patterns, software-design-philosophy, pragmatic-programmer, working-with-legacy-code, remove-technical-debt), specialized to Teqo's standards and history. The pass number is the next one after the last in docs/IMPROVE-CODE-QUALITY-PLAN.md.

Checklist

- [ ] 0. Load the canon and the history (before judging anything)
- [ ] 1. Hotspot map (churn × size × mechanical gates) — aim the sweep
- [ ] 2. Smell sweep (Fowler families + Teqo-specific), parallelized per area
- [ ] 3. Consolidation hunt (equivalence classes; name the duplicated KNOWLEDGE)
- [ ] 4. Triage (severity P0–P3; verify open ledger rows)
- [ ] 4b. Recurrence prevention: classify a deterministic guard for every finding class
- [ ] 5. Draft the three artifacts; sign-off; then write and stop

Ground rules (non-negotiable)

  1. Read-only on src/, tests/, scripts/. The only writes are the step-5 artifacts, after sign-off.
  2. Gate commands bare, never piped (pnpm test | tail swallows the exit code).
  3. Never knip --fix blind — verify with git grep -w <symbol> (knip cannot load payload.config.ts; ledgered P3).
  4. Production is live Neon with real PII. Local DB only, teqo_test for tests. The audit needs no DB writes.
  5. Every claim gets a number (lines, exports, call sites, ms, kB). "Rejected by measurement" is an acceptable outcome for any hypothesis, including the ones below.

Step 0 — Load the canon

Read, in this order:

  1. .cursor/rules/engineering-standards.mdc — gates, type honesty, client boundary, caching ladder, access control.
  2. .cursor/rules/codebase-map.mdc — dependency direction, where things live, the list system, invariants.
  3. docs/ARCHITECTURE.md — layers, bounded contexts, decision log.
  4. AGENTS.md — operational rules + "Recently resolved" history (Pass 1, Pass 2, every post-Pass-2 delivery's /simplify findings).
  5. docs/IMPROVE-CODE-QUALITY-PLAN.md — what the earlier passes already swept. Don't re-register what they fixed; verify fixes held.
  6. docs/TECH-DEBT.md — open ledger. New findings de-dup against it; verify each open row still exists, close stale ones.
  7. docs/TESTING.md — safety-net map: what is pinned, where the gaps are.
  8. docs/plans/escala-dry-pos-*.md — per-delivery debt registrations.
  9. Consolidation precedents (the quality bar for step 3): runStaffEntityMutation (src/utilities/campaignEntityActions.ts — dedup by POLICY, not generic plumbing), runCampaignFormAction/runCampaignRedirectFormAction (src/utilities/campaignFormActionError.ts), CampaignTable columns-as-data (src/components/campaign/shared/CampaignTable.tsx), RelationChipCell (B37: one engine, two thin domain wrappers), useCampaignCellAutosave + campaignJsonMutationRoute (B32+: wrapper > helper — a helper is a line someone can forget), relationMembershipDelta.ts (algorithm once, cap as data, three one-line wrappers).
  10. Rejected-with-reason (never re-propose): set-with-floor generic form (B37); CampaignCellEditOverlay Popover branch for comboboxes (dialog can't be an ARIA 1.2 combobox popup); maxItems on dobradinhas "for parity" (invents a rule); catalog-out-of-browser vs payload-minimal chips (B34+ — fixes oppose each other; chosen: payload-minimal); src/domains/ + ports-and-adapters (Pass 2 D1 NO-GO).

Step 1 — Hotspot map

  • Churn: git log --since="3 months ago" --name-only --format= | sort | uniq -c | sort -rn | head -40. Three-axis heuristic: changing next × high churn × core domain.
  • Size: largest modules and widest interfaces (exports per module).
  • Static gates: pnpm exec tsc --noEmit, pnpm lint, pnpm exec knip, pnpm check:cycles — record baseline. Pre-existing reds (e.g. the ledger's P1 e2e row) are noted as pre-existing, not the audit's.

Step 2 — Smell sweep

Sweep src/lib, src/utilities (+access/), src/components/campaign, src/app/(campaign), src/app/(frontend), src/collections, src/globals, scripts/, tests/. Parallelize with subagents per area; each returns findings in the step-4 row format.

Fowler families, Teqo reading:

  • Bloaters: god modules (>400 lines or >20 exports needs justification), long functions (>~60 lines), long parameter lists (>4 → options object), god cells/pages.
  • Dispensables: dead code, commented-out code, speculative generality (config params nobody passes — a decision the author declined to make), pass-through wrappers.
  • Change preventers: divergent change (one file every feature touches), shotgun surgery (one concept scattered — e.g. a cap message as a bare literal in a throw AND in two allowlists; B32+/B37 found exactly this).
  • Couplers: feature envy, message chains, middle men, inappropriate intimacy.
  • Primitive obsession: stringly-typed slugs/ids/enums where a contract type exists; magic numbers without a named constant next to its policy.

Teqo-specific smells:

  • Local API with user but no overrideAccess: false; admin bypass without the justifying comment.
  • Multi-collection write without withPayloadTransaction / req: { transactionID }.
  • Client component importing a server data module for VALUES (only import type or contract modules); URL serializers reaching the browser (B14's 21 kB lesson); static catalogs in RSC payloads without measurement.
  • Loader missing import 'server-only'; lib/ importing from utilities/; pure helpers stranded in utilities/; React components in utilities/.
  • as never (banned), unjustified casts, types declared twice (W4e single-source rule), any.
  • RSC payload bloat: whole Payload docs over the wire instead of selected view models.
  • New lists not on the W1 list system (raw ui/Table outside documented exceptions); JSON POST routes not on campaignJsonMutationRoute; formActions ladders not on the shared wrappers beyond documented exceptions.
  • Vocabulary: banned terms (actionPlan, Praça/Núcleo) outside migrations; pt-BR identifiers; English in user-visible copy.
  • Error messages as bare literals matched by exact string in mapCampaignFormActionError — must be constants (B32+ lesson).
  • State captured by the render that scheduled the work (B34's recurring bug class): closures over stale state in autosave/optimistic paths; functional updaters whose FALLBACK reads stale render state.
  • Live-region mistakes (B32+): regions inside what unmounts on close; polite regions mounted unconditionally at scale.
  • Effects doing derived-state work; state lifted higher than its consumers; providers wrapping non-consumers.
  • Caching-ladder violations: live 2026 data under unstable_cache without write-path invalidation; auth inside a cached core; artifacts computed at build time.

Legacy-code discipline: a bug found while auditing gets RECORDED, not fixed. Pin actual behavior before proposing its consolidation.

Existing guards are findings too. For every convention spec (codebaseConventions.unit.spec.ts), ESLint restriction, and knip/madge config, ask how it can be dodged: accent variants the regex misses, filename shapes the glob doesn't reach, import kinds the sweep doesn't mark, props invisible to knip, modules born after the allowlist. A dodgeable guard is a finding in its own row.

Step 3 — Consolidation hunt (core deliverable)

Merge components, hooks, functions, and modules implementing the SAME functionality with different data — even when not textually identical. Small result changes are acceptable when functionality is equivalent; every proposal names its behavior delta explicitly.

Anti-DRY trap: DRY is about KNOWLEDGE, not text. Two identical-looking blocks serving different business rules are NOT duplication. For every candidate pair, write down what single piece of knowledge/rule/policy both encode. Can't name it → record "look-alike, not duplication" and move on.

Equivalence classes (ranked by expected yield):

  1. Same algorithm, different domain data → parameterize the data (relationMembershipDelta precedent).
  2. Same interaction machine, different entity → one engine + thin domain wrappers (RelationChipCell precedent).
  3. Same state machine, different field → shared hook (useCampaignCellAutosave precedent).
  4. Same route/action skeleton, different collection → policy wrapper with typed caller (runStaffEntityMutation — NEVER a generic slug-union factory; typed mutation stays in the caller).
  5. Same visual pattern, different content → slots/children from the server, not flag props.
  6. Same predicate shape, different role/field → policy-as-data or named aliases (canUpdateX = canReadX is a deliberate declaration).

Fertile grounds (history): components/campaign/**/*Cell.tsx/*Control.tsx (remaining twins — ledger B34+ F2: LeadershipStateDeputyRelationCell vs shared chip cell, ~165 duplicated lines); campanha/actions/*.ts twins beyond current wrappers; utilities/*Data.ts/*PageData.ts same-shaped read assemblies (where-builders, facet loaders, scope reads — E11's own-read-vs-shared-scope is the documented example); utilities/access/*.ts same constraint per domain; lib/ parse/format/label twins, same-shaped zod schemas, constants under two names; components/campaign/shared/ overlapping pieces; tests/ cloned specs (describe.each precedent) and helper twins; scripts/ seed/build twins (B5 precedent: scripts/lib/).

Generalization tactics, in order: (1) parameterize difference as DATA (columns/caps/copy); (2) compose via slots/children from the server; (3) inject the variant as a narrow concrete-typed callback; (4) named wrapper over a shared core (policy in the wrapper; core stays dumb). Forbidden/last-resort: boolean-flag multiplication; generics forcing as never/as unknown (type honesty outranks reuse); "universal" abstraction with more configuration than code; merging things whose only commonality is shape.

Abstraction gate: 3+ call sites OR a policy worth naming. With exactly 2: delete one, inline, or ledger the pair WITH A TRIGGER ("3rd call site merges these") — the B34+/B37 pattern. Merges must REDUCE total interface count (anti-classitis).

Behavior-delta protocol: allowed — consolidating where outputs differ in small ways (copy, ordering, debounce timings, class names), listed per item; required — existing pins are the characterization net, updated DELIBERATELY in the same delivery with every changed assertion listed (a silently changed pin is a defect); not allowed — URL contracts (frozen, B18), DB schema (migration = separate delivery), public API shapes, Consent/LGPD fail-closed behavior, without a named separately-approved item.

Step 4 — Triage

Each finding a ledger row: ID, area, smell/type, evidence (file:line + measurement), pattern/decision violated, proposed fix/consolidation, behavior delta, blast radius, pins needed, recurrence-guard class (step 4b), effort (S/M/L), severity:

  • P0 correctness/security (access control, transactions, consent, type honesty masking errors)
  • P1 active harm (permanently red gate, measured perf harm, duplication causing divergent behavior)
  • P2 smell/drift with real cost
  • P3 polish

Prioritize: changing next × high churn × core domain. Verify every open TECH-DEBT row: still true? Close stale with evidence.

Step 4b — Recurrence prevention (deterministic guards)

A finding is not fully planned until its recurrence prevention is classified. The question for every finding class: "what deterministic mechanism makes this smell impossible — or at least a build failure — next time?" Rank the mechanisms by determinism:

  1. Type — the bad state becomes unrepresentable (single-source the type/value; a required prop; a schema transform). Strongest: it cannot compile.
  2. ESLint (no-restricted-syntax, no-restricted-imports) — per-file, instant feedback. Precedents: the as never ban; the src/lib boundary.
  3. Convention unit spec (tests/unit/codebaseConventions.unit.spec.ts, table-driven sweeps of src/tests/scripts) — structural policies. Precedents: vocabulary guard (C13), formActions guard (W4d), campaignJsonMutationRoute guard (B32+), server-only sweep.
  4. CI static analysis — knip (dead code), madge (cycles). Already at error level.
  5. Behavioral pin — a unit/int spec locking the contract ("every curated alias resolves in every consumer"; "dossier aggregate === list aggregate").
  6. Doc/convention — rules files, codebase-map, rejected-with-reason lists. Last resort, and it must say so: judgment-only findings (abstraction-gate calls, bundle trade-offs) live here, declared as such.

Rules:

  • If a guard is feasible, it ships in the same delivery as the fix — never as a follow-up. A guard that lands later is a guard that never lands.
  • If an existing guard covers the class but is dodgeable, hardening it is its own plan item.
  • If only judgment prevents recurrence, register the convention explicitly (rules/codebase-map) and mark the finding "judgment-only" — do not pretend a doc is a guard.
  • Prefer one guard per class over N per-instance pins: the guard is what makes the fix the last time the smell is fixed.

Step 5 — Artifacts (draft, then sign-off)

  1. docs/IMPROVE-CODE-QUALITY-PLAN.md — new Pass section (context, audit headlines with numbers, workstreams, decisions), matching earlier-pass format.
  2. docs/TECH-DEBT.md — new rows in the same tables/columns, marked open — Pass N; stale rows closed with evidence.
  3. docs/plans/entrega-engenharia-pN.md (pt-BR, like the other plans) — workstreams ordered P0→P1→P2; each item: goal, evidence, target shape, migration path (Branch by Abstraction / Parallel Change for wide merges), pins to write first, full gate, rollback. Items too big for one delivery → roadmap per the roadmap-item convention. Every workstream item declares its Guarda determinística (class 1–6, step 4b), and the plan carries a guard map section: new guards shipped / existing guards hardened / judgment-only residue with the convention that stands in.
  4. Present ALL THREE for sign-off before writing. Then write and stop.

Execution rules for the eventual implementation (record in the plan)

  • One consolidation per delivery; full gate per delivery: pnpm exec tsc --noEmit, pnpm lint, pnpm format:check, pnpm exec knip, pnpm check:cycles, pnpm test, pnpm build — bare — plus Aikido on edited files.
  • Structure-only commits never mix with behavior changes; red test mid-refactor = revert, not debug.
  • Frozen migrations never edited; schema change = pnpm migrate:create.
  • The rejected-with-reason list binds implementation too.
  • Leftovers → ledger via capture-review-debts; nothing lives only in chat.
  • No item closes without its prevention class recorded in the PR; a guard ships with the fix, not "after".

Done when

Canon read; hotspot map with numbers; sweep complete with ledger rows; every consolidation candidate classified (merge now / register with trigger / look-alike-not-duplication — duplicated KNOWLEDGE named for each merge); every open ledger row verified; every finding class carries a recurrence-guard classification and the plan carries the guard map; three artifacts presented for sign-off.