✗ A blanket "always 3NF for data-entry tables" instruction — too crude. It fights the PC bright line, the SmartForms-from-JSON model, and over-normalizes pure snapshots. It would make the code worse in real cases.
✓ Codify the decision rule above — yes. Put it in the
pact-writer /
createspec data-modeling checklist + one line in backend
CLAUDE.md, so every new clinical table gets the question asked before a migration is written.
// data-modeling rule (proposed drop-in)
One-to-many clinical data defaults to a normalized child table.
A JSON column is allowed only when the data is read/written solely as a whole
aggregate AND never queried by sub-field AND never feeds billing / GIQuIC / the med-or-prep engines.
Clinically-decisive facts (medications, allergies, anticoagulation) are always normalized;
a JSON snapshot may sit alongside for point-in-time fidelity, but is not the source of truth.