Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
e449181
fix(test): read the after-startup setting from the colon-form describ…
claude Oct 2, 2026
7e3fc4f
fix(check): a rendered test file no longer warns MDL-V1-SLASH
claude Oct 2, 2026
af17ac9
fix(association): do not reconcile System's access rules
claude Oct 2, 2026
0ffdaf6
fix(workflow): report an elided rewrite as Unchanged
claude Oct 2, 2026
feb41c8
fix(grammar): a grant member list accepts keyword-named attributes
claude Oct 2, 2026
65c1da3
fix(page): qualify an inherited CaptionAttribute with its declaring e…
claude Oct 2, 2026
38d5457
fix(describe): a combo box with OnChange keeps its Attribute and caption
claude Oct 2, 2026
8052f61
fix(theme): dropping a vendored font family keeps the partial's brace…
claude Oct 2, 2026
8d704af
fix(rename): renaming a view entity renames its OQL source document
claude Oct 2, 2026
c86b09a
style: gofmt reserved_keyword_hint_test.go
claude Oct 2, 2026
4201151
fix(lint): SEC008 counts only roles that can read a PII attribute
claude Oct 2, 2026
80878cf
fix(security): a revoke with nothing to revoke says Unchanged
claude Oct 2, 2026
8f7aa27
Merge remote-tracking branch 'origin/main' into claude/exciting-brahm…
claude Oct 2, 2026
1db6918
test(conformance): shrink the allowlist after keyword grant members p…
claude Oct 2, 2026
0896839
fix(check): give the contradictory-guard error its own id, MDL085
claude Oct 2, 2026
4a98159
fix(exec): drop the MDL067 note for a flow already stored that way
claude Oct 2, 2026
67f31b8
feat(exec): count the pre-flight's info notes instead of printing each
claude Oct 2, 2026
1ac3b4f
fix(describe): print a conditional editability once, as its expression
claude Oct 2, 2026
f949968
fix(check): a test file checked with --references declares MxTest
claude Oct 2, 2026
a3c5c97
fix(flow): in-loop refusals name `alter … replace loop`, not each other
claude Oct 2, 2026
1b0f4b7
docs(skills): change a loop body by replacing the whole loop with alter
claude Oct 2, 2026
49f0fa5
fix(check): MDL001 flags a nested loop only when it matches the itera…
claude Oct 2, 2026
465d9e7
Merge branch 'worktree-agent-afcd6e775a36d9908' into claude/exciting-…
claude Oct 2, 2026
d6109d4
Merge branch 'fix/quiet-rerun-diagnostics' into claude/exciting-brahm…
claude Oct 2, 2026
b2d3063
fix(check): report CE2421 and CE0582 on built-in input widgets
claude Oct 2, 2026
b5054b3
docs: input widget attribute types and the React drop-down
claude Oct 2, 2026
efab697
docs(skills): microflow arguments are named, never positional
claude Oct 2, 2026
ab6b193
Merge branch 'worktree-agent-a8898fc769ceb22cd' into claude/exciting-…
claude Oct 2, 2026
1fff432
fix(exec): refuse up front a flow change exec would refuse when reached
claude Oct 2, 2026
3d5c459
fix(lint): MPR008 measures each node with its stored size
claude Oct 2, 2026
f3c7964
fix(pages): store Visible/Editable on pluggable widgets
claude Oct 2, 2026
2939522
fix(pages): ShowLabel: false drops an input widget's label
claude Oct 2, 2026
d2cc9b9
Merge branch 'worktree-agent-ab5d2bc00ceae365e' into claude/exciting-…
claude Oct 2, 2026
ff2cda9
refactor(check): name the MDL-WIDGET39/40 rule ids as constants
claude Oct 2, 2026
f39adbc
fix(check): print one issue summary over every tier
claude Oct 2, 2026
41d8975
fix(alter page): make tab pages addressable by name
claude Oct 2, 2026
8502759
feat(meta): record which System entities store owner/changedBy/create…
claude Oct 2, 2026
809f117
fix(check): accept System.owner / System.changedBy in XPath, refuse b…
claude Oct 2, 2026
4600dd6
feat(check): report a used flow the script leaves without access (MDL…
claude Oct 2, 2026
33249a3
fix(alter page): write texts in the project's default language
claude Oct 2, 2026
49272c8
fix: keep a bare expression on a pluggable Expression property
claude Oct 2, 2026
a15dfde
Merge branch 'worktree-agent-a4da8feba89622032' into claude/exciting-…
claude Oct 2, 2026
07828f4
fix(entity): report an Auto* system member declared on a specialization
claude Oct 2, 2026
7d9acb5
fix(run --local --watch): bundle pages added while the loop runs
claude Oct 2, 2026
52b1759
fix: store HashedString attributes as HashedStringAttributeType
claude Oct 2, 2026
42b1b47
Merge branch 'worktree-agent-ac4c5b0760db121e4' into claude/exciting-…
claude Oct 2, 2026
70d1585
Merge branch 'fix/hashedstring-attribute-type' into claude/exciting-b…
claude Oct 2, 2026
a1d0883
fix(check): resolve a script-created association against project enti…
claude Oct 2, 2026
04e30fc
fix(check): flag getKey() in a retrieve constraint (MDL091)
claude Oct 2, 2026
2823e70
fix: MDL-WIDGET31 counts pluggable inputs in a list view
claude Oct 2, 2026
c521cec
fix(javaactions): generate the .java mxbuild generates, byte for byte
claude Oct 2, 2026
fa07a5a
docs(skills): correct the Java action parameter type mapping
claude Oct 2, 2026
9e67ec8
feat(exec): say when a new document is granted to the auto-created mo…
claude Oct 2, 2026
4d69b1a
fix(check): report a sort on CreatedDate / ChangedDate spelled with a…
claude Oct 2, 2026
1b49724
test(conformance): shrink the allowlist after the named-argument doc fix
claude Oct 2, 2026
14d4309
Merge branch 'fix/java-action-source-matches-mxbuild' into claude/exc…
claude Oct 2, 2026
e1e8464
Merge branch 'feature/ce0106-microflow-access-check' into claude/exci…
claude Oct 2, 2026
4beb5be
Merge branch 'worktree-agent-a32fa60ba5063dc4b' into claude/exciting-…
claude Oct 2, 2026
dccbd02
fix(security): never grant write on HasContents / PublicThumbnailPath…
claude Oct 2, 2026
ce05610
fix(security): revoke an inherited member by the reference it is stor…
claude Oct 2, 2026
3ccf7d0
fix(check): the expression-value rule is MDL-WIDGET42
claude Oct 2, 2026
1baba13
docs(skills): spell the owner constraint System.owner in the K2 migra…
claude Oct 2, 2026
c055175
test(conformance): shrink the allowlist after the HashedString fix
claude Oct 2, 2026
64a38bf
Merge branch 'fix/check-system-members' into claude/exciting-brahmagu…
claude Oct 2, 2026
7fc8f6a
refactor(check): one map of script association ends
claude Oct 2, 2026
f59c4da
Merge remote-tracking branch 'origin/main' into claude/exciting-brahm…
claude Oct 2, 2026
aaf48bf
fix(alter page): a replace keeps the stored editability it does not s…
claude Oct 2, 2026
eee301b
fix(pages): accept Visible: on every pluggable widget
claude Oct 2, 2026
18c5abf
fix(describe): print a pluggable image's visibility once
claude Oct 2, 2026
4611394
fix(pages): write an empty editability Conditions list with marker 2
claude Oct 2, 2026
7daeadb
feat(pages): bind a widget to a page or snippet parameter — $Param.Attr
claude Oct 2, 2026
6e60db8
Merge branch 'claude/exciting-brahmagupta-q0qhgl' into fix/snippet-pa…
claude Oct 2, 2026
53ba7d1
test(roundtrip): reclassify WorkflowCommons snippets that execute now
claude Oct 2, 2026
3b33ef1
Merge remote-tracking branch 'origin/main' into fix/snippet-param-bin…
claude Oct 2, 2026
47c9f65
style: gofmt sdk/pages/pages_widgets.go
claude Oct 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions .claude/lint-rules/sec_unconstrained_pii_read.star
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,29 @@ def check():
if len(pii_attrs) == 0:
continue

# Find roles with unconstrained READ
# Find roles that can read a PII attribute with no row constraint. The
# entity-level READ row is emitted when ANY member is readable, so it
# cannot answer this: a role granted `read (FullName)` has it too. The
# member row can. Its name is qualified for explicit member rights and
# bare when expanded from default rights, so match either spelling.
unconstrained_roles = []
readable_pii = []
for perm in permissions_for(e.qualified_name):
if perm.access_type == "READ" and perm.member_name == "" and not perm.is_constrained:
unconstrained_roles.append(perm.module_role_name)
if perm.access_type != "MEMBER_READ" or perm.is_constrained:
continue
for attr_name in pii_attrs:
if perm.member_name == attr_name or perm.member_name.endswith("." + attr_name):
if perm.module_role_name not in unconstrained_roles:
unconstrained_roles.append(perm.module_role_name)
if attr_name not in readable_pii:
readable_pii.append(attr_name)

if len(unconstrained_roles) > 0:
violations.append(violation(
message="Entity '{}' contains PII attributes ({}) and is readable without XPath row constraints by: {}".format(
e.qualified_name,
", ".join(pii_attrs),
", ".join(unconstrained_roles),
", ".join(readable_pii),
", ".join(sorted(unconstrained_roles)),
),
location=location(
module=e.module_name,
Expand Down
8 changes: 8 additions & 0 deletions .claude/skills/fix-issue/findings/cmd-mxcli.jsonl

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions .claude/skills/fix-issue/findings/mdl-backend.jsonl
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,10 @@
{"date": "2026-10-02", "area": "mdl/backend", "symptom": "Studio Pro 11.15 over --mcp: every write in a module fails 'validation failed for <doc>' with another document's error (e.g. an empty enumeration elsewhere); a nonexistent document checks 'No errors found.'", "cause": "11.15 replaced ped_check_errors' documents[] with filters{documentType,documentNamePrefix}+pagination and made all input schemas additionalProperties-permissive, so the old argument is accepted and IGNORED: the check ran project-wide. The answer became a paged listing ('Listing problems a-b (out of n). Check ID: k', then 'Name' (Type): unit headers).", "fix": "checkDocumentNow (mdl/backend/mcp/check_errors.go) sends filters when SupportsToolArg('ped_check_errors','filters'), fetches every page repeating the filters (a page without them lists the whole project), re-runs on a stale window, and keeps only problems under the exact 'Name' (Type): header (documentNamePrefix is a prefix). An unscoped listing from the fallback form is scoped the same way.", "insight": "A permissive schema turns an argument rename into a silent no-op, so 'the call succeeded' proves nothing; the live control needs a deliberately broken document AND a clean one checked in the same run (TestLive_CheckErrorsIsScoped). Gate on the newer shape's argument, never on serverInfo.version.", "file": "mdl/backend/mcp/check_errors.go", "issue": ""}
{"date": "2026-10-02", "area": "mdl/backend", "symptom": "Studio Pro 11.15 over --mcp: DESCRIBE of an entity edited this session shows String(unlimited) for String(200) attributes; reconstructed associations have empty type/owner.", "cause": "11.15's ped_read_document omits every property equal to its schema default (StringAttributeType.length=200, Association.type=Reference/owner=Default, NoGeneralization.persistable=true, BooleanConditionOutcome.value=false); readers mapped absent to Go's zero value, and length 0 means unlimited.", "fix": "attributeTypeFromPED reads length as *int and defaults absent to 200; reconstructAssociations defaults absent type/owner to Reference/Default.", "insight": "Diff the READ output of the same element across releases, not just tool schemas: this change is in one sentence of ped_read_document's description. Any new PED reader must treat an absent property as the schema default (ped_get_schema kind:element shows '= default').", "file": "mdl/backend/mcp/read_router.go", "issue": ""}
{"date": "2026-10-02", "area": "mdl/backend", "symptom": "create workflow \u2026 display 'X' over --mcp stores the document name as the workflow title and workflowName (Studio Pro 11.14 and 11.15).", "cause": "The context-shaped Workflows$Workflow constructor ignores the title (11.14 'caption', 11.15 'title') and workflowName it is given; 11.15 also renamed caption->title, which its permissive schema would have dropped silently anyway.", "fix": "workflowConstructorTakesContext's probe records the title key (workflowCtorTitle); workflowCreateLeafOps sets /title and /workflowName/text after the create (set ops both releases accept).", "insight": "Read back what a constructor stored instead of trusting SUCCESS: both releases accepted the key and applied nothing.", "file": "mdl/backend/mcp/workflow.go", "issue": ""}
{"date": "2026-10-02", "area": "mdl/backend", "symptom": "alter page … set (Caption = '…') on tabPage2 fails with `widget \"tabPage2\" not found` although describe page prints `tabpage tabPage2`; a tab caption missing its default-language translation (mxbuild CE4899 after switching DefaultLanguageCode) could only be fixed by re-creating the whole page.", "cause": "findInWidgetChildren (and its twins findNearestDSInChildren and collectWidgetScopeInChildren) walked TabPages[] only to descend into each page's Widgets[], never matching the Forms$TabPage's own Name — a tab page is a named element that lives in a list that is not a widget list.", "fix": "Walk TabPages through findInWidgetArray / findNearestDSInWidgets / collectWidgetScope like any named list; INSERT INTO a tab page appends to its Widgets, and INSERT BEFORE/AFTER, REPLACE and DROP on a tab page are refused (refuseTabPageSiblingEdit) because they would write widgets into TabPages or orphan the control's DefaultPagePointer.", "insight": "Resolving a new kind of node also hands it to every structural op that trusts parentKey/parentArr: making X addressable means deciding, per op, what writing into X's parent list does.", "file": "mdl/backend/pagemutator/mutator.go", "issue": ""}
{"date": "2026-10-02", "area": "mdl/backend", "symptom": "On a project whose default language is de_DE, alter page … set Caption on a tab page (and set Label on any Studio Pro 11 input widget) reports `Altered page` and stores nothing; set Caption on a button writes the German text over the first translation (en_US); set Title overwrites every language with the same string.", "cause": "Four text writers with four rules: setTranslatableText looked for a `Translations` key no Mendix document has, then DSet a `Text` field DSet cannot add (silent no-op on every real Texts$Text); setWidgetLabelMut read only the legacy `Label` key while 10+/11 store LabelTemplate (a Forms$ClientTemplate); setClientTemplateText wrote Items[0] whatever its language; updateTextsTextValue/updateClientTemplateText wrote all translations. A unit test built the fictional `Translations` shape and asserted nothing, so it stayed green.", "fix": "One helper, setTextsTextTranslation: update or append the Texts$Translation for model.AuthoringLanguage() (the project default DESCRIBE shows), keep other languages; setTranslatableText dispatches on $Type (Texts$Text / Forms$ClientTemplate) and refuses anything else; setWidgetLabelMut tries LabelTemplate first; execAlterPage resolves the authoring language before the first mutation.", "insight": "A text setter's test must build the shape read back from a Studio Pro-authored page (bson dump --format ndsl) and assert the stored translation per language; `err == nil` proves nothing for a setter whose miss path is DSet returning false. Verified live: de_DE switch → CE4899 on tabPage2, set Caption → de_DE added, en_US/nl_NL/ar_DZ kept, 0 errors.", "file": "mdl/backend/pagemutator/mutator.go", "issue": ""}
{"date": "2026-10-02", "area": "mdl/backend", "symptom": "create entity over --mcp stores every attribute as String(200) on both Studio Pro 11.14 and 11.15 MCP servers; String lengths never written (also on alter entity add attribute).", "cause": "pedAttribute sent \"$Type\":\"DomainModels$Attribute\" inside the DomainModels$Entity constructor, whose attributes are PlainObject<{name,type,enumerationName}>; with $Type present PED ignores `type` and still answers SUCCESS and a clean check. Neither attribute constructor has a length property.", "fix": "buildEntityValue clears $Type on nested attributes (omitempty); applyAttributeLengths sets /entities/N/attributes/M/type/length after create and after add for every String not at the schema default 200.", "insight": "The same element has two constructor shapes depending on where it is added (nested PlainObject vs standalone constructor) \u2014 read ped_get_schema for the container, not the element. A clean ped_check_errors proves nothing about a dropped property; only a read-back of each type caught it.", "file": "mdl/backend/mcp/domainmodel.go", "issue": "ako/mxcli#923"}
{"date": "2026-10-02", "area": "mdl/backend", "symptom": "TestLive_EntityAccessRuleReject fails on every live Studio Pro MCP server (entityIndex: not found) \u2014 its fixture module ExpenseApproval exists in no test project.", "cause": "The live test read a hand-made fixture (module/entity/role) from one developer's project via env defaults instead of building it.", "fix": "The test creates its own entity Zz_R12_AccessFixture_<stamp> in MXCLI_MCP_MODULE, grants MXCLI_MCP_ROLE (default <module>.User) once, then asserts the second grant is rejected with the rule count unchanged; skips with the role to set when the role does not exist (module roles cannot be created over MCP).", "insight": "A live test that depends on state it does not create fails as an environment problem on every other machine, so its real failures read as noise; build the fixture, and skip only on what MCP cannot author.", "file": "mdl/backend/mcp/security_test.go", "issue": "ako/mxcli#924"}
{"area": "mdl/backend", "date": "2026-10-02", "symptom": "A view entity's OQL document that Studio Pro excluded is re-included by any CREATE OR MODIFY of the view entity that changes its query.", "cause": "encodeViewEntitySourceDocument writes Excluded=false as a constant, and WriteViewEntitySourceDocument's update path carried only the stored ExportLevel (#816), not Excluded.", "file": "`mdl/backend/modelsdk/move_view_write.go` (WriteViewEntitySourceDocument), `export_level_carry.go` (keepStoredExcluded)", "insight": "A shared create/update encoder that writes model state as a constant needs a carry on the update path for every such key, not just the one a previous bug named (#816 ExportLevel, #914 Excluded).", "refs": ["ako/mxcli#827", "ako/mxcli#914"]}
{"area": "mdl/backend", "date": "2026-10-02", "issue": "ako/mxcli#803", "symptom": "`create association A.X from A.E to B.F on delete restrict` (TO entity in another module) stores ChildDeleteBehavior DeleteMeIfNoReferences with a null ChildErrorMessage — the shape that stops the runtime starting (CapTrackV2 §1). The same statement within one module, and ALTER on the cross-module one, were fine.", "cause": "crossAssocToGen built the delete behaviour without the restrict message; #795 added patchCrossDeleteErrorMessage only at one call site (patchCrossAssociations' new-element arm), not in the converter, so CreateCrossAssociation still wrote null.", "file": "`mdl/backend/modelsdk/association_move_write.go` (crossAssocToGen)", "fix": "Call patchCrossDeleteErrorMessage inside crossAssocToGen, as assocToGen does inline; drop the now-redundant call site.", "insight": "A property fix belongs in the converter, not at the call site that was reported — enumerate the converter's callers. Test: mdl/backend/modelsdk/issue803_cross_assoc_restrict_test.go, keep behaviour as the null control."}
{"area": "mdl/backend", "date": "2026-10-02", "symptom": "getput: describe → exec of a combo box with `Editable: <expr>` rewrites ConditionalEditabilitySettings/Conditions[0]: 2 -> 3", "cause": "Forms$ConditionalEditabilitySettings registered Conditions as a plain mandatory list (default marker 3); Studio Pro writes [2], as for visibility", "file": "`mdl/backend/modelsdk/widget_write.go` (RegisterTypeDefaults)", "insight": "measured on both editability settings in TestApp; the ALTER path (pagemutator setWidgetConditionalSettingMut) still hand-writes [3] for both settings", "refs": ["#721"]}
Loading
Loading