Repository navigation
Sync ako/mxcli: describe flow round-trips, check false refusals, per-file findings - #1353
Merged
Merged
Conversation
getErrorHandlerBody kept its own list of statements with an ON ERROR clause and lacked the REST statements (and call workflow, the mapping statements, commit, delete, …). The merge/join label walk read handler bodies through it, so a `join` in a REST call's custom error handler went unseen and its merge was reported as "nothing joins it". That is the retry loop of Studio Pro-authored OIDC.GET/POST/PUT/PATCH/DELETE and AWSAuthentication.POST_v1_GetCallerIdentity_ValidateCredentials, which build at 0 errors; exec refused their describe output. getErrorHandlerBody now reads the shared StatementErrorHandling table (mdl/exprcheck/adapters), as stmtErrorHandling already does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hing #953 taught the duplicate-variable check (MDL063) that a call to a void Java/JavaScript action keeps an inert output name. Studio Pro stores calls to void microflows and nanoflows the same way (ResultVariableName with UseReturnVariable=true), and the resolver never looked at them: Evora's OIDC.webCallback, OIDC.SUB_HandleUserProvisioning and two Teamcenter microflows (0 errors under mx check) failed check, and describe headed webCallback with "duplicate output variable … model is invalid". Measured on mxbuild 10.24.15 and 11.13.0: two void microflow calls of one name 0, void call then declare 0, two void nanoflow calls 0, reading a void microflow call's output CE0109, two String microflow calls CE0111. voidCodeActions now resolves called microflows and nanoflows (script first, then the project), which also extends MDL093 and describe's duplicate-output header to them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ning Studio Pro keeps an end event's return value when a microflow's return type is set to Nothing, and hides the field. Evora stores five such microflows; describe renders the value faithfully and MDL004 refused it, so exec would not re-apply an untouched microflow. mxbuild 10.24.15 and 11.13.0 build the shape at 0 errors. The value is not inert — the runtime returns it, and a workflow branching on the call fails at instance start — so new code keeps the error. Like DropSettledCommitNotes for MDL067, check -p and exec now downgrade it to a warning only for a microflow the project already stores with at least as many valued end events. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eral Studio Pro names a True/False enumeration's values `_True` and `_False` and stores a constraint on one as `[A = '_True']`; describe prints it as `[A = M.E._True]`. The stored-form rewrite (normalizeXPathEnumRefs) matched only value names starting with a letter, so exec wrote the qualified name verbatim — CE0161 on mxbuild 10.24.15 — and `check -p` correctly refused it as "neither an attribute nor an association". Evora's AgentCommons.DS_Agent_GetDeployedModels is the instance. The value part of xpathEnumRefRe now allows a leading underscore, as xpathQualifiedNameRe already did. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e as Boolean `mxcli check -p` reported E009 (Boolean slot, Decimal expression) on `hoursBetween(...) : 4 < $Max` in Evora's ConversationalUI.*_GetGranularity microflows, which Studio Pro and mxbuild accept. The expression checker's lexer did not know `:` and emitted a TokError. parseMul saw no operator, parseCmp saw no comparison, and Parse skips the trailing-token error for TokError, so the expression was silently truncated to `hoursBetween(...)` and typed as Decimal. The MDL grammar itself already parsed `:` at the multiplicative level; only the checker's second parser had drifted. `:` is now TokColon, parsed at the one left-associative multiplicative level with `*`, `div` and `mod`, typed as Decimal like `div`, and treated as a recovery boundary. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…translations checkTranslationTargets read the project settings (for the source language) on every `check -p`, and only consults them for a `create translations` statement. Skip the read when the script has none. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… about `check -p` on a 140 MB MPR v1 project spent ~9 s in CheckProjectConflicts for a one-flow `create or modify` script: loadProjectNameSets listed all ~40 document kinds, and every module's security, before reading a statement — though only a plain CREATE is ever flagged. CheckProjectNameClashes then listed its 13 kinds up front too. - projectNameSets.setFor lists a kind on first use and caches it. CheckProjectConflicts asks only for the kinds a plain CREATE names; a DROP records a dropped project name only when a plain CREATE of its kind follows (droppedFromProject is read nowhere else). - CheckProjectNameClashes lists a kind only if a create, rename or move can read it (the union of nameSpaceKinds over those statements). A drop on another kind updates a throwaway set nothing reads. Semantics unchanged: a lazily-loaded set plus the same mutations equals the eagerly-loaded one. `create or modify microflow` still lists the flow name space (microflow/nanoflow/rule), since a cross-kind clash is CE0122 whether or not the statement modifies. Tests count the listings through a MockBackend whose List* fields are wrapped by reflection: on main the or-modify script issues 36 listings; now 0 for a kind with no shared name space, 3 for a microflow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A crossed merge (Mode 2) is joined on arrival by traverseFlow, traverseFlowUntilMerge and continueAfterSplitJoin, but five other places walked THROUGH a merge without asking: continueAfterNestedSplitJoin, the split-type continuation at both levels, and the guard-clause false-branch skip at both levels. When the crossing sat inside another branch, the crossed merge's suffix was printed inline there, and then either - the walk marked it visited, its section was never declared, and the description ended in `merge shared1; join shared2;` with nothing declaring shared2 (Evora SnowflakeIntegration / SnowflakeRESTSQL .Request_Validation: MDL-FLOW02, MDL003), or - the walk ran on a case/split-type arm's private visited copy, so the section printed the suffix a second time (Evora AgentCommons.Tool_Validate: one stored MicroflowSelection_GetCreate call, two in the description, MDL063). Every pass-through now asks joinCrossedMerge first, and a labelled merge is no longer skipped by the guard-clause continuation. The faithful Tool_Validate description then failed check for a second reason: the section after the `split type` reads $IsValid, declared in the arm that joins it. The check-time validator scoped variables by text order; a `merge <label>` now sees what its joins had declared, and the linear MDL005 branch-scope warning stops at a merge, where scope comes from the joins it cannot see. assertDescriptionRebuildsGraph is the invariant every test here holds a description to: parse it, build it with the real builder, and compare the graph with the stored one modulo exclusive merges - every stored activity exactly once, every stored sequence flow present. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A `case` or `split type` walks every arm with its own copy of the visited set until the split's join, so a region that two arms reach before that join was printed in both. Evora OIDC.handleAuthorizationCode has one token REST call where two of its four arms meet; the description had two, both with output $TokenResponse (MDL063), and re-executing it builds an activity the model does not have. Mode 2 did not label it because a fourth arm returns: the split's post-dominator is then the exit, the overlap has two entries (the shared region and the join), and Analyze classifies it interleaved, which labelCrossedMerges skips. sharedArmEntries computes the overlap from the describer's own stop instead, and when it holds a real activity and is entered through merges, labels the entry and the split's join as crossed: the arms `join` the region, which is printed once in its section. Arms that meet on a bare merge chain print nothing twice and are left alone. The MDL-FLOW01 "NOT equivalent, must not be re-executed" warning is retired when every entry of the finding was declared, not only a single one - otherwise it stays on a description that is now faithful. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A manual loop - a merge the path comes back round to - is written as `while true` by traverseFlow at the top level. Reached inside an `if` branch, traverseFlowUntilMerge walked through it as a plain merge, so the way round came back to an activity already printed and stopped in silence. The description had no back-edge and re-executed to a flow that ends where the original goes round again: Evora AmazonBedrockConnector.AmazonBedrockAgent_Sync and AmazonBedrockKnowledgeBase_Sync lost their pagination loop (MDL003). The branch walker now writes the same `while true`. Only a merge whose way round avoids the enclosing stop and everything already printed is a header: the merges on the path BACK to it are on the cycle too, and treating them as headers nested empty loops inside the body. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…1314) Since mendixlabs#1269 lint reads modules().domain_model_documentation and project_security().admin_user_name, but MDL could write neither: the doc comment before `create or modify module MyFirstModule` is lost ... [MDL089] alter app security has no property "AdminUserName" - The doc comment on `create [or modify] module` is stored as the module's domain model documentation (DomainModels$DomainModel. Documentation; Projects$Module has none). No comment preserves what is stored, `/** */` clears it, and a plain create of an existing module stays a no-op. `describe module` prints it back as that comment. - `alter app security ( AdminUserName: '<name>' )` renames the built-in administrator. The password stays out of MDL (#624). New backend methods SetDomainModelDocumentation and SetProjectAdminUserName change only that property on the stored unit. Checked on a fresh 11.12.5 app: exec, describe round-trip, the catalog column lint reads, and mx check with 0 errors, same as an untouched control. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uj8k5uUCi1zKZ3Edj8MZ8h
…L stored first mendixlabs#1182 (v0.23.0, Mendix 11.12.2): "SET Caption wrote Dutch, and restating the snippet deleted the other languages." Both halves are already fixed on main — SET by setTextsTextTranslation writing the project default language's entry (33249a3), the restate by CarryTranslations pairing a text by its owning named element. Neither had a test of the reported shape: a caption whose default language (en_US) is listed SECOND after nl_NL, and a restate that changes the English and the widget tree at once. This adds them. Verified against the reporter's version: upstream v0.23.0 built from its tag and run on a fresh 11.12.2 project with nl_NL listed first — SET: nl_NL "Opslaan" -> "Save changes", en_US stays "Save" restate: nl_NL deleted and on this branch — SET: en_US -> "Save changes", nl_NL "Opslaan" kept restate: en_US "Save all changes", nl_NL "Opslaan" kept; mx check passes. Controls: writing the first listed translation fails the mutator test with map[en_US:Save nl_NL:Save changes]; disabling owning-element pairing fails the canon test with map[en_US:Save all changes]. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Sg2HXaNgpZDxkHr9CYwEXp
The describe-round-trip-gaps page said the read path has no oracle. For a flow it does: rebuild the description and compare graphs. Note it, and note that `Unchanged` from `create or modify` on a describe output is the splice verdict, not evidence the description is the stored graph. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every fix appended a line to a shared findings/<area>.jsonl, and nearly every fix lands in mdl-executor. merge=union resolved that locally, but GitHub's server-side merge does not run merge drivers, so each merged fix-PR put every other open one into conflict: eight PRs re-conflicting after each merge, each needing a local merge, rebuild and re-test. Findings are now findings/<area>/<date>-<slug>.json, one JSON object on one line. Two fixes add two different files; nothing conflicts. - scripts/split-findings.py did the migration and stays as the remedy for a pre-split branch that brings a shard file back on merge. It writes each line verbatim, so the result is the multiset of unique original lines, byte for byte (1,579 lines -> 1,573 files: six records were in mdl-executor.jsonl twice, a union-merge artefact). - check-findings validates the files (name pattern, one line, fields) and refuses a stray *.jsonl, naming the converter. - digest-status reads the new glob; the merge=union line is removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… per-file layout Recording a fix now means adding a file, never appending; lookups use grep -r and DuckDB's read_json_auto over findings/*/*.json. Bug-pattern page sources name the area directories. Historical logs (SYNC_LOG, CHANGELOG, proposals, bug reports) keep the paths they were written with. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
TestRepoClaudeMDStaysWithinItsContextBudget caps CLAUDE.md at 28,000 bytes and main sat at 27,991, so the per-file wording has to be byte-neutral. The why (GitHub does not run merge=union) lives in the findings README; CLAUDE.md keeps only the instruction. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
main appended two findings to the old shards (cmd-mxcli, mdl-executor) since this branch was cut; scripts/split-findings.py turned exactly those two lines into files and removed the re-created shards. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`alter page M.P { add parameters $X: T; }` was a parse error ("mismatched
input 'parameters' expecting VARIABLES_KW"), so adding a parameter to an
existing page meant CREATE OR REPLACE, which rebuilds every widget and
loses what describe does not round-trip.
- Grammar: `add parameters <pageParameter>` / `drop parameters $X`, reusing
CREATE's `pageParameter` rule; the visitor shares `buildPageParameter`.
- PageMutator gains AddParameter/DropParameter. The raw-BSON mutator gets
the element from a new Deps.SerializeParameter, which the codec backend
implements with CREATE's own pageParameterToGen/snippetParameterToGen, so
the 11.5+ IsRequired/DefaultValue gate holds. Key set matches a Studio
Pro-authored parameter on the 11.6 fixture.
- Exec refuses an add that leaves a page's Url without the new parameter's
segment (CE5601, measured on 11.12.1) unless the statement sets a Url
that names it; a primitive snippet parameter (MDL087/CE0046, also at
check time); a drop while a data source or expression still uses it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ZiACMmuCejcDnzsvG3PKQ
When two or more activities' error flows land on one merge that no normal path reaches, every `on error … begin end error` block came out empty and the handler body they share disappeared from the description. The handler walk stops at the first merge it meets and emits `join <label>` only when the merge has a label, and labelRejoinMerges names only merges the normal path also reaches. Re-executed, the description deletes the shared handler. Label such a merge as a crossed merge: each block now ends in `join sharedN;` and the body is printed once, in its own section after the main flow. The builder already accepts a forward join out of a handler, so this needs no new syntax. Evora: PrePopulateData.ASU_CheckForWorkforce (three calls, one log + end) and GenAICommons.ToolCall_ProcessAndExecuteTool (two calls, four activities rejoining the main path) now rebuild their stored graphs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In a loop body, an activity with no outgoing flow ends the iteration. When such an activity closed a branch whose join goes on (to a `break`, or to more activities), the description closed the branch and printed the join's path after it, so the arm fell into that path. GenAICommons.Trace_GetModelSpanInput then broke out of its loop at the first ToolSpan instead of collecting them all. The arm now ends in `continue;` when anything is printed after the branch closes, at any enclosing level up to the loop body. That is not a local question (IVK_RecalculateSize's dead end sits in an `if` with no join, inside a `case` arm whose join goes on), so it is carried on the ExecContext: set when a branch walk's stop merge goes on, inherited by nested walks, extended for a guard's THEN arm by the false continuation, and reset per loop body. A dead end whose branch is the last thing in the body gets no `continue`, which keeps the commonest loop shape (last body activity is a dead end) unchanged. Evora: GenAICommons.Trace_GetModelSpanInput, MxModelReflection.IVK_RecalculateSize and TeamcenterToolkit.ExpandGRMInput_Create now rebuild their stored graphs (a ContinueEvent stands in for the dead end, which the invariant treats as the same ending). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An error handler's path can run through ExclusiveMerges with a single incoming flow, which join nothing (Studio Pro leaves them behind when a flow is re-routed). firstReachableErrorHandlerMerge settled on the first of them as the handler's stop, and the handler walk stops at any merge, so everything after it was dropped. In SnowflakeRESTSQL.GET_v1_RetrievePartition that was `set $Retry = false` and the way back to the loop header: re-executed, a token retry became a fall-through. A merge with one way in is now walked through: by the handler walk, by firstReachableErrorHandlerMerge, and by firstMergeFrom, which decides where a handler rejoins and so which merges need a label. The two traverse tests that modelled a rejoin merge with only the handler's flow into it now give it the main path's flow too, which is what makes it a rejoin. The faithful description then failed `mxcli check` with "merge rejoin1: nothing joins it" (MDL-FLOW02), for two reasons. The label walk read handler bodies through getErrorHandlerBody, which does not know a REST call has one; it now uses the builder's statementErrorHandling. It also treated every `while` as a loop activity, but `while true` around a return is a merge and a back-edge in the enclosing graph, so its labels belong to that graph. A label in a handler inside a real loop is now refused (MDL-FLOW04) instead of being missed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Studio Pro can draw one merge that both closes an `if` and heads a loop. The describer paired it with the `if` and walked on after `end if`, so the way round came back to an activity already printed and stopped there. In SnowflakeRESTSQL.POST_v1_ExecuteStatement that dropped the 202 poll: re-executed, the description calls the service once and carries on as if it had answered. When a split's join is also an undescribed loop header (the same test #1055 uses for a header inside a branch: a way round that avoids the stop and everything already printed), continueAfterSplitJoin and continueAfterNestedSplitJoin now write it as `while true` after the split. MDL spells the two jobs as two statements, and the rebuild's two merges contract to the stored one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… are merges
An `if` whose arms reach a shared region at different depths was left alone
when the overlap had more than one entry ("interleaved"): it kept the #923
MDL-FLOW01 "NOT equivalent" warning and was nested as fall-through. In
OIDC.GetLoginEndpoint that sent an arm two decisions deep past the
authorization-URL region straight to the nonce cookie.
When every entry of an interleaved `if` is a merge, label each entry and the
join as crossed merges: every arm that reaches one ends in `join`, and each
region is printed once in its own section that joins the next. This also
needed armFallsInto. When no arm falls out of the `if` (they all return or
join), the crossed join is no longer written after `end if`, where it was an
edge out of nothing that the builder then invented a source for. The textbook
A -> {B, C}, B/C -> {D, E} fixture fails without it.
An interleaved overlap entered at an activity is still left with MDL-FLOW01,
because there is no merge to name. TestLabelCrossedMerges_IgnoresInterleaved
encoded the old decision, so it is replaced by one test for each side of the
new line.
On Evora this fixes GetLoginEndpoint and retires a stale MDL-FLOW01 on six
flows that already rebuilt correctly, with no new invariant violations.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Resolves the findings-file conflict GitHub reports for appends to the shards (merge=union keeps both locally; GitHub's server-side merge does not run merge drivers). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Resolves the findings-file conflict GitHub reports for appends to the shards (merge=union keeps both locally; GitHub's server-side merge does not run merge drivers). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Resolves the findings-file conflict GitHub reports for appends to the shards (merge=union keeps both locally; GitHub's server-side merge does not run merge drivers). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Resolves the findings-file conflict GitHub reports for appends to the shards (merge=union keeps both locally; GitHub's server-side merge does not run merge drivers). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Converts the findings main appended to the old shards since the last merge into per-finding files with scripts/split-findings.py. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix(check): a void microflow/nanoflow call's output name declares nothing (MDL063)
Resolves the findings-file conflict GitHub reports for appends to the shards (merge=union keeps both locally; GitHub's server-side merge does not run merge drivers). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix(check): MDL004 on a stored void microflow's return value is a warning
Resolves the findings-file conflict GitHub reports for appends to the shards (merge=union keeps both locally; GitHub's server-side merge does not run merge drivers). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Converts the findings main appended to the old shards since the last merge into per-finding files with scripts/split-findings.py. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
chore(findings): one file per finding, so fix-PRs stop conflicting
main now stores findings one file per finding (#1054). This branch's appended line in mdl-executor.jsonl is converted with scripts/split-findings.py into its own file. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
main now stores findings one file per finding (#1054). This branch's appended findings lines are converted with scripts/split-findings.py into their own files. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
main now stores findings one file per finding (#1054). This branch's appended findings lines are converted with scripts/split-findings.py into their own files. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix(xpath): store an underscore-led enumeration value (`_True`) as a string literal
main now stores findings one file per finding (#1054). This branch's appended findings lines are converted with scripts/split-findings.py into their own files. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…invariant-remaining main now stores findings one file per finding (#1054). This branch's appended findings lines are converted with scripts/split-findings.py into their own files. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…82-xlma7z # Conflicts: # .claude/skills/fix-issue/findings/mdl-backend.jsonl
…34-2z9io3 # Conflicts: # .claude/skills/fix-issue/findings/mdl-grammar.jsonl
fix(exprcheck): lex `:` as Mendix division so comparisons over it type as Boolean
perf(check): list only the document kinds the script's statements ask about
fix(describe): irreducible microflow graphs describe as the stored flow
…14-5to4h3 # Conflicts: # .claude/skills/fix-issue/findings/mdl-executor.jsonl
Add module documentation and admin user name support (issue mendixlabs#1314)
test: pin mendixlabs#1182 — SET Caption and snippet restate with nl_NL stored first
Add ALTER PAGE/SNIPPET support for ADD/DROP parameters
…abs#1254) (#1060) A decision whose caption was cleared in Studio Pro stores Caption ''. Describe skipped an empty caption, and a decision with no @caption is built with its condition as the caption, so the round trip added "@caption 'true'" to the diagram. Describe now prints @caption '' for an empty decision caption; the visitor keeps an explicit empty @caption (ActivityAnnotations.CaptionSet) and the builder applies it to if and enum splits. Fixes mendixlabs#1254 Claude-Session: https://claude.ai/code/session_019Tfs5Hj34WTnLFtBTb8Bze Co-authored-by: Claude <noreply@anthropic.com>
fix(describe): the 8 remaining flows describe as their stored graph (re-land of #1056)
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
ako/mxcli:mainintomendixlabs/mxcli:main: 24 commits since #1340, landed in the fork through PRs ako#1045–ako#1061.Note on the diff size: almost all of the 1,752 changed files are the findings migration below. The bug-findings
.jsonlshards become one file per finding.Describe: flows that did not round-trip
Found by rebuilding the describe output of every flow in a large real-world project and comparing graphs. Each of these re-executed to a different flow than the one stored.
casearms share is printed once, and every crossing of an interleavedifwhose entries are merges is joined.continue;instead of falling into the join's path.Check: false refusals on Studio Pro-authored flows
:is lexed as Mendix division in the expression checker, sohoursBetween(…) : 4 < $Maxtypes as Boolean (false E009)._True) is stored as a string literal (CE0161).check -plists only the document kinds the script's statements ask about (~9 s saved on a 140 MB MPR v1 project), and reads project settings only for scripts that write translations.MDL
alter page|snippet … { add parameters $X: T; drop parameters $X; }(ALTER PAGE cannot add or drop page parameters (only variables) #1234), without CREATE OR REPLACE.create [or modify] module, andalter app security ( AdminUserName: '…' )(MDL cannot set the domain model documentation or the admin user name #1314).Contributor tooling
findings/<area>/<date>-<slug>.json) instead of shared.jsonlshards. GitHub's server-side merge does not runmerge=union, so every merged fix-PR put the other open ones into conflict.scripts/split-findings.pydid the migration byte for byte, and skills, commands, CLAUDE.md and the wiki point at the new layout.