fix(lint): validateFormLayout resolves a list-bound view's object for its default form - #16417
Conversation
… its default form Carries the list-binding fallback rung already used one validator over (validate-translatable-sections.ts:178-185) into validate-form-layout.ts: a container whose object lives only on `list.data.object` (HotCRM's own shape, all 14 of its views) had no object of its own, so `containerObject` resolved to undefined for every site under it — including its own default `form` — and form-field-unknown / form-section-group-unknown never fired there. absolute-colspan-discouraged is unaffected: measured, that check sits outside the known-gated block and was never gated on the object binding. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vbw3RPgdtqesx4azk9SbW8
📓 Docs Drift CheckThis PR changes 1 package(s): ⛔ 2 release-owned page(s) name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 5 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 326fa8d78447e1aef88c1473628f8742ca7856e9 && git checkout 326fa8d78447e1aef88c1473628f8742ca7856e9
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin dff0bdd3ac51df2653e1bd7beb7f2b3ca0fa58c3 85f9543d3a7a1496100b46536006ca79930e9006 && git checkout -B drift-repro dff0bdd3ac51df2653e1bd7beb7f2b3ca0fa58c3 && git merge --no-ff 85f9543d3a7a1496100b46536006ca79930e9006
node scripts/docs-audit/affected-docs.mjs --json dff0bdd3ac51df2653e1bd7beb7f2b3ca0fa58c3
|
|
CI red classified — not this PR's; one re-run taken — PM seat At head The diff is Per landing-operations B: a failure naming a service the diff does not touch earns exactly one re-run to confirm it reproduces identically; Generated by Claude Code |
Fixes #16168
What
validateFormLayoutnow falls back to the container'slistbinding (list.data.object/list.object/list.objectName, via the sharedviewObjectName) when resolving the bound object for a form site, whenever the container itself carries noobject/objectName/data.objectof its own. This is the same third rungvalidate-translatable-sections.ts:178-179already carries for its own sites (recordObject/listBinding) — carried, not duplicated, intovalidate-form-layout.ts:132/142.Before: a view container that binds its object only through the
listblock (HotCRM's own shape, all 14 of its views) hadcontainerObject === undefined, so every site under it — including its own defaultform— could never resolve an object, andform-field-unknown/form-section-group-unknownnever fired there, however wrong the section content was.packages/lint/src/validate-form-layout.ts— the fix (2 new lines + 1 changed line + comments).packages/lint/src/validate-form-layout.test.ts— new describe block ("falls back to the container list binding"): P1/P2 (red-first on unmodified code, confirmed), N1 positive control (byte-identicalwhere/pathwithobjectalso on the container), N2 clean list-bound container, N3 aformViews[]entry with its own binding (unchanged), N4 no binding anywhere stays silent (unchanged), plus a pin provingabsolute-colspan-discouragedwas never gated on the object binding (see "colspan" below)..changeset/lint-form-layout-list-binding.md—@objectstack/lintpatch.Why
Filed by the hotcrm epic's rule-survey seat (hotcrm card 1637): on hotcrm at
db5fe702, 49 of 49 authored form sections across 14/14 views were unreachable by this validator because every one of those views binds its object only vialist.data.object. Triaged (comment 5556877712) againstorigin/main: the diagnosis holds on the platform source, and the fix shape already exists one validator over — this PR carries that same ladder intovalidate-form-layout.ts, and only there (the package's other two ladder lengths are a separate convergence card per that triage, out of scope here).Colspan — measured, not assumed
The filing seat's own scope correction (comment 5556746408) flagged
absolute-colspan-discouragedas unmeasured on the "never fires" claim. Measured here: the colspan check (validate-form-layout.ts's(b)block) sits outside theknown-gated block — it needs onlyentry.colSpan != null, neverobjName/known. So it was never actually dead on a list-bound container; it already fired regardless of whether the object resolved. This PR's fix therefore changes onlyform-field-unknownandform-section-group-unknown.Risk & cost (rollback)
Advisory-only (
severity: 'warning') — nothing is blocked. A stack whose list-bound container's defaultform(or an unboundformViews.*entry) references a real dangling field/group now surfaces a warning it did not surface before; a clean stack of the same shape produces no new output (N2/N4 pin this). Patch-level change to@objectstack/lint, single-file source diff, revert is a straightgit revert.Open questions for the maintainer
See report JSON
open_questions(posted as a comment on this issue) — notably what thegroupslegacy-bucket alias (card 6926) now surfaces once this binding resolves, per the triage seat's ask; reported there for information, not acted on here.🤖 Generated with Claude Code
https://claude.ai/code/session_01Vbw3RPgdtqesx4azk9SbW8