Skip to content

Sync ako/mxcli: pluggable widget action variables, ALTER pluggable property kinds, Starlark API docs - #1208

Merged
ako merged 19 commits into
mendixlabs:mainfrom
ako:main
Sep 26, 2026
Merged

ako merged 19 commits into
mendixlabs:mainfrom
ako:main

Conversation

@ako

@ako ako commented Sep 26, 2026

Copy link
Copy Markdown
Collaborator

Syncs ako/mxcli:main into mendixlabs/mxcli:main: 3 commits since #1204, landed in the fork through PRs ako#699–#701.

Pluggable widgets

Lint

claude and others added 17 commits September 26, 2026 08:01
…e whole surface

The write-lint-rules skill is what Starlark rules are written from, and it
had drifted from the API:
- seven query functions were missing (java_actions, documents,
  documentable_elements, navigation_targets, queues, module_cycles,
  database_connections), four of them used by shipped rules;
- get_option() and struct() were missing from the helper table;
- scheduled_event lacked repeat, on_overlap and time_zone, and
  project_security lacked anonymous_user_role.

Document all of them, and add a test that holds the skill to the API as
registered in code:
- every name in buildPredeclared() must appear as `name(` in the skill;
- every struct built with starlarkstruct.FromStringDict (found by parsing
  the package source, including dicts built in a local variable) must have
  a table listing exactly its fields.

Structs documented another way are named in explicit maps: violation and
location as helper parameters, cycle and module_cycle as inline struct{...}
rows, and entity_permission in the shared permission table.

Follow-up to mendixlabs#1178, whose test covered only the entity and
microflow tables.

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

`ALTER PAGE … SET ImageUrl = … ON img1` printed "Altered page" and changed
nothing. setPluggableWidgetPropertyMut wrote every value to PrimitiveValue;
the pluggable Image's imageUrl is a TextTemplate, which DESCRIBE, mx check
and the runtime read instead.

The setter now reads the property's declared ValueType.Type and dispatches
through columnValueField, the same schema dispatch the DataGrid 2 column
setter already uses: TextTemplate updates the template text, Expression
writes Expression, primitives keep PrimitiveValue. Kinds a plain value
cannot express (Action, DataSource, Image, Icon, Attribute, Widgets, …) are
refused instead of reported as success, as is a list value (mendixlabs#750) and a
null (hidden, #574) text template.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H79ZLyf5E4LuV48TmbDdq9
docs(lint): document every Starlark builtin and struct field; test the whole surface
…ixlabs#1200)

A pluggable widget built from its .mpk wrote every action property's
ValueType with an empty ActionVariables list, so the stored widget Type
disagreed with its package and mx check reported CE0463 on every page
carrying it, even with no action configured (Signature 2.1.0, Calendar
2.6.0 on Mendix 11.12.2).

The .mpk parser now reads <actionVariables><actionVariable key type
caption/> (top-level and nested object-list properties), and the generator
writes them as CustomWidgets$WidgetActionVariable entries (Caption, Key,
Type), the shape Studio Pro stores in the embedded Combobox template.
Reconcile brings an embedded template's list in line with the installed
package, rewriting it only when it disagrees so an agreeing template keeps
its entries and $IDs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H79ZLyf5E4LuV48TmbDdq9
Critique of the whole MDL language against ADR-0003 before the alpha to
beta transition, with verified before/after examples, twelve
consolidation rules, the changes that cannot be bridged by an alias,
a two-mode (MDL-first / data-first) editing model with content-addressed
ALTER MICROFLOW, and a phased implementation plan.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- create or modify is the one idempotent create, with minimal-change
  semantics: an unchanged definition writes nothing; implemented as
  diff-then-patch on the same splice engine as alter.
- show is dropped in favour of list (and describe for single things).
- microflow list operations mirror Studio Pro's List operation and
  Aggregate list activities, one statement per activity.
- PedApp may be committed as the round-trip fixture.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…proposal

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tion

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… modes

ADR-0010: one canonical form governed by rules R1-R12 (extends ADR-0003,
amends its verb inventory: show is dropped).
ADR-0011: spelling changes become registered deprecated aliases; meaning
changes apply only under the mdl <n> language header.
ADR-0012: MDL-first and data-first editing share one syntax and one patch
engine; create or modify is diff-then-patch; round-trip laws; optional
@base optimistic locking.

Cross-references: ADR index, ADR-0003 status note, proposal frontmatter,
CLAUDE.md pointer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds the R1-R12 canonical rules and alias/versioning checks, and fixes
examples that contradicted the grammar (rename ... as, entity grant order)
or the new rules (show, filter).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ew until beta

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix(alter): write a pluggable property to the field its kind declares (mendixlabs#1201)
fix(widgets): carry an action's <actionVariables> from the .mpk (mendixlabs#1200)
…-syntax

CLAUDE.md is at its context budget (TestRepoClaudeMDStaysWithinItsContextBudget).
The rule applies only when designing syntax, so the design-mdl-syntax skill,
which already carries R1-R12 and the versioning checks, is its home.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

AI Code Review

Review Summary

This PR syncs three commits from ako/mxcli:main addressing:

  1. Pluggable widget action variables handling (Pluggable widgets built from the .mpk lose their <actionVariables>: the action's ValueType is written with an empty ActionVariables list, and mx check reports CE0463 #1200)
  2. Pluggable property kind-aware ALTER PAGE SET (ALTER PAGE … SET ImageUrl = … ON <image> reports "Altered page" and changes nothing: the pluggable setter writes PrimitiveValue into a TextTemplate-kind property, so DESCRIBE, mx check and the runtime never see it #1201)
  3. Starlark lint skill documentation completeness

What Looks Good

Minor Issues

Recommendation

Approve. The changes are:

  • Correctly scoped to fix specific reported issues
  • Fully tested with both unit and integration verification
  • Consistent with existing code patterns and architecture
  • Accompanied by validating MDL example scripts
  • The lint update prevents future documentation/code drift

No blocking issues found. The PR successfully resolves CE0463 for Signature/Calendar widgets and fixes broken ALTER PAGE SET for pluggable properties while improving lint rule author experience.


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

ako and others added 2 commits September 26, 2026 18:39
…nd CI validation

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs: MDL beta syntax proposal and ADR-0010..0012
@github-actions

Copy link
Copy Markdown

AI Code Review

Let me analyze this pull request based on the provided context and checklist.

The PR is titled "Sync ako/mxcli: pluggable widget action variables, ALTER pluggable property kinds, Starlark API docs" and includes:

  1. Pluggable widgets fixes:
    • Carrying action's <actionVariables> from .mpk (fixes CE0463)
    • ALTER PAGE writing pluggable property to correct field based on declared type
  2. Lint documentation improvements:
    • Documenting every Starlark builtin and struct field in write-lint-rules skill

Let me review against the checklist:

Overlap & duplication

  • The PR includes a proposal "PROPOSAL_mdl_beta_syntax_freeze.md" which appears to be new documentation about MDL language critique and beta syntax freeze
  • There are also new ADRs (0010, 0011, 0012) being added
  • I need to check if these duplicate existing proposals or documentation
  • Looking at the proposals list in CLAUDE.md, it says "Proposals in repo: No proposals directory." so this seems to be new content
  • The ADRs being added (0010, 0011, 0012) appear to be new decisions being recorded

MDL syntax design

  • The PR doesn't appear to add or modify MDL syntax directly (no changes to grammar files shown in the diff)
  • The changes are mostly about fixing existing functionality and adding documentation
  • The proposal document discusses syntax rules but doesn't appear to be implementing new syntax

Full-stack consistency

  • Since no new MDL syntax is being added, this doesn't apply
  • The fixes are to existing functionality (pluggable widget handling)

Test coverage

  • The PR includes several new test files:
    • mdl/linter/starlark_skill_coverage_test.go (327 lines)
    • modelsdk/widgets/actionvariables_test.go (187 lines)
    • modelsdk/widgets/mpk/actionvariables_test.go (103 lines)
    • mdl/backend/pagemutator/pluggable_property_kind_test.go (169 lines)
    • mdl-examples/bug-tests/1200-mpk-action-variables.mdl (24 lines)
    • mdl-examples/bug-tests/1201-alter-page-set-pluggable-texttemplate.mdl (24 lines)
  • This looks like good test coverage for the fixes being implemented

Security & robustness

  • No obvious security issues spotted in the diff
  • The changes seem to be about correctly handling data types and avoiding silent failures

Scope & atomicity

Code quality

  • The changes look consistent with existing patterns
  • No obvious old patterns being left behind
  • The design docs being added (the proposal and ADRs) seem to match the implementation approach

Bugs & correctness

Let me look more closely at the specific changes:

For the pluggable widget action variables (#1200):

  • Added ActionVariables field to PropertyDef struct in modelsdk/widgets/mpk/mpk.go
  • Updated XML parsing to handle actionVariables
  • Added buildActionVariablesArray and actionVariablesMatch functions
  • Modified reconcileValueTypesFromMPK to use the action variables from the MPK
  • Updated createDefaultValueType to use buildActionVariablesArray
  • Added comprehensive tests

For the ALTER PAGE pluggable property kinds (#1201):

  • Added buildPropKindMap function to determine property kind from widget schema
  • Modified setPluggableWidgetPropertyMut to:
    • Check for list values and refuse them
    • Determine the correct field based on property kind (TextTemplate, Expression, PrimitiveValue)
    • Handle null TextTemplate case (refuse rather than write to hidden slot)
    • Handle Expression kind correctly
    • Refuse structured kinds (Action, DataSource, etc.) that can't be set with plain values
    • Keep primitive kinds in PrimitiveValue
  • Added comprehensive tests

For the Starlark API documentation:

  • Significantly expanded .claude/skills/mendix/write-lint-rules/SKILL.md to document:
    • New query functions: queues(), java_actions(), database_connections(), documents(), documentable_elements(), navigation_targets()
    • Struct fields for scheduled_event, password_policy, project_security
    • Helper functions like get_option
  • Added test file mdl/linter/starlark_skill_coverage_test.go to verify the skill matches the actual API

Additionally, the PR includes:

  • A large proposal document PROPOSAL_mdl_beta_syntax_freeze.md discussing MDL language critique and beta syntax freeze
  • Three new ADRs (0010, 0011, 0012) documenting decisions about:
    • 0010: MDL canonical syntax rules
    • 0011: MDL language versioning
    • 0012: MDL-first and data-first editing
  • Updates to existing documents:
    • .claude/skills/design-mdl-syntax.md (minor changes)
    • docs/13-decisions/0003-mdl-is-sql-shaped.md (minor change)
    • docs/13-decisions/README.md (added entries for new ADRs)

Let me check if there are any issues with the proposal and ADRs:

The proposal PROPOSAL_mdl_beta_syntax_freeze.md discusses MDL language critique and beta syntax freeze. It mentions decisions ADR-0010, ADR-0011, ADR-0012 which are being added in this PR. This seems consistent - the proposal is proposing these decisions, and the ADRs are recording them as accepted.

Looking at ADR-0010 (0010-mdl-canonical-syntax-rules.md):

  • It establishes twelve syntax rules for MDL
  • It's marked as Accepted
  • Related to ADR-0003 and the proposal

ADR-0011 (0011-mdl-language-versioning.md):

  • About MDL evolving through deprecation aliases and language header
  • Accepted
  • Related to ADR-0010 and the proposal

ADR-0012 (0012-mdl-first-and-data-first-editing.md):

These seem to be legitimate architecture decisions being recorded.

Now, let me check against the specific review checklist items from CLAUDE.md:

Working Rules for a Change

Since this isn't a bug fix (it's a feature fix and documentation), I'll look at the general requirements:

Scope & atomicity

  • Each commit does one thing - Based on the PR description, it's three commits:
    1. Pluggable widgets - carry action's from .mpk
    2. ALTER PAGE writes pluggable property to correct field
    3. Lint - document Starlark builtins and struct fields
      This looks correct - each commit addresses one concern
  • Each PR scoped to single feature/concern - The PR description says it's syncing three commits from a fork, all related to improving widget handling and lint documentation. This seems reasonably scoped.
  • Independent features in separate PRs - The three commits are related (all about improving correctness of widget handling and documentation), so keeping them together makes sense
  • Refactors touching many files as own commit - No major refactors apparent

Code quality

  • Refactors applied consistently - No obvious inconsistencies
  • Manually maintained lists flagged as maintenance risks - The Starlark skill documentation is manually maintained, but the new test helps ensure it stays correct
  • Design docs match implementation - The proposal and ADRs being added seem to describe the current/future state of the project

MDL syntax design

Since no new MDL syntax is being added, this section doesn't apply significantly. However, the proposal document discusses syntax rules, so let me check if it violates any:

  • The proposal is documentation, not implementation
  • It's discussing existing and proposed syntax, not adding new syntax
  • It follows the guidelines by reading as English, using standard CRUD verbs, etc.

Full-stack consistency

Since no new MDL syntax is being added, this doesn't apply. The fixes are to existing functionality.

Let me check if there are any red flags:

  1. The proposal document is very large (1362 lines) - but it's documentation, not code
  2. The ADRs are being added - but they're documenting decisions that appear to have been made
  3. The Starlark skill documentation is greatly expanded - but it's being verified by the new test

One thing to check: in the ALTER PAGE pluggable property fix, there's this comment:

// A null template is how #574 stores one its condition hides. ALTER
// does not re-run visibility, so building one here would put text in
// a pruned slot — refused, not created.

This references issue #574, which seems to be about conditional visibility. The fix correctly refuses to write to a null/hidden template rather than creating it in a hidden slot, which would be incorrect.

Another thing: in the same function, there's:

// Structured kinds cannot be expressed as a plain SET value. Before, they took
// a string in PrimitiveValue and reported success.

And then it refuses kinds like Action, DataSource, etc. This seems correct - you shouldn't be able to set complex properties with simple values.

For the action variables fix, the comment explains:

// The package's action variables. A template from an older
// widget version (or one cloned without them) otherwise keeps
// a list that disagrees with the installed definition — CE0463
// (#1200). Rewritten only when it differs, so a template that
// already agrees keeps its entries as they are.

This shows they're being careful to only update when necessary to preserve $IDs, which aligns with the GUID preservation principles in CLAUDE.md.

Let me check if the PR follows the "Definition of Done" from CONTRIBUTING.md (referenced in CLAUDE.md):

  1. File an issue first - The PR references issues Pluggable widgets built from the .mpk lose their <actionVariables>: the action's ValueType is written with an empty ActionVariables list, and mx check reports CE0463 #1200 and ALTER PAGE … SET ImageUrl = … ON <image> reports "Altered page" and changes nothing: the pluggable setter writes PrimitiveValue into a TextTemplate-kind property, so DESCRIBE, mx check and the runtime never see it #1201
  2. Get approval - Not visible in diff, but assumed done
  3. Create feature branch - This is a sync from a fork
  4. Use contributor commands - Not visible in diff
  5. Validate locally - The PR includes tests that would be run with make test
  6. Open a PR - Done

The PR also mentions:

These are concrete symptoms that were fixed.

Let me check if there's anything that violates the MDL syntax design guidelines mentioned in CLAUDE.md:

  • Reads as English (target audience is citizen developers)
  • Uses standard CRUD verbs (CREATE/ALTER/DROP/SHOW/DESCRIBE)
  • Consistent property format (Key: value) for property definitions
  • AS for name-to-name mappings (old AS new)
  • Qualified names (Module.Element)
  • No keyword overloading
  • No symbolic syntax
  • Colon is for property definitions (Key: value), AS is for name mappings/renaming

Since no new MDL syntax is being added, these don't directly apply to the code changes. The proposal document discusses these guidelines but doesn't violate them.

One potential issue: I should check if the proposal document or ADRs introduce any syntax that violates these guidelines, but they're documentation, not executable MDL.

Let me look at one specific part of the proposal that might be concerning:

From PROPOSAL_mdl_beta_syntax_freeze.md:

### R1. One idempotent create, with one defined meaning

This is discussing a syntax rule, not implementing it. The actual implementation would be in the code, but I don't see changes to the grammar or visitor that implement this rule in this PR. The PR is adding documentation about the rule, not implementing the rule itself.

Actually, looking more carefully, the PR is adding the ADRs that record decisions about these rules, but the actual implementation of the rules would be in other PRs. This PR is just documenting the decisions.

This seems appropriate - first document and decide on the changes, then implement them in follow-up work.

Let me check if there are any missing pieces:

For the pluggable widget action variables fix:

  • Does it handle nested object-list properties as mentioned in the PR description?
    • Looking at the mpk/actionvariables_test.go, there's a test for nested action variables in object properties
    • The test parses widget XML with nested properties and checks action variables
    • So yes, it appears to handle nested cases

For the ALTER PAGE pluggable property kinds fix:

  • Does it handle all the cases mentioned?
    • TextTemplate: writes to TextTemplate field
    • Expression: writes to Expression field
    • Primitive: writes to PrimitiveValue
    • Null TextTemplate: refuses
    • List value: refuses
    • Structured kinds (Action, DataSource, etc.): refuses
    • This matches the PR description

For the Starlark API documentation:

  • Does it document everything mentioned?
    • Seven query functions: queues(), java_actions(), database_connections(), documents(), documentable_elements(), navigation_targets(), and one more? (The PR description says seven)
    • Two helpers: gets mentioned get_option
    • Several struct fields: scheduled_event schedule fields, password_policy, project_security fields
    • The expanded skill document shows all these

One thing I noticed: in the Starlark skill coverage test, there's this line:

if len(names) < 10 {
    t.Fatalf("buildPredeclared returned %d names -- the enumeration is broken", len(names))
}

This suggests they expect at least 10 builtins, which seems reasonable.

Let me check if there are any testability concerns:

  • The tests look comprehensive
  • They use table-driven approaches where appropriate
  • They check both positive and negative cases
  • They verify the actual BSON structure being written

One potential improvement: in the pagemutator/pluggable_property_kind_test.go, there are tests for refusing structured kinds, but I don't see a test for what happens when you try to set a list value. Wait, actually there is:

// A bracketed value arrives as []string and %v fused its tokens into one
// string written as success (#750). No pluggable property takes a list.
func TestSetPluggableProperty_ListValueIsRefused(t *testing.T) {

So that's covered.

Let me check if the changes align with the architecture described in CLAUDE.md:

From CLAUDE.md:

  • modelsdk/ is the MPR engine
  • mdl/ is the language: grammar -> visitor -> ast -> executor
  • api/ is the fluent builder layer
  • cmd/mxcli/ is the CLI

The fixes are in:

  • modelsdk/widgets/ - correct, this is part of the MPR engine for widgets
  • mdl/backend/pagemutator/ - correct, this is where page mutations happen in the backend
  • modelsdk/widgets/mpk/ - correct, MPK parsing is part of widget handling in modelsdk

The documentation changes are in:

  • .claude/skills/ - correct, this is where skills live
  • docs/11-proposals/ - correct, for proposals
  • docs/13-decisions/ - correct, for ADRs

Everything is in the right place.

Let me check for any violations of the "Critical" concepts from CLAUDE.md:

GUID preservation:

  • The action variables fix talks about keeping entries as they are when they already agree, to preserve $IDs
  • This aligns with: "Preserve the stored GUID when rewriting an existing element."
  • The comment says: "Reconcile rewrites an embedded template's list only when it disagrees with the installed package, so an agreeing template keeps its entries and $IDs."

ID preservation:

  • From CLAUDE.md: "Writes Are Conditional, and an $ID Is Never

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

@ako
ako merged commit 9509176 into mendixlabs:main Sep 26, 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.

2 participants