golid-ai/golid
AI-native factory for Go + SolidJS apps — Cursor rules, spec drift CI, plans, and a production starter with auth, SSR, S
Actual rules from this repo
Path in source repo: .cursor/rules/audit-bugs.mdc · format: mdc
---
description: Bug audit checklist — use when asked to review code for bugs, security issues, or quality problems
alwaysApply: false
---
# Bug Audit Checklist
> **Thesis:** Run this checklist against any file or module being reviewed.
> Each item references a real bug found in this codebase.
## When to Run
Use `workflow-routing` first when the user asks for review/audit depth or when
the diff crosses T2/T3 triggers; this checklist is scoped by that tier.
Two trigger points, not just one:
1. **Pre-merge gate** — before declaring a card/feature "done", run the relevant section of this checklist against every file you touched. ~20% of recent commits are post-hoc audit cleanup; running this proactively converts those into the original commit. This is the highest-ROI use.
2. **On demand** — when explicitly asked to audit, review for bugs, or grade code quality.
The checklist below is the same for both; only the trigger differs.
## Evidence Requirements
A finding isn't "audited" until you've produced one of:
- **File path + function name + line range** for the offending pattern (e.g., `service/feature/feature.go::Create lines 45-52`).
- **`rg` command + match count** for codebase-wide patterns (e.g., `rg "_ = pool\.Exec" -g '*.go' | wc -l → 3 hits`).
- **"Verified clean"** with the search you ran, when no instances exist (e.g., `rg "createResource" frontend/ → 0 hits`).
"Looks fine" is not an audit result. If you can't cite the search, you didn't run it.
Core patterns (`apperror`, parameterized SQL, `batch()`, Switch/Match, `createResource`, alive guard) — see `codebase-standards`. Frontend fetch — `solidjs-data-fetching`. Route UI — `solidjs-pages`.
## Audit Strategy
A single audit pass catches ~60-70% of real issues. Each pass has blind spots due to which files get read first, which patterns the search focuses on, and attention saturation on large codebases. To maximize coverage:
1. **Run multiple independent passes with different focus areas** — e.g., one pass for reactive patterns, one for auth/security, one for config consistency, one for the fork/rename story. Narrow scope finds more than broad sweeps.
2. **Vary the search strategy** — don't just follow this checklist. Grep for known anti-patterns (`return () =>` in `.tsx`, `_ =` in `.go`, `any` in component props). Read files the checklist doesn't mention (entry-server.tsx, rename tool, CI config, env files).
3. **Check reference implementations are textbook-perfect** — `app.tsx`, `login/index.tsx`, `dashboard/index.tsx`, and `settings/index.tsx` are copied by the scaffold tool and by AI assistants. A bug in these propagates everywhere.
4. **Verify the tool chain, not just the code** — rename tool, scaffold templates, deploy scripts, and CI config can have bugs that downstream users inherit silently.
5. **After fixing issues, re-read the fixed files** — fixes can introduce new problems (e.g., a rename tool step that corrupts URLs by naively replacing project names inside domain strings).
## Backend Service Files
- [ ] **SQL injection** — `fmt.Sprintf` with values or identifiers in SQL? Use `$N` placeholders (see `codebase-standards`).
- [ ] **Missing transactions** — any method with 2+ writes that isn't wrapped in `Begin/Commit`?
- [ ] **Silent error discards** — `_ = fn(...)` or `_ = pool.Exec(...)`? Log errors (see `codebase-standards`).
- [ ] **ErrNoRows masking** — any `_ = pool.QueryRow(...)` that ignores real DB errors? Must check `err != nil && err != pgx.ErrNoRows`.
- [ ] **Role-only auth** — any method that checks `userType` but not specific resource membership? Must use `verifyXAccess`.
- [ ] **Missing status guards** — can the method be called on inactive/completed/cancelled parent entities? Add guards.
- [ ] **echo.NewHTTPError usage** — use `apperror.X()` instead (see `codebase-standards`).
- [ ] **TIMESTAMPTZ scan into *string** — nullable `TIMESTAMPTZ` columns CANNOT scan into `*string`. Must scan into `*time.Time` then format: `if t != nil { s := t.Format(time.RFC3339); field = &s }`.
- [ ] **ON CONFLICT without UNIQUE constraint** — any `ON CONFLICT (col1, col2)` requires a matching `UNIQUE` index on those columns. Without it, PostgreSQL returns a runtime error.
- [ ] **Hardcoded values in service constructors** — names, emails, URLs should come from config/env, not hardcoded strings.
- [ ] **Missing `rows.Err()` after `rows.Next()` loops** — partial iteration errors are silent without this check. Every `for rows.Next()` must be followed by `if err := rows.Err()`.
- [ ] **`apperror.NotFound("X not found")` double-suffix** — `apperror.NotFound(resource string)` formats its argument as `"%s not found"`, so `apperror.NotFound("User not found")` emits the user-facing string `"User not found not found"`. Pass the bare resource noun (e.g. `apperror.NotFound("User")`, `apperror.NotFound("Invoice")`). The May 26 audit found this pattern in 7 production sites — the formatter contract is non-obvious and the double-suffix surfaces in real API responses.
- [ ] **Bare `err == pgx.ErrNoRows` instead of `errors.Is(err, pgx.ErrNoRows)`** — direct equality breaks the moment any caller wraps the error with `fmt.Errorf("...: %w", err)`. The codebase has 110+ bare-equality sites (May 26 audit); they work today only because nothing wraps before the comparison. Use `errors.Is` defensively — same one-line fix, future-proof against wrapping.
## Backend Handler Files
- [ ] **Missing requireUserID/requireUserType** — every protected handler must extract auth.
- [ ] **Business logic in handler** — DB queries or complex logic should be in the service layer.
- [ ] **Missing request validation** — required fields should be checked before calling service.
## Frontend Route Files
- [ ] **Nested `<Show>` for content states** — use flat `Switch/Match` (see `solidjs-pages`).
- [ ] **Missing `batch()` on async signal updates** — wrap post-`await` signal updates in `batch()` (see `solidjs-data-fetching`).
- [ ] **Missing `defer: true
Content truncated. View full file in the source repo (linked above).
Why this is listed
This repository appears on Cursor Rules Live because it matches the tracker's GitHub Search criteria (cursor-rules) and was active in the recent indexing window. The tracker refreshes every 15 minutes, so the metadata above reflects the state at the most recent index pass. If the data here looks stale, the source repository may have been archived or moved out of the tracked topic; the next cron tick will reconcile.