Skip to content

fix: silent-property-drop cluster — loop @curve, alter annotations, Java action descriptions - #1522

Merged
ako merged 4 commits into
mainfrom
claude/trusting-darwin-q2q31j
Oct 21, 2026
Merged

ako merged 4 commits into
mainfrom
claude/trusting-darwin-q2q31j

Conversation

@ako

@ako ako commented Oct 21, 2026

Copy link
Copy Markdown
Owner

Closes #1496, closes #1507. Triage cluster silent-property-drop (#1357). Mirrors of mendixlabs#1588 and mendixlabs#1597.

The other two issues in the cluster are already fixed on main, so this PR leaves them alone:

Each commit fixes one thing.

1. @curve inside a loop / while body was dropped — mendixlabs#1597 case A

Symptom. @curve(from: (39, 0), to: (0, 61)) on a statement inside a loop body passed check and exec, but describe printed the body without it. The same annotation after the loop was kept.

Cause. A loop body is built by its own flowBuilder, which records the curve. addLoopStatement and addWhileStatement hand that builder's flows, notes and errors back to the main builder, but not its curves. Curves are applied once, by the builder that ends up owning the flows, so the body's curves were never applied. #991 fixed exactly this for error-handler bodies, but only at that one place.

Fix. A new helper, adoptCurves, now called by the loop, while and error-handler merges alike.

2. Alter fragments skipped the annotation checks — mendixlabs#1597 case B

Symptom. @annotation('Why this commit is here.') in alter microflow … insert passed check and exec ("Altered microflow"), and no note was written. create or modify refuses the same line as MDL079.

Cause. The annotation rules ran on create bodies only. ValidateProgram had no AlterFlowStmt case and execAlterFlow validated nothing, while the fragment goes through the same builder, which drops what the visitor could not read. All four rules had the hole: I checked @postion(10, 20), @curve(from: (a, b)) and @anchor(from: sideways) in a fragment too, and each passed silently.

Fix.

  • ValidateAlterFlow runs MDL059, MDL060, MDL079 and MDL092 over every insert and replace fragment.
  • execAlterFlow refuses the subset exec already enforces for create.
  • Only the annotation rules run on a fragment. The rest of the microflow rule set reads the whole flow (parameters, declares, later uses), which a fragment cannot see, so running it would trade a silent drop for false refusals.

3. Java action parameter descriptions and return value name — mendixlabs#1588

Symptom. create java action had no way to set a parameter's description or the return value's name. describe printed both as -- comments (Input: String not null -- The text to convert., -- return NAME: 'UpperText'). In a script those passed check and exec and were dropped, leaving the description empty and the return name ReturnValueName.

Fix. Both now use the spelling the language already has for the same thing, which were also the first two spellings the reporter tried:

  • A /** … */ before a parameter is its description, as on an entity attribute.
  • returns T as $Name names the return value, as on a microflow.

Details:

  • Java and JavaScript actions share the grammar rules, so both visitors read them through one helper (buildJavaActionParams / buildJavaActionReturn) and both describers print through one emitter. Otherwise a field read by only one of them would be a new silent drop in the other.
  • On create or modify, an omitted description or name still keeps what is stored (carriedDocumentation).
  • A multi-line description, which the -- form cut to its first line, now round-trips whole.
  • A description that contains */ can't go in a doc comment, so it is still printed as a comment. The output parses, and a rewrite keeps the stored description.
  • Updated the syntax help, the manual pages (Java and JavaScript action), both quick references and both skills.

Evidence

Tests written first, run before each fix. Each failed with the reported symptom:

--- FAIL: TestLoopBody_KeepsCurve
    0 loop-body flows carry the curve, want 1 (inside-a → inside-b)
--- FAIL: TestWhileBody_KeepsCurve
--- FAIL: TestNestedLoopBody_KeepsCurve
--- FAIL: TestValidateProgram_ChecksAnnotationsInAnAlterFlowFragment   (all 10 subtests: 4 rules + nested, × insert/replace)
--- FAIL: TestExecAlterFlow_RefusesADroppedAnnotation
--- FAIL: TestCreateJavaAction_WritesStatedParameterDescriptionAndReturnName
    parse: line 2:4 extraneous input '/** The text to convert. */' … line 9:20 mismatched input '$UpperText' expecting DOLLAR_STRING
--- FAIL: TestJavaActionRewrite_StatedDescriptionAndReturnNameReplaceStored
--- FAIL: TestDescribeJavaAction_DescriptionAndReturnNameRoundTrip
    describe still prints a value as a `--` comment, which create drops
(+ the JavaScript twins)

In-test controls.

Fresh Mendix 11.12.5 app, pre-fix binary vs fixed binary:

