Skip to content

Round-trip a page over a flow the project lacks: keep bindings qualified - #678

Merged
ako merged 4 commits into
mainfrom
fix/describe-unresolved-context-attrs
Sep 25, 2026
Merged

ako merged 4 commits into
mainfrom
fix/describe-unresolved-context-attrs

Conversation

@ako

@ako ako commented Sep 25, 2026

Copy link
Copy Markdown
Owner

Follow-up to #675.

Symptom

FeedbackModule.ShareFeedback_Logo (Feedback v4.0.2, Mendix 11.13.0) is an excluded example page whose data view is sourced by a nanoflow the module doesn't ship. After #675, describe → exec was still refused:

nanoflow not found: FeedbackModule.DS_FeedbackForm (data source)

Forcing it through left a project mx check could not load (ArgumentNullException setting 'Attribute').

Cause

With the flow missing, describe had no entity in scope for the data view, so it printed every binding inside it bare: Attribute: Subject, {1} = ImageB64, Visible: _showEmail in (…). Exec has nothing to qualify those against.

The stored model never lost the information. Every AttributeRef in there still holds FeedbackModule.Feedback.Subject; describe threw the entity away.

Fix

  • Describe: inside a data view, list view or gallery whose flow can't be resolved, bindings keep their stored Module.Entity.Attr. That covers Attribute:, template parameters, pluggable attribute properties, object-list items and the attribute visibility condition. Where the entity is known, output is unchanged.
  • Visible: Module.Entity.Attr in (…) (from Round-trip "Visible: based on attribute value" (Visible: Attr in (…)) #671) accepts the qualified form without an entity in scope. Inherited attributes are still stored against their declaring entity.
  • Builder: on an excluded page, a missing data-source flow is kept by name, like Excluded pages: dangling action references warn instead of blocking exec #675's action targets.
  • Check: a missing data-source flow is a warning when every binding inside the container is qualified. Otherwise it is refused, naming each bare binding and its widget. The walk stops at nested containers that have their own data source.
  • Writer, as the last line: a page or snippet holding a DomainModels$AttributeRef that isn't Module.Entity.Attr is refused, naming it. Studio Pro qualifies every one (72 of 72 across the project's pages, snippets and layouts), and a bare one takes Mendix's loader down. This turns a load-time stack trace into a statement error. The full backend suite passes with the guard on.

Evidence

Control. With the implementation reverted, every layer fails:

  • describe: lacks "Attribute: FeedbackModule.Feedback.Subject" and the three other bindings;
  • builder: failed to resolve nanoflow: nanoflow not found: Feedback.DS_FeedbackForm;
  • visibility: Visible: M.Job.IsLocal in (…): … place the widget inside a data container;
  • writer guard (stubbed): a bare attribute reference must be refused, naming it; got <nil>.

Real run (copy of the 11.13.0 project):

Bug-test mdl-examples/bug-tests/excluded-page-unresolved-flow-qualified-bindings.mdl: 0 errors, and a bare variant is refused.

Reviewer notes

  • The writer guard covers pages and snippets written by the builder. ALTER PAGE's raw BSON path (pagemutator) is not covered.
  • The check-syntax skill and the docs-site validation tutorial are updated for the new rule.
  • The branch includes a gofmt-only follow-up commit.

Checklist

  • Failing tests first (describe, builder, check, visibility, writer guard)
  • Control recorded
  • Real mx check run, including the forced-fault variant
  • Bug-test MDL; make check-mdl passes
  • Finding appended; make check-findings passes
  • make build && make test && make lint pass

🤖 Generated with Claude Code

ako and others added 4 commits September 25, 2026 09:05
describe → exec of Feedback v4.0.2's EXCLUDED FeedbackModule.ShareFeedback_Logo
was refused: "nanoflow not found: FeedbackModule.DS_FeedbackForm (data source)".
Forcing it through left a project `mx check` could not LOAD
(ArgumentNullException setting 'Attribute').

With the flow missing, DESCRIBE had no context entity and printed every
binding inside the data view bare (`Attribute: Subject`, `{1} = ImageB64`,
`Visible: _showEmail in (…)`). Exec had nothing to qualify them against.
The stored model always has the full names.

- DESCRIBE keeps the stored Module.Entity.Attr for bindings inside a data
  view, list view or gallery whose flow cannot be resolved. This covers
  Attribute:, template parameters, pluggable attribute properties,
  object-list items and the attribute visibility condition.
- `Visible: Module.Entity.Attr in (…)` is accepted and needs no entity in
  scope.
- On an excluded page a missing data-source flow is kept by name, like the
  action targets in the previous commit.
- The check reports it as a warning when every binding inside is qualified.
  Otherwise it refuses and names the bare binding and its widget.
- As a last line, the page and snippet writer refuses any DomainModels$AttributeRef
  that is not Module.Entity.Attr. Studio Pro qualifies every one (72 of 72
  across the project), and a bare one takes the loader down.

ShareFeedback_Logo now round-trips: warnings only, all 6 attribute references
identical to the stored ones, the page still excluded, and `mx check` 0 errors.
A forced-fault variant with one binding hand-edited back to bare is refused,
naming the widget. All 17 pages of the project now exec.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…k' into fix/describe-unresolved-context-attrs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant