# AI Prompt Engineering Rules for ShopProQuote

All AI features (AI Write, Smart Upsell, Priority Analysis, Daily Briefing) run via local Ollama (qwen2.5:14b at `/llm/v1/chat/completions`). These rules prevent the LLM from fabricating information, ignoring provided context, or responding in unhelpful ways.

## Rule 1: NEVER fabricate vehicle conditions

The LLM has NOT inspected the vehicle. It only knows year/make/model, mileage, and the service catalog. **Never let it invent inspection findings.**

**Bad prompt signals** (these give the LLM permission to fabricate):
- "Be proactive about what the customer likely needs"
- "this mileage/condition warrants this service" (the word "condition")
- "suggest what's wearing out"

**Good prompt signals**:
- "You have NOT inspected this vehicle and do NOT know its actual condition."
- "NEVER invent or assume a condition. Do NOT say anything is leaking, worn, cracked, failing, low, dirty, or due unless referencing a manufacturer mileage interval."
- "Every reason MUST cite either: (a) a mileage milestone, or (b) a known complementary pairing."

**Real example of LLM fabrication**: User had "Front Mount Motor" selected. LLM suggested "Replace shocks because they are leaking." The LLM had no inspection data — it invented the leak.

## Rule 2: System prompt must explicitly command use of additional context

If you pass extra data (technician notes, vehicle mileage, interval data) in the user message but only mention the service name + recommendation in the system prompt, the LLM will follow the system prompt literally and IGNORE the extra data.

**Fix requires ALL FOUR changes:**
1. Move the additional context INTO the system prompt body with a prominent header: `"ADDITIONAL CONTEXT FROM THE TECHNICIAN:\n${additionalContext}"`
2. Add an explicit numbered task: "3. If technician notes are provided, incorporate that specific information into the explanation"
3. Add a WITH_NOTES example showing exactly how to incorporate notes
4. Increase sentence count limit when notes are present (2-4 → 3-5)

Missing any one of these four → the LLM still ignores the notes.

## Rule 3: Compute occurrence counts for mileage-based recommendations — EXPLICIT BOUNDARY CASES

When a service has a `maintenanceInterval` and the vehicle has mileage, compute interval boundaries explicitly. The LLM needs ALL FOUR cases spelled out or it will guess wrong.

```
occurrence = floor(mileage / interval)
currentBoundary = occurrence × interval
```

**Four output cases** (give the LLM worked examples for each):
1. **Due now** (mileage == boundary): e.g. 90,000 ÷ 30,000 = 90,000. "This service is due now."
2. **Past due** (mileage > boundary): e.g. 95,000 ÷ 30,000 → boundary 90,000, 5,000 miles past. "This service is 5,000 miles past due."
3. **Approaching** (mileage within 2,000 of next boundary): e.g. 88,000 ÷ 30,000 → boundary 90,000. "Approaching 90,000 miles — this service will be due soon."
4. **Well before** (mileage far from boundary): e.g. 75,000 ÷ 30,000 → boundary 90,000. "Next due at 90,000 miles."

**CRITICAL**: Include "NEVER subtract the last-done mileage. ONLY compare current mileage against interval boundaries." The LLM will otherwise subtract "last done at 60K" from "current 90K" and claim it's 30K past due — which is wrong.

**Pitfall (fixed June 2026)**: Old instructions only had two cases (occurrence ≥ 1, or approaching next). The LLM guessed the "past due" case and usually got it wrong by subtracting last-done mileage instead of comparing against interval boundaries.

Use an `ordinal()` helper: 1→1st, 2→2nd, 3→3rd, 4→4th, etc.

## Rule 4: Daily Briefing — anti-Team prompt

The LLM defaults to addressing groups as "Team" when role-playing as a foreman. To make it address a specific person:

```
System: "You are speaking directly to [Name], a service advisor. You are NOT a foreman addressing a team. ALWAYS address [Name] by their first name. Never say 'Team' or 'everyone.'"
```

Soft instructions ("address them by name") are ignored. Must be explicit and negative ("NOT a foreman. Never say Team.").

## Rule 5: Time-of-day greeting

Never hardcode "Good morning". Compute from `new Date().getHours()`:
- < 12: "Good morning"
- < 17: "Good afternoon"
- else: "Good evening"

## Rule 6: Consequence of inaction

Every AI Write explanation must end with what could happen if left unaddressed. Use qualifying language ("may potentially lead to", not "will cause"). One sentence max.

## Rule 7: AI Suggest — require minimum suggestions

Without explicit minimums, the LLM returns 0-1 suggestions. With "at least 2 services" + mileage tiers, it reliably returns 2-4. The prompt must specify both a minimum count and the mileage thresholds.

## Rule 8: Catalog data must be rich

The LLM needs price, duration, and category to make informed suggestions. Sending only service names produces generic, unhelpful recommendations. Include: name, category, price, duration, maintenanceInterval.

## Rule 9: Suppress mileage mentions for non-interval services (AI Write)

When AI Write generates an explanation for a non-interval service (brake pads, belts, leaks, mounts — anything the technician FOUND rather than a scheduled maintenance item), the mileage should NOT be mentioned in the customer explanation text. It sounds robotic and repetitive, especially when AI Write is used on multiple services in the same RO.

**Implementation** (in `api.js` `handleAiWrite`):
- Only include mileage in `additionalContext` when `maintenanceInterval` is also present
- For non-interval services, pass mileage as background-only with explicit instruction: `"Vehicle mileage (for context only — do NOT mention this in the explanation unless the service itself is mileage-based): X miles"`
- Prompt rule: `"Only mention mileage in the explanation if the service has interval data. Skip mileage entirely for non-interval services (e.g., brake pads, belts, fluid leaks) unless the service name explicitly includes a mileage milestone."`

**Pitfall (fixed June 2026)**: Old code always appended `"Current mileage: X miles"` to every AI Write prompt, and the prompt instructed the LLM to always mention it. Every explanation said "at X miles, your..." — redundant and unnatural.