Case Pre-fix Fixed
1597-curve-inside-loop-body.mdl describe shows no @curve inside either body curve inside both bodies; mx check: 0 errors
1597-alter-annotation-positional.fail.mdl Check passed! MDL079; exec of the file refuses
-c "alter … @postion(10, 20) …" Altered microflow [MDL059] unknown annotation
1597-alter-annotation-forms.mdl both notes written both notes written
1588-java-action-param-description-return-name.mdl parse error at /** bson dump: Description: "The text to convert.", ActionDefaultReturnName: "UpperText"; describe → exec reports Unchanged; mx check: 0 errors

make build, make test, make lint, make check-mdl, make check-findings, make check-skill-mdl and make check-skill-index pass locally. The branch merges cleanly with the current main.

Not covered

MDL079 is not among the rules exec enforces, for create or for alter. So exec without the check pre-check (-c, the REPL, --no-check) still writes past an unreadable @annotation. Running exec on a file is covered, because it runs check first. Fixing it changes create too, so it's left for a follow-up.

Bookkeeping

Three finding files under .claude/skills/fix-issue/findings/ (mdl-executor ×2, mdl-grammar ×1), and four bug-test scripts under mdl-examples/bug-tests/.


Generated by Claude Code

A `@curve` on a statement inside a `loop` or `while` body passed check and
exec and was not stored; `describe` printed the body without it, while the
same annotation after the loop was kept.

The body is built by its own flowBuilder, which recorded the curve, and the
loop hoisted that builder's flows to the parent without the curves that
belong on them. applyFlowCurves runs once, on the builder that owns the
flows, so the body's curves were never applied. The error-handler builder
had the same merge (#991); it is now one helper, adoptCurves, which the
loop, while and error-handler merges all call.

Refs #1507

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HjYj5GTj2in3ckFYaDBAuN
…#1597)

`@annotation('Why this commit is here.')` in an `alter microflow … insert`
fragment passed check and exec ("Altered microflow") and no note was
written; the same line in `create or modify microflow` is refused as MDL079.

The annotation rules — MDL059, MDL060, MDL079, MDL092 — ran over create
bodies only. A fragment is built by the same flowBuilder, which drops an
annotation the visitor could not read, so all four reached the builder
unchecked in an alter. check now runs them over every insert and replace
fragment, and execAlterFlow refuses the exec-enforced subset as create does,
for `-c` and the REPL, which skip the check preflight.

Refs #1507

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HjYj5GTj2in3ckFYaDBAuN
…ame (mendixlabs#1588)

`create java action` had no way to set a parameter's description or the
return value's name. `describe` printed both as `--` comments
(`Input: String not null  -- The text to convert.`, `-- return NAME:
'UpperText'`), which read like syntax: written in a script they passed
check and exec and were dropped, leaving the description empty and the
return name `ReturnValueName`.

Both now use the spelling the language already has for the same thing
elsewhere:

  - a `/** … */` doc comment before a parameter is its description, as on
    an entity attribute;
  - `returns T as $Name` names the return value, as on a microflow.

Java and JavaScript actions share these grammar rules, so both visitors
read them through one helper and both describers print them through one
emitter; describe output now re-executes as "Unchanged". On `create or
modify` an omitted description or name still keeps what is stored. A
multi-line description, of which the `--` form printed only the first
line, now round-trips whole; one holding `*/`, which a doc comment
cannot carry, is still shown as a comment so the output parses.

Refs #1496

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HjYj5GTj2in3ckFYaDBAuN
govulncheck flagged GO-2026-6809 (distrust compromised intermediate
certificates in crypto/x509), present in crypto/x509@go1.27.2 and fixed
in go1.27.3. mxcli reaches the vulnerable code through
marketplace.Client.Download (io.Copy over TLS). This is a new advisory
against the standard library: build-and-test is red on main for the
same reason.

Bump the toolchain in go.mod and the go-version in every workflow, so CI
installs the fixed standard library.

Locally, govulncheck ./... reports GO-2026-6809 on go1.27.2 (exit 3) and
"No vulnerabilities found" on go1.27.3. make build, make test and
make vet pass on go1.27.3.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AeAyg3qx2my26Q8cvGyW5z
(cherry picked from commit 21be71b)

ako commented Oct 21, 2026

Copy link
Copy Markdown
Owner Author

build-and-test was red on the first head (ca5f477), and the failure is not from this PR. Everything in the job passed up to the govulncheck ./... step:

  • the tests, lint and every MDL / skill / findings check passed;
  • govulncheck then reported GO-2026-6809, a new advisory in the Go standard library (crypto/x509@go1.27.2, fixed in go1.27.3), reached through marketplace.Client.Download.

main pins the same go1.27.2 in go.mod and every workflow, so it is red for the same reason.

Fix ported: I cherry-picked the toolchain-bump commit from #1520 (21be71b, "ci(deps): bump Go toolchain 1.27.2 → 1.27.3 for GO-2026-6809") as e9bfd00, and nothing else from that PR. Once #1520 merges, this commit is a no-op against main.

Verified locally:

  • govulncheck exits 3 with GO-2026-6809 on go1.27.2, and reports "No vulnerabilities found" on go1.27.3.
  • make build, make test and make lint pass on this branch under go1.27.3.

Generated by Claude Code

@ako
ako merged commit dc2f733 into main Oct 21, 2026
33 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

2 participants