Skip to content

crm_contact models a postal address as five flat text fields while crm_account and crm_lead use Field.address() — and AGENTS.md's own guidance names Field.address() for exactly this #1836

Description

@os-steve

Blocked-by: objectstack-ai/objectstack#20149

Observation-class finding, noticed while working #1827 (which gave the five flat fields their missing form surface). ⛔ Deliberately not changed there — this is a data-model question with an importer contract and a migration behind it, not a form-layout fix.

The inconsistency

Three objects in this app carry a postal address, and they are modelled two different ways.

object field shape
crm_account billing_address Field.address({ … }) — one structured value with street / city / state / postalCode / country parts
crm_lead address Field.address({ … })
crm_contact mailing_street · mailing_city · mailing_state · mailing_postal_code · mailing_country five independent text / textarea fields

AGENTS.md's Field Type Guidance table takes a side:

| Mailing address | Field.address() | Structured postal address |

So the contact is the outlier against both its sibling objects and this repo's own written guidance.

Why it may nevertheless be deliberate

src/mappings/contact_import.mapping.ts states the flat shape as a decision, in its header:

"Address lands in the flat mailing_* text fields, which is why contacts (unlike accounts and leads) carry address columns in their template."

and src/mappings/account_import.mapping.ts refers to the same split from the other side. So somebody knew. What is not on the record is the reasoning — the comment states the consequence (contacts get five CSV columns) rather than the reason, and no ADR or ruling is cited. A reader today cannot tell a considered modelling choice from an accident that was later described.

There is also a plausible historical reason worth checking before anyone acts: #664 (closed) reported Field.address() values rendering as raw JSON on the detail page. If the flat shape was chosen to dodge that renderer, the premise may have expired — that would need re-measuring against the pinned @objectstack/console@17.4.0 rather than assumed in either direction.

What a change would actually cost

Not a rename. Converting crm_contact to Field.address() moves:

That is why this is filed rather than done, and why it wants a decision before an implementation.

What is being asked for

A ruling on which shape crm_contact should carry, recorded where the next reader will find it:

  • keep the flat fields — then say why in contact.object.ts, so the deviation from AGENTS.md is an authored decision rather than a silent one, and consider whether the guidance table needs a caveat;
  • convert to Field.address() — then it is a migration card with the surfaces above enumerated, and the importer contract change needs its own call.

⛔ This finding takes no side. It records that the two objects disagree, that the guidance names one of them, and that the reason is nowhere on the record.

Refs: #1827 (where it was noticed) · #664 (the address renderer defect, closed).


Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    metadataDeclarative metadata — schema, security posture, UI surfaces

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions