Sync ako/mxcli: two pluggable-widget defects, a stdlib toolchain bump, and a corrected parser claim - #889
Merged
Merged
Conversation
…roblem 1) A LoopedActivity's Size is computed from a pre-pass over the AST before its body is built, so it is a function of statement count alone and the children's real positions -- @position included -- have no effect on the box meant to contain them. Measured on 11.6.6: two activities at x=150/310, at x=1500/2000, and at x=160/170 all yield Size 480;160; only changing the statement count to four moves it (800;160). In the x=1500/2000 case both children sit entirely outside their own container and mx check reports no additional error, so nothing catches it short of opening the flow in Studio Pro. The fix is not a one-liner: children are placed relative to an inner origin derived from the size, so deriving the size from the children closes a cycle. Proposes build-first / size-after / translate-once, with the translation as a single post-pass over the nested builder's objects -- the same single-choke-point shape used for @Curve and @merge. Includes the four-case repro as a bug-test example, and notes the two consequences worth a release note: every flow containing a loop changes geometry once, and under ADR-0008 that means one round of writes users did not author. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013uQvFDd5R4eNqqita59jM8
…etrieve Range
parseRange carried the comment "Studio Pro stores custom ranges as ConstantRange
with LimitExpression/OffsetExpression", and a branch acting on it. Measured
against a real document — ako/TestApp MyFirstModule.RetrieveExamples on Mendix
11.13.0, three retrieves, one per UI option:
All ConstantRange {SingleObject: false}
First ConstantRange {SingleObject: true}
Custom (limit 4, off 2) CustomRange {LimitExpression: "4", OffsetExpression: "2"}
LimitExpression never appears on a ConstantRange. Studio Pro stores exactly what
generated/metamodel and modelsdk/gen declare, so the branch has never fired.
The comment was not harmless. The two engines differ on that input — modelsdk's
rangeFromGen cannot read it at all, because gen binds only SingleObject on
ConstantRange — so a reader trusting the comment concludes the default engine
silently drops a bounded retrieve's limit. It does not. The claim nearly became
a bug report against correct code.
The branch is kept, because one version's evidence justifies correcting a false
claim but not deleting tolerance for pre-11 formats that have not been sampled.
It is now labelled as unobserved, with the asymmetry and its consequences
recorded: if such a document ever appears the fix belongs in gen, not here.
Tests pin the three measured shapes, and name the tolerance case so a future
discovery lands somewhere with context. Also verified, on both engines, that a
describe -> exec round trip reproduces all three byte-for-byte — DESCRIBE
renders First as `limit 1`, which maps back to ConstantRange{SingleObject:true}
rather than a CustomRange, so the object-vs-list distinction survives.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LUToAkUx54bNkNjsBpufRH
The import-mapping Range work (mendixlabs#881) added FIRST to the lexer but the committed generated completion list was never refreshed, so `make build` left the tree dirty on a clean checkout. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013uQvFDd5R4eNqqita59jM8
The `Vulnerability scan` step (govulncheck ./...) started failing with exit 3 on every push. Nothing in mxcli changed: all six findings are standard-library advisories reported as `Found in: <pkg>@go1.26.5` / `Fixed in: <pkg>@go1.26.6`, and go1.26.6 was published between the last green run and the first red one. govulncheck@latest re-resolves the vuln database on each run, so the pinned toolchain went stale underneath a workflow that had not been touched. GO-2026-6218 net/url quadratic complexity in resolvePath GO-2026-6090 crypto/tls unbounded post-handshake messages GO-2026-6089 net/http ReadHeaderTimeout on the h2c check GO-2026-6088 encoding/xml missing recursion depth guard GO-2026-5972 encoding/asn1 missing recursion depth limit GO-2026-5026 net/http idna punycode label rejection Bumps every pin together -- go.mod's toolchain plus push-test, release and nightly (two jobs) -- so a release binary is not still linked against the vulnerable standard library after CI goes green. Same treatment as the 1.26.4 -> 1.26.5 bump for GO-2026-5856. Verified by running the scan under both toolchains: go1.26.5 reports the six above and exits 3, go1.26.6 reports "No vulnerabilities found" and exits 0. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013uQvFDd5R4eNqqita59jM8
A page carrying a pluggable widget could not be described and re-applied:
`mxcli check` on the description failed from the first widget onward with
`extraneous input ':'`. That takes any such page out of the
DESCRIBE-edit-CREATE OR REPLACE workflow mxcli itself documents as the way
to change an element you did not author — and a widget has no other route,
having never been hand-authorable in Studio Pro terms.
Two independent defects in the same path:
- Emit. Explicit properties went out through a raw %s, so every string
lost its quotes. A JSON spec then broke the parse at its first brace.
- Read. extractExplicitProperties skipped any value of "true"/"false" as
a "common default". A widget's default may be either, the document
only stores what the author set, and the property was simply gone.
Both are fixed together because fixing one is worse than fixing neither:
quote without emitting booleans and the description re-parses cleanly
while silently dropping a property — a wrong page that validates.
Quoting is decided by the DECLARED type, never the value's shape. Each
property's ValueType.Type is already in the widget's
Type.ObjectType.PropertyTypes, the array buildPropertyTypeKeyMap walks for
PropertyKey and throws away; a String holding "30" is indistinguishable
from an Integer once it is a string in BSON, and has to come back quoted.
Where no type is declared the shape is all that is left, and the fallback
quotes anything not plainly numeric or boolean — an unquoted arbitrary
string may not parse at all, while a quoted literal still round-trips.
Verified end to end on 11.12.1, which is the test rather than the output:
describe -> check -> exec -> describe is byte-identical, and mx check
reports 0 errors. Before the fix the first step did not parse.
Uncovered while verifying and NOT fixed here, because it is a write-path
defect with no DESCRIBE involved: giving a property in a conditionally
shown group a non-default value writes a widget Mendix rejects with
CE0463. On ProgressCircle both `showLabel: true` and
`labelType: 'percentage'` do it, while the same widget's General-group
properties take non-default values happily. The example keeps that group
at its defaults so it isolates the round trip; the symptom table records
the repro.
Reported in mxcli-ledger FINDINGS #104.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
Authoring a pluggable widget property that lives in a conditionally shown group wrote a widget Mendix rejects with CE0463. On ProgressCircle both `showLabel: true` and `labelType: 'percentage'` did it; `showLabel: false` and the same widget's General-group properties were clean. No DESCRIBE involved — three lines of MDL reproduce it. Two gaps on the same axis, and closing one alone inverts the bug: - Serialization. mendixlabs#574 nulls the TextTemplate of a HIDDEN conditional property, but left a VISIBLE one null, where Mendix stores an empty Forms$ClientTemplate. Null and empty are each invalid in the other's state, so nulling hidden ones was only half the rule. - Extraction. The editorConfig reader did not understand a ternary's ELSE branch — `cond ? (…) : hidePropertiesIn([…])` — so ProgressCircle's `showLabel` gate was never seen and labelText read as visible whenever labelType was "text", its default. Filling visible templates without the missing gate simply moved which case failed: `showLabel: false` began failing where `true` had. Both are measured, both ways round, before and after. Only CONDITIONAL properties are filled. Studio Pro's convention for an unset TextTemplate is not uniform — a DataGrid custom-content column stores null for `tooltip` and an empty template for `exportValue`, which is what emptyClientTemplateRules exists for — so filling every unset one would trade this bug for its mirror image. Diagnosis followed .claude/skills/diagnose-ce0463.md. Handing the failing project to Mendix's own `mx update-widgets` on a copy produced the reference, and diffing it against mxcli's output named one meaningful path out of 969: Object/Properties[N]/Value/TextTemplate, null against a Forms$ClientTemplate. Authoring the same widget with the boolean both ways gave two documents differing in exactly one path, so nothing else needed eliminating. The extractor's preamble is why the first attempt read as "unsupported shape": the ternary follows a whole switch statement, and walking back past the `?` to the start of the function hands the guard parser a fragment with an unbalanced `}`. trailingExpr bounds it to the statement. Verified on 11.12.1: both showLabel states 0 errors, `showLabel: true` with `labelType: 'percentage'` 0 errors, and the DESCRIBE round trip of a widget carrying the boolean parses, re-executes and re-describes byte-identically. The widgetdemo showcase applies with 0 CE0463 (its 4 CE1613 are a pre-existing attribute reference in the example). Reported in mxcli-ledger FINDINGS #104 follow-on. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
Fix red CI (Go 1.26.6), propose container auto-sizing for mendixlabs#884, regenerate LSP completions
Document Range parsing with measured Studio Pro shapes
Pluggable widgets: round-trip through DESCRIBE, and write a valid one when a conditional property is shown
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Syncs 6 commits from
ako/mxcli:main. Upstream is not ahead, so this fast-forwards.Pluggable widgets — two independent defects on the same path
A conditionally shown property wrote a widget Mendix rejects (CE0463) (
c8a483d). On ProgressCircle, bothshowLabel: trueandlabelType: 'percentage'produced it;showLabel: falseand the same widget's General-group properties were clean. Three lines of MDL reproduce it — no DESCRIBE involved.Two gaps, and closing either alone inverts the bug rather than fixing it:
Forms$ClientTemplate. Null and empty are each invalid in the other's state.cond ? (…) : hidePropertiesIn([…])), soshowLabel's gate was never seen andlabelTextread as visible wheneverlabelTypewas"text", its default.Filling visible templates without the missing gate simply moved which case failed. Both directions are measured, before and after. Only conditional properties are filled: Studio Pro's convention for an unset TextTemplate is not uniform — a DataGrid custom-content column stores null for
tooltipand an empty template forexportValue— so filling every unset one would trade this bug for its mirror image.A page carrying a pluggable widget could not be described and re-applied (
9d0ac46).mxcli checkon the description failed from the first widget onward withextraneous input ':', taking such pages out of the DESCRIBE-edit-CREATE OR REPLACEworkflow mxcli documents as the way to change an element you did not author — and a widget has no other route.%s, so every string lost its quotes; a JSON spec then broke the parse at its first brace.extractExplicitPropertiesskipped any value of"true"/"false"as a "common default". A widget's default may be either, the document only stores what the author set, so the property was simply gone.Fixed together because fixing one is worse than fixing neither: quote without emitting booleans and the description re-parses cleanly while silently dropping a property — a wrong page that validates. Quoting is decided by the declared type, never the value's shape: a String holding
"30"is indistinguishable from an Integer once it's a string in BSON.Both were diagnosed by handing the failing project to Mendix's own
mx update-widgetson a copy and diffing against that reference — which named one meaningful path out of 969.Build
cad70cc).govulncheck ./...began failing with exit 3 on every push with nothing in mxcli changed: all six findings are stdlib advisoriesFound in: <pkg>@go1.26.5/Fixed in: @go1.26.6, published between the last green run and the first red one.govulncheck@latestre-resolves the database each run, so the pinned toolchain went stale under an untouched workflow.FIRSTkeyword (64935d4). The import-mapping Range work addedFIRSTto the lexer but the committed completion list was never refreshed, somake buildleft a clean checkout dirty.Correctness of the record
8991344).parseRangecarried the comment "Studio Pro stores custom ranges as ConstantRange with LimitExpression/OffsetExpression", plus a branch acting on it. Measured against a real document on 11.13.0, one retrieve per UI option:All→ConstantRange {SingleObject: false},First→ConstantRange {SingleObject: true},Custom(limit 4, offset 2)→CustomRange {LimitExpression, OffsetExpression}.LimitExpressionnever appears on aConstantRange, so the branch had never fired.Sizefrom contents (cd2b01e, docs only). ALoopedActivity's Size is computed from a pre-pass over the AST before its body is built, so it's a function of statement count alone and children's real positions —@positionincluded — have no effect on the box meant to contain them. Measured on 11.6.6: children at x=150/310, x=1500/2000 and x=160/170 all yield Size480;160; only the statement count moves it. In the x=1500/2000 case both children sit entirely outside their container andmx checkreports nothing.