[schemas] CRM core: editable contacts + field-proposal truth layer#393
[schemas] CRM core: editable contacts + field-proposal truth layer#393alanshurafa wants to merge 1 commit into
Conversation
OB1 PR Gate✅ Folder structure — All files are in allowed directories Result: All 15 checks passed! Ready for human review. Post-Merge TasksThese don't block merge — they're reminders for admins after this PR lands.
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5d69eafb0b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| c_known_keys CONSTANT TEXT[] := ARRAY[ | ||
| 'display_name', 'preferred_name', 'given_name', 'family_name', 'pronouns', | ||
| 'job_title', 'organization_name', 'location', 'relationship_note', | ||
| 'lifecycle_status', 'privacy_tier', 'owner_label' | ||
| ]; |
There was a problem hiding this comment.
Allow canonical email updates through the truth layer
Because crm_create_contact accepts and stores p_canonical_email, but this allowlist omits canonical_email, any later crm_patch_contact_record call for that field—also the path used when accepting a contact_field proposal—raises unknown contact field before reaching the update. That leaves a created canonical email impossible to correct through the advertised editable/proposal RPC layer unless callers bypass it with direct table writes.
Useful? React with 👍 / 👎.
| ELSE | ||
| UPDATE public.crm_contact_methods | ||
| SET label = NULLIF(trim(COALESCE(p_label, '')), ''), | ||
| is_primary = COALESCE(p_is_primary, is_primary), |
There was a problem hiding this comment.
Preserve primary status when re-upserting a method
When an existing contact method is re-added without explicitly setting p_is_primary (the default is false), this assignment overwrites a previously primary method to false; the accept path for contact_method proposals also passes false, so accepting a duplicate proposal for the current primary email/phone silently leaves the contact with no primary method. Preserve is_primary on existing rows unless the caller explicitly promotes another method.
Useful? React with 👍 / 👎.
Adds
schemas/crm-core: an editable contact book on top of Open Brain with a human-in-the-loop truth layer.Six tables (
crm_contacts,crm_contact_methods,crm_contact_aliases,crm_contact_change_log,crm_field_proposals,crm_field_evidence) plus RPCs give each contact field per-field provenance and a propose/accept/reject flow: a human writes canonical fields directly, while a machine or agent must propose a change instead of overwriting one. A human then accepts (apply + log) or rejects (discard + log). A pending proposal never mutates the live field. Field locks let a human freeze a field against all writers. Contact-method values are redacted in the audit log.Every primary key is UUID and every memory reference is
UUID REFERENCES public.thoughts(id).Self-contained under
schemas/crm-core/; idempotent (IF NOT EXISTSthroughout). Includes README + metadata.json.Testing: applied on an ephemeral Postgres alongside the full schema stack; composes cleanly.