Repository navigation
new(lint): ERR001 ErrorSwallowed + LOOP001 ExpensiveActionInLoop (lint backlog Batch 1) - #248
Merged
Merged
Conversation
Two Starlark rules delivered through the existing lint-rules install/refresh path (install-manifest MXTK_LINT_RULES, README row each, delivery fixture count 4 -> 6). UX001 flags a button that deletes directly (Forms$DeleteClientAction has no confirmation setting) or calls a microflow/nanoflow without "Ask confirmation" when that flow deletes objects (bounded call-graph walk) or is named as an irreversible step (Approve/Reject/Submit/Archive/...). UX002 flags decisions left on their auto-generated caption and flows of 8+ top-level activities with neither an annotation nor a documentation text. Both need mxcli >= 0.25.0 (widget action_type/has_confirmation, activity caption/auto_generate_caption) and emit a `_rule` blindness finding on anything older, so lint-gate.sh never reads them as a clean pass. Vocabulary was read from the mxcli catalog builder source, not from the bundled API guide. No mxcli binary was reachable in the authoring session, so the first field calibration on a scratch copy of a real model is still owed; the README note says so and names the probe queries. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
…reter tests/lint-rules/ runs both rules through go.starlark.net at mxcli's pinned version via a small Go harness (starrun) that rebuilds the mxcli projection structs from JSON fixtures and rejects any field the projection does not have. 33 hand-written fixtures cover self-checks, call depth on both sides of the bound, cycles, the destructive-name pattern, module skips, snippet locations and the version probe; a generated 3000-flow / 20000-widget model times each rule (~0.7 s). 35 cases, wired into CI as its own step. The suite caught two defects in UX002 before they shipped: StartEvent/EndEvent objects returned by activities_for() inflated the activity count, and the "needs mxcli >= 0.25.0" probe only fired on flows that had a decision. Both fixed here; UX001's depth comment now states what the bound means. Fixtures encode the projection as read from the mxcli source, not captured output: they prove the rule logic, not the catalog vocabulary. Field calibration on a real model is still owed and the README still says so. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
check-portability.sh (in CI) rejects a hard-coded `python3`: on Windows a name on PATH may be the Store alias stub, not an interpreter. The suite now sources bin/lib/portable.sh, calls require_py and runs "$PY", like every other script here. 35/35 cases still pass; check-portability clean. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
…atch 1) First batch from process/lint-backlog.md, as the rollout there prescribes: two rules, warning severity, Starlark unit fixtures, draft until a real project reports a count. ERR001: an activity set to Continue / Custom / CustomWithoutRollBack in a flow where nothing logs (LogMessageAction), raises (ErrorEvent) or calls a handler-named flow (SUB_LogError, ERR_*). The complement of mxcli's CONV013/CONV014, which only check that handling is set. LOOP001: a database retrieve, delete, REST, external or Java call inside a loop body at any depth. CONV011 covers commit-in-loop; this is the rest. Association retrieves, sub-flow calls and unknown retrieve sources are left alone. Vocabulary from the mxcli source, not guessed: error_handling_type values per sdk/microflows/error_handling.go (CustomWithoutRollBack, capital B), loop_depth / retrieve_source per the 0.25.0 catalog builder. Both rules read the fields through getattr and emit a `_rule` blindness finding on an older binary, an empty column, or loops with no indexed bodies. tests/lint-rules/test-batch1-rules.sh: 29 cases under the real Starlark interpreter (incl. the 3000-flow perf fixture), wired into CI. The starrun harness gains activities_for(nested=) mirroring the 0.25.0 builtin, so the default call hides loop bodies exactly as mxcli does. Field evidence: none yet. No mxcli binary is reachable from the authoring session; the first count on a real project is owed before this leaves draft, per the backlog's own rule. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
test-stock-hashes.sh T2 demanded a STOCK-HASHES.txt entry per version for every file in MXTK_LINT_RULES. mxcli init seeds only three of those; the toolkit-authored ux001/ux002 rules can never have a stock hash, so the fixture went red on every version (3 FAIL) the moment they joined the list. install-manifest.sh gains MXTK_LINT_RULES_STOCK (the three init-seeded rules). The fixture's coverage, listed-name and live-capture checks walk that set, and a new check asserts it is a subset of MXTK_LINT_RULES. Replayed T2's awk against the real list: all three versions cover all three stock rules; a listed non-stock name still fails. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
# Conflicts: # CHANGELOG.md # bin/lib/install-manifest.sh
…e manifest Case 1 asserted a literal 4 files in .claude/lint-rules/ after a fresh install. Two toolkit-authored rules joined MXTK_LINT_RULES, six landed, and the fixture reported them as a NOINSTALL leak. The expected count is now the size of MXTK_LINT_RULES + MXTK_LINT_RULES_CONFIGURABLE, with an explicit check that no MXTK_LINT_RULES_NOINSTALL file was installed. CI's own output on 40f2c00 listed exactly the six manifest rules. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
# Conflicts: # CHANGELOG.md
Case 10 ("caller forgot the manifest") still compared against a literal 6
after case 1 was switched to the manifest-derived count in 53c4a36. On this
branch two more managed rules land, so the literal went red in CI while the
install itself was correct.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
5 tasks done
…ulary defects First run of the pair with mxcli 0.26.0 against a scratch copy of a 21-module Mendix 11.12 app (876 microflows, 124 pages): UX001 fired 0 times and UX002's decision leg 0 times across 728 decisions. A catalog probe explained both: - the stored microflow-button action type is Forms$MicroflowAction, not the Forms$MicroflowClientAction read from the source, so UX001 legs 2-3 could never fire for a microflow button. FLOW_CALLS now lists both spellings. - auto_generate_caption is 0 on every ExclusiveSplit; a bare decision carries its condition expression as its caption. UX002 now flags a caption that is empty or equals condition_expression (39 of 39 custom decisions on that model; marketplace decisions carry real questions). Fixtures carry the probed action-type name; new case q pins the caption==condition shape. tests/lint-rules/test-ux-rules.sh: 36/36. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
mxcli 0.26.0 against a scratch copy of a 21-module Mendix 11.12 app (876 microflows): ERR001 8 findings (3 true, 5 debatable), LOOP001 4 (4 true), all on the app's own modules, no load errors. No false positives; rule text unchanged, warning severity kept. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
MendixMau
marked this pull request as ready for review
October 12, 2026 03:13
# Conflicts: # .github/workflows/checks.yml # CHANGELOG.md # bin/lib/install-manifest.sh # lint-rules/README.md # tests/lint-rules/starrun/main.go # tests/test-lint-delivery.sh
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.
Stacked on #238— #238 is merged (f98eff0); base retargeted tomasterand master merged in (97badd6). The diff against master is now Batch 1 only.What changed and why
Batch 1 of the lint backlog: the two activity-based candidates whose fields are confirmed in the mxcli 0.25.0 source.
Continue/Custom/CustomWithoutRollBackin a flow where nothing logs (LogMessageAction), raises (ErrorEvent) or calls a handler-named flow (SUB_LogError,ERR_*,*_HandleError) — the "Continue and pray" patternRollback,Abort, unset; System/Administration; RULE flowsERR001 is the complement of mxcli's CONV013/CONV014 (which check that handling is set); LOOP001 is the rest of CONV011's list (commit-in-loop).
Both read
error_handling_type/loop_depth/retrieve_sourcethroughgetattrand emit a_ruleblindness finding on an older binary, an empty column, or loops with no indexed bodies. Vocabulary is from the mxcli source (sdk/microflows/error_handling.go:CustomWithoutRollBackwith a capital B; catalog builder:retrieve_source∈database/association).Delivery: added to
MXTK_LINT_RULESin the install manifest, README rows, CHANGELOG line. The starrun harness gainsactivities_for(nested=)mirroring the 0.25.0 builtin (default call hides loop bodies, as mxcli does).Field evidence (2026-10-12, mxcli 0.26.0, scratch copy of a 21-module Mendix 11.12 app — 876 microflows, 55 rules loaded, no load errors, 1.7 s)
on error continue, nothing logged, raised or handled; one silently drops a callee's gate failure). 5 debatable: 4 REST wrappers and 1 button flow return an error payload or empty result as their signal, log nothing, and carry an annotation saying the handling is deliberate, which the rule does not read. 0 false.Neither rule emitted a
_rulefinding; no findings on marketplace or System modules. Vocabulary (RetrieveAction,RestCallAction,MicroflowCallAction,Continue) confirmed by the messages themselves. Open question for after the second project: should an annotation, or an explicit error-payload return from the failure branch, count as handling? Until then the rule text stands at warning severity (rollout rule inprocess/lint-backlog.md).Checklist
tests/lint-rules/test-batch1-rules.sh— 29 cases under the real Starlark interpreter incl. the 3000-flow perf run; wired into CI_rulefindings for missing field, empty column, no loop bodies, no activities)check-portability,check-scripts, leak guard,check-pr-disciplineclean on the merged head🤖 Generated with Claude Code
https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw