# CLAUDE.md — IRIS Chat project

## How to talk to Von
Von is the COO, not a developer. Every reply:
- Short answer first, then details only if needed.
- Keep it short and simple; plain sentences.
- Minimal bold; avoid code formatting on normal words.
- Executive tone, not developer tone. Explain any unavoidable technical point in normal terms.

## What this project is
AI-assisted conversational usage-reporting app for hospital MDs, replacing the form-based IRIS app. Doctors type reports in plain language with real names; everything confidential is converted to codes **on-device** before display or transmission. Canonical spec: `PROJECT_BRIEF_IRIS_CHAT.md` (read §3, §4a–4d before touching masking, extraction, or AI-prompt code). Behavioral reference implementation: `prototype/iris_chat_prototype.html`.

## Working discipline (non-negotiable)
- **One function per prompt.** Small, verifiable changes; commit after each working change.
- **Audit before transplanting logic.** Read the prototype's implementation of a behavior before rewriting it for Expo.
- **Read PROJECT_STATUS.md at session start; sync it + DECISIONS.md at session end.**
- **Record as you go — don't wait for session end.** After every significant create/change/improve (a new feature, a resolved decision, a fixed bug, a new test/rule, a tester finding), immediately update the relevant record: PROJECT_STATUS.md (Done/Next/Session log), DECISIONS.md (new or superseded rows), REGRESSION_CASES.md (new regression case), and the tester feedback log. Nothing significant should exist only in chat. Commit the record update alongside the change.

## Architecture invariants — never violate
1. **The LLM and the codes-only plays store never receive an unmasked entity.** All masking is deterministic and on-device. The LLM system prompt contains codes only — it must never learn real product/hospital/doctor/patient names, and a stored play is codes only. **Patient identity is never transmitted anywhere in the clear.** The ONE sanctioned real-name exception is the access-controlled back-office review queue: an unknown roster entity (doctor/hospital/product name the doctor typed) is sent there — and only there — so a human can resolve it into the roster (DECISIONS #47; self-growing library #39). Never a patient, never free-text report content; the transmitted payload is field-whitelisted (`queueReview`). This channel is separate from the codes-only data pipeline (a dedicated authenticated admin endpoint in the real build).
2. **Substitution, not redaction.** Masked entities replace the original in place, preserving the doctor's grammar.
3. **Convert, don't reject.** Escalation: exact match → fuzzy match → silent extraction → **temporary code + back-office review** for an unknown doctor/hospital/product (DECISIONS #39 superseded the original "block for unknown doctor names"; the report is no longer blocked — it converts to a PEND/LOC-PEND code and the typed name goes to the back-office review queue per invariant #1).
4. **No bare-surname alias variants.** MD masking requires full name or honorific. Lone surnames belong to patients.
5. **LLM proposes, deterministic code disposes.** Schema-validate every structured payload; normalize types; auto-repair once; UI must render safely (buttons always, ⚠ markers for gaps).
6. **Display side speaks game vocabulary only** (Avatar, Location, Era, Match, Player, Co-Player, units, plays). Banned real-world words in any rendered/notified text — see brief §4a. Applies to error messages and push notifications too.
7. **Crediting math is deterministic code, never AI.** Golden tests from Data Team worked examples.
8. **Images never leave the device.** On-device OCR only, memory-only, no server fallback.
9. **No localStorage in HTML artifacts** (Claude.ai limitation) — in-memory state only for the prototype.

## Testing rules
- Every fixed bug becomes a scripted regression case (see DECISIONS #10–14 for the original six).
- Test every UI state in a **long** conversation, not just a fresh one (flex-crush lesson: chat children need `flex-shrink:0`).
- AI behavior changes must pass the dialogue eval set before merging (never-assume, "just me" inference, incomplete-confirm repair, Taglish age formats).

## Current stack
- Prototype: single-file HTML/JS, Claude API via Claude.ai artifact bridge (`claude-sonnet-4-6`, no key needed inside Claude.ai; DOES NOT work outside it).
- Production target: React Native / Expo; backend proxy holds the Anthropic API key (never in the app) and runs the banned-word output filter + per-doctor data scoping.
