Skip to content

fix(check): report MDL042 for @caption on a while loop (#1187) - #1188

Merged
ako merged 3 commits into
mendixlabs:mainfrom
tgolembiewski:fix/1187-while-caption-mdl042
Sep 25, 2026
Merged

ako merged 3 commits into
mendixlabs:mainfrom
tgolembiewski:fix/1187-while-caption-mdl042

Conversation

@tgolembiewski

Copy link
Copy Markdown
Contributor

Closes #1187

What

@caption above a while loop passed mxcli check with no warning, exec created the microflow, and describe showed the loop without the caption. The same caption on a loop has been reported as MDL042 for some time.

Both statements build a Microflows$LoopedActivity. A while just carries a WhileLoopCondition where a for-each loop has an iterator. LoopedActivity has no Caption property, so the caption is dropped either way. MDL042 was raised only in the *ast.LoopStmt case of validate_microflow.go, so a while fell through.

The check now lives in one helper, checkCaptionOnLoop, which both cases call. Its message names the statement ("a loop" / "a while loop") and points to @annotation, which survives exec and comes back from describe. There are no syntax changes and no builder changes, and nothing new is written to the model.

Reproduced on v0.24.0 against a blank Mendix 11.12.1 project:

before after
@caption on loop MDL042 MDL042
@caption on while no warning; caption lost on exec MDL042
@annotation on while no warning; note kept no warning; note kept

Changes

  • mdl/executor/validate_microflow.go: the shared checkCaptionOnLoop, called for LoopStmt and WhileStmt.
  • mdl/executor/validate_microflow_loop_caption_test.go: two new tests, TestValidateMicroflow_CaptionOnWhileWarns and TestValidateMicroflow_AnnotationOnWhileNoWarn.
  • write-microflows/reference/control-flow.md: the MDL042 note now covers while as well as loop.
  • CHANGELOG.md ([Unreleased] / Fixed), plus one line in .claude/skills/fix-issue/findings/mdl-executor.jsonl.

Tests

  • I removed the WhileStmt call and confirmed that TestValidateMicroflow_CaptionOnWhileWarns fails, then put it back and confirmed it passes.
  • The existing loop tests pass unchanged.
  • I ran the whole of push-test.yml locally on macOS: build, make test, lint-go, check-mdl, check-findings, check-wiki-pages, tunnel deps, the skill and docs-site MDL blocks, integration tests against mx 11.12.1, and govulncheck. All green.

A while loop builds the same Microflows$LoopedActivity as a for-each loop,
which has no Caption property, so @caption on it was dropped by exec. MDL042
was raised only in the LoopStmt case; it now lives in checkCaptionOnLoop and
is called for WhileStmt too, pointing to @annotation instead.
@github-actions

Copy link
Copy Markdown

AI Code Review

Critical Issues

None found.

Moderate Issues

None found.

Minor Issues

None found.

What Looks Good

  • The PR correctly refactors duplicated validation logic into a shared helper function checkCaptionOnLoop, improving maintainability.
  • Test coverage is added for both the new case (while loop caption) and the existing safeguard (annotation on while loop).
  • Documentation is updated to reflect that @caption is ineffective on both loop and while loops, directing users to @annotation.
  • The changelog entry clearly describes the fix and references the issue.
  • All existing tests pass, and the new tests validate the expected behavior.
  • No syntax changes are made, adhering to the requirement that new MDL features must follow the full pipeline (this is a bug fix, not a new feature).
  • The fix addresses the root cause: both loop types build the same Microflows$LoopedActivity lacking a Caption property.

Recommendation

Approve the PR. The change is focused, well-tested, and aligns with project conventions. No further action is needed.


Automated review via OpenRouter (Nemotron Super 120B) — workflow source

@ako ako left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed against the checklist by re-running the claims. No blockers — the fix is correct, minimal, and complete for its class. Two moderate items and two minor ones below.

Verified independently

  • The premise holds. generated/metamodel.MicroflowsLoopedActivity — the arbiter per CLAUDE.md — declares no Caption. A caption on a loop genuinely has nowhere to go.
  • The scope is complete: there is no third case. I checked every caption-bearing type in the semantic model against the metamodel. ActionActivity, ExclusiveSplit, InheritanceSplit and Annotation all have a metamodel Caption; LoopedActivity is the only one that does not. loop and while are the only statements that build it, so the two cases here are the whole class — worth stating explicitly, because "we fixed the second instance" and "the class is closed" are different claims and only the second one retires the bug.
  • The control works. Deleting the checkCaptionOnLoop(stmt.Annotations, "a while loop") line takes TestValidateMicroflow_CaptionOnWhileWarns to FAIL; restored, it passes.
  • MDL042 is right on both backends — the MCP payload for a LoopedActivity (mdl/backend/mcp/microflow.go:477) sends no caption either, so the unconditional warning is not wrong on the PED path.
  • No stale claims elsewhere — every other @caption example across the skills, docs-site and syntax topics sits on an ActionActivity, which genuinely carries one. control-flow.md was the only doc that needed the update.
  • make test: exit 0, zero failures. Finding recorded, CHANGELOG entry present.

Moderate 1 — dead code that contradicts the fix

mdl/executor/cmd_microflows_builder_annotations.go:118 still runs:

case *microflows.LoopedActivity:
    // LOOP / WHILE activities can carry a caption just like
    // splits and action activities.
    if ann.Caption != "" { activity.Caption = ann.Caption }

That comment says the opposite of what MDL042 now tells the user, two files away. Nothing reads it back: the gen writer (microflow_write.go:380) sets no caption on a LoopedActivity, and the read path cannot populate one. cmd_microflows_show_helpers.go:800 likewise emits @caption for a loop, unreachable from any stored document.

Why it is worth fixing in this PR rather than later: the next contributor reads the builder, concludes the new warning is wrong, and deletes MDL042 — reopening #1187 from the other side. The assignment is the more convincing artefact, because it looks like working code while the warning looks like an opinion.

Fix: delete the case *microflows.LoopedActivity: branch (and the describe branch at show_helpers.go:800), or replace the comment with one stating that the caption is dropped at the storage boundary and MDL042 is the diagnostic. sdk/microflows.LoopedActivity.Caption can stay or go — the metamodel does not declare it, so it cannot survive a write either way.

Moderate 2 — no mdl-examples/bug-tests/ script

Checklist item for every bug fix, so the regression can be confirmed in Studio Pro. The issue already contains the exact reproduction.

Fix: add mdl-examples/bug-tests/microflow-1187-while-caption.mdl with the reporter's CountMonths snippet. Note the naming convention in that directory — a topic prefix plus the qualified number, since three numbering namespaces collide there.

Minor

  1. The CONFLICTING status is an artefact, the same one as #1165. Both sides appended to .claude/skills/fix-issue/findings/mdl-executor.jsonl. Measured with a plain 3-way merge of each candidate file: that file exits 1, CHANGELOG.md exits 0. .gitattributes:70 sets merge=union for exactly this case and GitHub's check does not apply that driver, so a local git merge origin/main and push should clear it with no content decision to make.

  2. The recorded finding's own insight is not implemented. It says to key the check "on what the builder writes (here: every LoopedActivity) rather than on the MDL keyword that led there" — the code still keys on two AST cases calling a shared helper. Harmless today, since I confirmed no third statement builds a LoopedActivity; but the finding and the code now say different things, and the finding is the artefact the next person greps.

ako and others added 2 commits September 25, 2026 06:25
…adicts

Review follow-up on mendixlabs#1188. MDL042 now tells the author a loop's @caption is
dropped because the activity has no Caption property -- while two files away
the builder still ran

    case *microflows.LoopedActivity:
        // LOOP / WHILE activities can carry a caption just like splits
        activity.Caption = ann.Caption

and the describer still emitted @caption for one. Nothing read either back:
generated/metamodel -- the arbiter -- declares no Caption on
Microflows$LoopedActivity, microflow_write.go sets none on the gen object, and
the reader therefore cannot populate one. The next contributor reads the
builder, concludes the new warning is wrong and deletes MDL042, reopening
mendixlabs#1187 from the other side.

Measured before deleting anything, with the UNMODIFIED branch build against a
Mendix 11.6.6 project: `@caption` on a loop and on a while are both absent from
`describe microflow` after `exec`, while `@annotation` on either round-trips.
So the value died at the gen boundary and the assignment only ever populated an
in-memory field.

That is also why the code survived: three tests asserted it. They tested the
semantic object, never storage, so they passed throughout and would have failed
on the correct fix. Inverted rather than deleted, each naming the measurement:

  TestLoopCaptionPreserved       -> TestLoopCaptionNotStorable
  TestWhileLoopCaptionPreserved  -> TestWhileLoopCaptionNotStorable
  TestEmitObjectAnnotations_LoopCaption -> ..._LoopCaptionNotEmitted

The describe test's real value was mdlQuote escaping, which
TestMdlQuote_* already covers directly, so retargeting loses nothing.
Reinstating the assignment fails the two builder tests -- checked.

Also adds the bug-test script the checklist asks for, covering both captions
(MDL042 x2) and both @annotation forms (silent), and keeps sdk/microflows
LoopedActivity.Caption with a comment saying it cannot be stored.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

AI Code Review

Critical Issues

None found.

Moderate Issues

None found.

Minor Issues

  • In mdl/executor/cmd_microflows_builder_annotations_test.go, the test function names were changed from TestLoopCaptionPreserved/TestWhileLoopCaptionPreserved to TestLoopCaptionNotStorable/TestWhileLoopCaptionNotStorable. While this accurately reflects the test's purpose, the renaming could be considered a minor refactor that doesn't directly relate to the bug fix. However, it improves clarity and is acceptable.
  • The CHANGELOG entry uses an em dash (—) which is consistent with the project's style, but note that some style guides prefer a hyphen with spaces (-). This is a very minor stylistic point and does not violate any explicit rule.

What Looks Good

  • The fix correctly addresses the core issue: moving the caption validation for loops into a shared helper function (checkCaptionOnLoop) that handles both loop and while statements.
  • Test coverage is robust: new unit tests validate the fix for while loops, existing loop tests remain unaffected, and the integration test script (microflow-1187-while-caption.mdl) provides end-to-end verification.
  • Documentation updates (.claude/skills/mendix/write-microflows/reference/control-flow.md) accurately reflect that @caption is ineffective on both loop types.
  • Builder and SHOW helper modifications correctly remove erroneous caption handling for LoopedActivity, aligning with the metamodel's lack of a Caption property.
  • The PR follows the contribution workflow: references an issue, includes tests, updates documentation, and records a finding in .claude/skills/fix-issue/findings/mdl-executor.jsonl.
  • All validation layers (executor, builder) are consistently updated, and the fix ensures MDL042 is triggered appropriately while preserving @annotation behavior.

Recommendation

Approve the PR. It resolves the reported bug (MDL042 missing for @caption on while loops) with minimal, focused changes that adhere to the project's architectural guidelines and quality standards. The fix is well-tested, documented, and maintains backward compatibility for valid usage patterns (@annotation). No critical or moderate issues were identified.


Automated review via OpenRouter (Nemotron Super 120B) — workflow source

@ako
ako merged commit 779ee9d into mendixlabs:main Sep 25, 2026
5 checks passed
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.

@caption on a while loop is dropped with no MDL042 — only for-each loops are warned

2 participants