Skip to content

lint: validateFormLayout is dead for any view that binds its object through list.data.objectform-field-unknown / form-section-group-unknown / absolute-colspan-discouraged never fire on 14/14 of HotCRM's views (49 form sections) #16168

Description

@os-steve

Measured against the pinned @objectstack/lint@17.3.0 in node_modules (never the platform source tree), on objectstack-ai/hotcrm at db5fe702, as part of the step-3 rule survey (hotcrm#1637).

The fact

validateFormLayout walks formViewSites(view, viewPath), which does include the container's default form as a site. But for each site it resolves the object with

const objName = viewObjectName(site.view) ?? containerObject;

and viewObjectName reads only three anchors:

function viewObjectName(view) {
  return strName7(view.objectName) ?? strName7(view.object)
      ?? (isRec15(view.data) ? strName7(view.data.object) : void 0);
}

view.list.data.object is not among them. A view record that binds its object the way HotCRM does — through the list block — therefore yields objName === undefined, and every finding in this validator is gated on it:

  • form-field-unknown needs known = objectFields.get(objName) (undefined ⇒ the if (fname && known && ...) guard never passes)
  • form-section-group-unknown goes through checkSectionGroupRefs, which opens if (!objectName) return findings;
  • absolute-colspan-discouraged sits in the same loop body

⇒ the whole validator no-ops.

Population on the app that surfaced it

Probe importing the app's own objectstack.config:

views: 14   ·  views with a `form`: 14   ·  form sections: 49
views where viewObjectName() resolves: 0
views binding the object only via list.data.object: 14

So 49 authored form sections are unwalked, and a dangling field reference in any of them is reported by nothing at all.

Repro, and the control that makes the negative mean something

One character class of edit, one file, objectstack lint --json each time, exit code captured before any pipe.

Negativesrc/views/contact.view.ts, default form, section contact_details:

injection lint result
fields: ['email_nope', 'phone', 'mobile', 'avatar'] exit 0 nothing — output byte-identical to the clean baseline (0 errors / 17 warnings / 12 suggestions)
the same section rewritten as { group: 'no_such_group_nope' } exit 0 nothing

Positive control — same defect, same site, same command, one key added. Adding object: 'crm_contact' to the view record (changing nothing about the defect itself) wakes both rules:

injection lint finding
dangling field + object: 'crm_contact' exit 0 form-field-unknown warning at views[3].form.sections[1].fields[0]
undeclared group + object: 'crm_contact' exit 0 form-section-group-unknown warning at views[3].form.sections[1].group

That is the whole diagnosis: the defect was always there, the binding is what the walker cannot see.

Second control, same run: translation-section-name-missing does fire at views[2].form.sections[0] on this repo without any added binding — a different walker (collectViewRecord) reaching the same array, so the array itself is reachable and only this validator's object resolution is at fault.

crm_contact declares six fieldGroups (identity, account_info, contact_info, mailing_address, additional, preferences), so objectFieldGroups.get(...) was never the blocker.

Every injection was restored in the same run and proven restored by git hash-object equalling git rev-parse HEAD:PATH and an empty git status for that path; the clean-tree lint baseline reproduces byte-identically afterwards.

Why this is not a duplicate

#5415 (closed) is the same anchor one validator over: translation-target-unknown missed a view container's default form.sections because collectViewRecord iterated only ['listViews', 'formViews']. That was fixed — measured above, the translation rules now reach this surface. validateFormLayout misses the same sections for a different cause: not the bucket list (its viewContainerSites already pushes view.form), but the object binding. #5415's own text anticipated exactly this shape — "this issue is the reference validator catching up on the same anchor."

Also checked and not duplicating: #14107 (list-view field references, closed), #4329 (React page field refs, closed), #13626 (form-view className boundary), #6926 (FormViewSchema.groups alias never folded — I deliberately make no claim about the groups bucket here, because my one probe of it was confounded by this same binding defect).

Suggested direction

Fall back to the container's list binding when resolving a form site's object — i.e. let containerObject consider view.list?.data?.object (and the same for any other block that carries a data.object) before giving up. ⛔ Not proposing a change to viewContainerSites; the site is already collected correctly.

Filed unassigned by the hotcrm epic seat (hotcrm#1579 step 3, survey part 3 — hotcrm#1637). Consequence for that epic: form-section-group-unknown is blocked upstream on this card, and hotcrm's local form-reference assertions stay.

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions