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
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.
crm_accountbilling_addressField.address({ … })— one structured value withstreet/city/state/postalCode/countrypartscrm_leadaddressField.address({ … })crm_contactmailing_street·mailing_city·mailing_state·mailing_postal_code·mailing_countrytext/textareafieldsAGENTS.md's Field Type Guidance table takes a side: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.tsstates the flat shape as a decision, in its header:and
src/mappings/account_import.mapping.tsrefers 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.0rather than assumed in either direction.What a change would actually cost
Not a rename. Converting
crm_contacttoField.address()moves:mailing_addressfield group;assets/import-templates/contacts.csv— a customer-facing contract, five columns collapsing to one structured target;crm_contact.mailing_*fields: the CSV importer writes them and the authored contact form may show none of them — clear the last 5field-no-consumerswarnings blocking #1581 (epic #1579) #1827, and the synthesized detail screen;content/docs/sales/contacts.mdxand its.zh-Hans/.zh-Hantsiblings, which describe "five separate fields" by name;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_contactshould carry, recorded where the next reader will find it:contact.object.ts, so the deviation fromAGENTS.mdis an authored decision rather than a silent one, and consider whether the guidance table needs a caveat;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
addressrenderer defect, closed).Generated by Claude Code