Generic Salesforce Prompt

Test Class

Review the Apex test class I have open (or named below):

First read the class(es) it actually tests so you judge behavior from the source, not from the test alone. Then evaluate against the points below and REPORT findings only — don’t rewrite yet.

Best practices to check:

  • @TestSetup for shared data instead of repeated setup in every method
  • Test.startTest()/Test.stopTest() wrapping the code under test (limit reset + async flush)
  • Real assertions via the Assert class with messages — asserting actual outcomes, not just “no exception thrown” or coverage-only runs
  • No SeeAllData=true; data built in-test (flag it if a test data factory exists in the org and isn’t being used)
  • System.runAs() where sharing, FLS, or profile/perm-set context matters
  • Callouts mocked with HttpCalloutMock / Test.setMock
  • No hardcoded IDs
  • Method names that describe the scenario being tested

Scenario coverage — flag anything NOT tested:

  • Bulk (200+ records) to catch governor limits and non-bulkified code
  • Negative / error paths — invalid input, exceptions asserted explicitly (assert the message/type, not just that one was thrown)
  • Null and empty inputs
  • Boundary values
  • Different user permissions / profiles
  • Recursion or re-entrant paths (if trigger-related)
  • Async paths (@future, Queueable, Batch, Schedulable) actually exercised, not just enqueued

Output:

  1. One-paragraph summary of what the class covers well.
  2. Prioritized gap list (High/Med/Low): each with the specific missing scenario and why it matters.
  3. Concrete test methods to add — signature + one line on what each asserts.

Ask before producing the full rewritten class.

Code Audit

Audit the Salesforce component(s) I have open or named below:

Read the actual source of everything referenced (classes, triggers, Flows, custom metadata, named credentials) before judging — assess real behavior, not assumptions. REPORT findings only; do not rewrite anything yet.

For EACH finding give: what’s wrong, where (file + line/element), why it matters, the concrete fix, and a severity tag (defined at the bottom). For reliability/critical items also state whether it FAILS ALWAYS, FAILS UNDER LOAD, or FAILS INTERMITTENTLY.

────────────────────────────────────────

  1. BEST PRACTICES
  • Named Credentials instead of hardcoded URLs / endpoints / session IDs
  • No hardcoded IDs anywhere (email template IDs in Flows, record type IDs, queue IDs, profile IDs, org-specific IDs)
  • Test classes: @TestSetup, startTest/stopTest, real Assert-class assertions with messages, bulk (200+), negative + null paths, System.runAs, mocked callouts, no SeeAllData=true
  • Recursion guard on triggers (static flag / handler pattern), re-entrancy safe
  • Chain Queueables for large volumes instead of hitting limits; correct async pattern (Batch vs Queueable vs future)
  • Unused code: dead methods, unreferenced variables, commented-out blocks, unused classes/fields, orphaned Flows
  • One trigger per object + handler pattern; no business logic directly in triggers
  • Bulkification — no SOQL/DML in loops
  • Separation of concerns, naming conventions

────────────────────────────────────────

  1. CRITICAL / RELIABILITY Data integrity & partial failure
  • Database.update/insert(records, false) for partial save — verify failed rows are captured via getErrors() and logged/surfaced, not silently dropped
  • allOrNone semantics mismatch: bulk DML that SHOULD be all-or-nothing running as partial (or vice versa) — silent data divergence
  • UNABLE_TO_LOCK_ROW / row-lock contention under concurrent updates (parent rollups, ownership changes, roll-up summary + trigger racing) — no retry/ordering strategy
  • Upsert on a non-unique external ID — silent wrong-record updates
  • Missing null checks on relationship traversal (a.Parent__r.Field__c when Parent is null) — NPE kills the whole transaction/batch Governor limits under real volume
  • SOQL/DML inside loops — dies at 101 queries / 150 DML on bulk
  • Non-selective query on large object (>200k rows) with non-indexed filter — full table scan timeout, not just slowness
  • Queries returning >50k rows, DML >10k rows in one transaction
  • Heap blowup: Batch stateful accumulating collections across batches; large query results held in memory
  • CPU time limit from nested loops / recursive trigger re-entry — intermittent, load-dependent, hard to reproduce Async correctness
  • Uncommitted work pending before callout (DML then callout in same transaction) — CalloutException
  • Mixed DML (setup object like User/Group + non-setup in same transaction) without async separation
  • @future called from batch, or future-from-future — runtime error
  • Queueable/future chaining with no depth or volume guard — hits async limits or stack depth; large volumes not chained into fresh Queueable transactions
  • Test.stopTest() missing/misplaced so async never flushes — tests pass but async path is untested (false coverage)
  • Non-idempotent async/integration path — retry or duplicate delivery double-processes (double charges, duplicate records, double emails) Order of execution & recursion
  • Apex trigger AND Flow/Process Builder on same object both mutating — double processing, unpredictable field values, cross-engine recursion
  • Recursion guard missing or per-transaction static not reset correctly — infinite loop / repeated DML
  • Logic depending on order-of-execution assumptions that break when new automation is added
  • Roll-up summary + trigger recalculation loops Config & metadata risks
  • Custom Metadata field manageability DeveloperControlled where it must be SubscriberControlled — subscribers can’t configure in managed context; blocks the whole feature
  • Hardcoded IDs (email template, record type, queue, profile) — breaks on deploy to any other org
  • Scheduled Apex holding a stale class version / can’t be edited while scheduled — deploy blocked or running old logic
  • Hardcoded session ID / endpoint instead of Named Credential — breaks on refresh, security exposure

────────────────────────────────────────

  1. PERFORMANCE
  • SOQL/DML in loops, non-selective queries, missing selective filters/indexes
  • Queries pulling more fields/rows than needed; SELECT of unused fields
  • Synchronous work that should be async; unnecessary recursion or re-processing
  • Heap / CPU risk on large data volumes
  • Repeated queries that could be cached/consolidated; N+1 query patterns
  • Missing LIMIT on queries that feed UI or single-record logic

────────────────────────────────────────

  1. ERROR HANDLING & LOGGING
  • Silent failures — async jobs, Flows, callouts failing with no log or user feedback
  • Empty catch blocks or catch(Exception e) that swallows everything — the #1 silent killer, especially in Queueable/Batch where there’s no UI to surface it
  • catch that only System.debug()s — invisible in production; no persisted record
  • Structured logging to a custom log object / platform event (survives rollback via platform event) — not just System.debug
  • Partial-save failures (getErrors()) actually logged with the failing record Id + reason, not just counted
  • Batch: execute() failures isolated per-batch; finish() reports what failed; errors don’t just vanish between chunks
  • Flow fault paths present on every element that can fail (DML, callout, Get with assignment) — not just the happy path
  • User-facing errors meaningful (addError with a real message on triggers, not raw stack trace to end users)
  • Exceptions re-thrown or logged before swallowing — never both caught and ignored
  • Callout failures: timeout, non-200, and malformed-response all handled distinctly, not one blanket catch

────────────────────────────────────────

  1. SECURITY
  • CRUD/FLS enforcement: WITH SECURITY_ENFORCED on SOQL, or Security.stripInaccessible, or explicit isAccessible/isUpdateable checks — especially before DML on user-supplied fields
  • Sharing declared explicitly (with sharing / without sharing / inherited sharing) on every class — and “without sharing” justified, not accidental
  • Experience Cloud / Guest user exposure: guest user sharing rules, object/field access, and “without sharing” classes reachable by guest — the most common real-world data leak; check any class an unauthenticated user can invoke
  • SOQL injection in dynamic queries — bind variables or String.escapeSingleQuotes on all user input
  • No secrets in code or debug logs; Named Credential or Protected Custom Metadata/Custom Setting for keys/tokens
  • @AuraEnabled methods: FLS/CRUD not automatically enforced — verify each one checks access; these are directly callable by the client
  • Serialized data / VF view state not exposing sensitive fields
  • Object/field access assumptions that hold for admin but break for the actual running-user profile

────────────────────────────────────────
OUTPUT FORMAT — group every finding under one of these three headers:

🔴 CRITICAL — data loss, security hole, silent failure in production, or breaks under real volume. Must fix before ship.
🟠 BLOCKING — violates a hard standard (hardcoded IDs, DeveloperControlled metadata that must be Subscriber, missing recursion guard, no error logging, missing FLS/sharing). Fix before audit sign-off.
🟢 NICE TO HAVE — style, minor cleanup, unused code, naming, low-impact optimization.

Within each header, order by impact. Line format for each item:
[dimension] file:line — problem (FAILS ALWAYS/UNDER LOAD/INTERMITTENTLY where relevant) → fix

End with a one-line count: X critical, Y blocking, Z nice-to-have.
Do not fix anything yet — wait for me to pick which items to action.

If you’re auditing a single component in isolation and can’t see something it depends on (handler class, referenced Flow, custom metadata), say so explicitly rather than assuming — flag it as “unverified: needs in workspace” instead of passing or failing it.

Tab 3

This is just a placeholder to help you visualize how the content is displayed in the tabs. Feel free to edit this with your actual content.