Found while migrating hotcrm onto the 17.4.0 line (hotcrm#1807, hotcrm PR #1814). Filed unassigned, observation class.
The new field-no-consumers rule (shipped from #15922, HotCRM's retired local scanner as design input) reported 12 fields on the first real app to take it. The findings are useful — several are genuine display gaps. But all 12 are visible and editable in the product today, and two categories may be worth a ruling before app teams start removing columns to clear the count.
1. A synthesized layout names nothing, so a field only reachable through it reads as unconsumed
The rule's own message enumerates what counts: "no view column, form section, page binding, flow node, dataset, widget, formula, validation, hook or action names it." Every one of the 12 carries a group, every group is a declared fieldGroup, and most of these objects render through the synthesized detail/form layout rather than an authored *.page.ts. A synthesized layout names nothing, so those fields are unnamed in metadata while being on screen.
Concretely: crm_contact.mailing_street / mailing_city / mailing_state / mailing_postal_code / mailing_country render as the mailing_address field group on the synthesized contact layout, and each is additionally an import-mapping target, so the CSV importer writes them. The verdict is carrier-only.
There is a ruling neighbourhood here already: #7427 refers to a "previews-count-as-consumers ruling". Whether a synthesized layout is the same kind of consumer is the open question. Both answers are defensible — what is expensive is app teams guessing.
2. A hidden: true seeder-only identity column is unconsumed by construction
crm_forecast.seed_key is hidden: true, readonly: true, and its own description says "Demo-fixture identity. Written only by the seed loader; empty on every real snapshot." Its whole job is to be a seeder-only upsert identity that no real row can acquire and nothing reads. A consumer would defeat it.
That shape — hidden: true plus readonly: true plus seed-only writers — looks mechanically recognisable, and recognising it would remove a permanent warning that no correct change can clear.
Why this is worth a ruling rather than per-app judgement
The rule's remedies are "add a consumer" or "remove the field with carrier cleanup". Both are product decisions, and the second is expensive and irreversible: on the app measured, one field lists 57 carrier sites a removal would have to clean. A warning an app cannot correctly clear becomes a warning it learns to skim — which is the failure mode the rule exists to prevent.
⛔ Nothing was suppressed, whitelisted or re-severitied on the app side; all 12 stand as reported warnings with a per-field disposition in hotcrm PR #1814.
Measured on
@objectstack/lint@17.4.0 via os lint --json over hotcrm@3.0.0: errors: 0 · warnings: 13 · suggestions: 12, of which 12 warnings are field-no-consumers.
Generated by Claude Code
Found while migrating
hotcrmonto the 17.4.0 line (hotcrm#1807, hotcrm PR #1814). Filed unassigned, observation class.The new
field-no-consumersrule (shipped from #15922, HotCRM's retired local scanner as design input) reported 12 fields on the first real app to take it. The findings are useful — several are genuine display gaps. But all 12 are visible and editable in the product today, and two categories may be worth a ruling before app teams start removing columns to clear the count.1. A synthesized layout names nothing, so a field only reachable through it reads as unconsumed
The rule's own message enumerates what counts: "no view column, form section, page binding, flow node, dataset, widget, formula, validation, hook or action names it." Every one of the 12 carries a
group, every group is a declaredfieldGroup, and most of these objects render through the synthesized detail/form layout rather than an authored*.page.ts. A synthesized layout names nothing, so those fields are unnamed in metadata while being on screen.Concretely:
crm_contact.mailing_street/mailing_city/mailing_state/mailing_postal_code/mailing_countryrender as themailing_addressfield group on the synthesized contact layout, and each is additionally an import-mapping target, so the CSV importer writes them. The verdict iscarrier-only.There is a ruling neighbourhood here already: #7427 refers to a "previews-count-as-consumers ruling". Whether a synthesized layout is the same kind of consumer is the open question. Both answers are defensible — what is expensive is app teams guessing.
2. A
hidden: trueseeder-only identity column is unconsumed by constructioncrm_forecast.seed_keyishidden: true,readonly: true, and its owndescriptionsays "Demo-fixture identity. Written only by the seed loader; empty on every real snapshot." Its whole job is to be a seeder-only upsert identity that no real row can acquire and nothing reads. A consumer would defeat it.That shape —
hidden: trueplusreadonly: trueplus seed-only writers — looks mechanically recognisable, and recognising it would remove a permanent warning that no correct change can clear.Why this is worth a ruling rather than per-app judgement
The rule's remedies are "add a consumer" or "remove the field with carrier cleanup". Both are product decisions, and the second is expensive and irreversible: on the app measured, one field lists 57 carrier sites a removal would have to clean. A warning an app cannot correctly clear becomes a warning it learns to skim — which is the failure mode the rule exists to prevent.
⛔ Nothing was suppressed, whitelisted or re-severitied on the app side; all 12 stand as reported warnings with a per-field disposition in hotcrm PR #1814.
Measured on
@objectstack/lint@17.4.0viaos lint --jsonoverhotcrm@3.0.0:errors: 0 · warnings: 13 · suggestions: 12, of which 12 warnings arefield-no-consumers.Generated by Claude Code