Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
8b11d04
fix(describe): DESCRIBE FRAGMENT FROM PAGE/SNIPPET found no widget, ever
ako Sep 26, 2026
9436742
fix(search): warn when the source index was never built
ako Sep 26, 2026
a7c2377
fix(structure): show microflow and nanoflow counts at depth 1
ako Sep 26, 2026
11ff6f2
fix(catalog): reference edges to attributes, enumerations, workflows …
ako Sep 26, 2026
493932f
fix(refs): one row per reference, impact counts elements, and an empt…
ako Sep 26, 2026
fd677e3
fix(context): related entities come from associations, and callers ar…
ako Sep 26, 2026
6096300
fix(describe): trim a stored expression's outer whitespace when rende…
ako Sep 26, 2026
b70bcdb
test(refs): MDL repro for the reference-graph gaps, and findings
ako Sep 26, 2026
8db1dce
fix(cli): keep --json stdout pure across the query commands
ako Sep 26, 2026
a37ccdf
docs(findings): record the --json purity recurrence
ako Sep 26, 2026
3dfa674
Merge remote-tracking branch 'origin/main' into chain-715
ako Sep 27, 2026
1e3e130
Merge branch 'chain-715' into chain-716
ako Sep 27, 2026
ba06295
Merge branch 'chain-716' into chain-717
ako Sep 27, 2026
796ab8f
Merge branch 'chain-717' into chain-718
ako Sep 27, 2026
35bc2a4
roundtrip: strike putget for SUB_Feedback_PostToAppInsights, fixed by…
ako Sep 27, 2026
e51bb12
Merge branch 'chain-718' into chain-720
ako Sep 27, 2026
f679b3e
Merge branch 'chain-720' into chain-719
ako Sep 27, 2026
034185f
merge: drop the diagnostics() helper duplicated by #716 and #719
ako Sep 27, 2026
af0dbb2
test: #720 made the no-references message more specific; match its pr…
ako Sep 27, 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
1 change: 1 addition & 0 deletions .claude/skills/fix-issue/findings/cmd-mxcli.jsonl
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,4 @@
{"area": "cmd/mxcli", "date": "2026-09-25", "symptom": "Shipped Starlark rules CONV009, CONV010, QUAL001, QUAL003, QUAL004 and CUSTOM002 report nanoflows and rules as microflows: \"Microflow 'NF_Foo' has 30 activities\", and documentType \"Microflow\" in the JSON and report output.", "cause": "microflows() yields all three flow flavours (one catalog table, MicroflowType MICROFLOW/NANOFLOW/RULE), and each rule hardcoded document_type=\"Microflow\" and a \"Microflow '...'\" message. The Go rules had already been fixed with Microflow.DocumentNoun() after MPR002 called a rule a microflow, but that method was never exposed to Starlark, so every Starlark rule had to re-derive it and none did.", "file": "mdl/linter/starlark.go, .claude/lint-rules/{conv009_max_microflow_objects,conv010_act_microflow_content,example_microflow,long_microflows,mccabe_complexity,orphaned_elements}.star, mdl/linter/starlark_flow_noun_test.go", "insight": "When a Go-side fix lives in a method, check whether the Starlark projection can reach it; a fix Starlark cannot call is a fix for half the rules. Exposed as document_noun / document_noun_title on the microflow struct, and the test runs every shipped rule over a fixture with one flow per flavour, requiring a finding on each (else vacuous) plus a guard that any new `for x in microflows()` rule joins the list. Skip the wrong turn of excluding nanoflows/rules from QUAL004: rule calls from decisions ARE emitted as 'call' refs (builder_references.go collectRuleCalls), so only the label was wrong.", "refs": "mendixlabs/mxcli#1178"}
{"area": "cmd/mxcli", "date": "2026-09-25", "symptom": "Starlark rule API docs name microflow_type values the linter never returns: the write-lint-rules skill said \"microflow\"/\"nanoflow\", example_microflow.star (copied into every project by mxcli init) said \"Microflow\"/\"Nanoflow\", only mccabe_complexity.star had \"MICROFLOW\"/\"NANOFLOW\", and none listed \"RULE\". The skill's entity table also omitted has_created_date/has_changed_date/has_owner/has_changed_by.", "cause": "LintContext.Microflows() passes the catalog's MicroflowType through raw (MICROFLOW/NANOFLOW/RULE) while Entities() CASE-normalizes EntityType to TitleCase, so the two adjacent iterators have opposite conventions and each doc author guessed. Nothing tied the documented literals to what the API emits, so two passes over the same skill file (59db6e7b, #1165) fixed instances and left this one.", "file": ".claude/skills/mendix/write-lint-rules/SKILL.md, .claude/lint-rules/example_microflow.star, .claude/lint-rules/mccabe_complexity.star, mdl/linter/starlark_documented_values_test.go", "insight": "Fix the class, not the row: observe the emitted field names and enum values by running a Starlark rule (dir(e), e.entity_type) over a fixture holding every stored kind, then assert the skill tables, the shipped rules' `# .field - ...` headers, and every `.entity_type/.microflow_type ==` comparison in shipped rules against that observed set. Equality, not subset, for the docs -- an undocumented value (RULE) is a flavour a rule silently mistreats. Normalizing MicroflowType instead would have broken every user rule already comparing \"MICROFLOW\" correctly.", "refs": "mendixlabs/mxcli#1178, mendixlabs/mxcli#1164"}
{"area": "cmd/mxcli", "date": "2026-09-26", "symptom": "The write-lint-rules skill, which Starlark rules are written from, omitted seven query functions (java_actions, documents, documentable_elements, navigation_targets, queues, module_cycles, database_connections) plus get_option() and struct(), and fields on scheduled_event (repeat, on_overlap, time_zone) and project_security (anonymous_user_role). Four of the missing functions are used by shipped rules.", "cause": "Each builtin and field was added in code with its own PR and a docs-site paragraph at most; nothing compared the skill to buildPredeclared() or to the struct keys, so every API addition drifted from the skill by default. #1178's test pinned only the entity and microflow tables.", "file": ".claude/skills/mendix/write-lint-rules/SKILL.md, mdl/linter/starlark_skill_coverage_test.go", "insight": "Cover the whole surface at once rather than the table that was reported: an internal test ranges over (&StarlarkRule{}).buildPredeclared() for builtins and go/ast-parses every starlarkstruct.FromStringDict(starlark.String(name), dict) call in the package for struct fields (literal dicts and locally-built ones like ppDict), then requires each struct's skill table to match exactly. Structs documented elsewhere are named in explicit maps (helper params, inline struct{...} in a function row, shared permission table) so an exemption is a visible decision. The quick one-off Python diff over-reported (nested password_policy, permissions_for's entity_name) -- the test encodes those layouts instead of guessing.", "refs": "mendixlabs/mxcli#1178"}
{"area": "cmd/mxcli", "date": "2026-09-26", "symptom": "`--json` output did not parse. `mxcli refs|callers|callees|impact|structure|show|search … --json` and `mxcli -c \"select … from CATALOG.x\" --json` printed \"Connected to:\", catalog load/build progress (`✓ Table: N`, 40+ lines on a cold cache), a \"References to X\" header and a \"Found N\" count ahead of the array; an empty answer was the sentence \"(no references found)\" / \"(no results)\" instead of []; `context` ignored --json and printed markdown; `check --format json` wrote its document to STDERR (one per phase), leaving only executor chatter on stdout; `show widgets|data transformers|import/export mappings|catalog status` had no JSON path for empty or at all; `diff --json` silently printed a text diff. Found by an agent-orientation audit on a 140MB app (Evora Factory Management)", "cause": "The executor has ONE writer, ctx.Output, and it carries both the payload and every status line. The #904 fix (progressSink) only works when the payload is written by the COMMAND (lint/report format their own result to os.Stdout, so the executor's writer can be pointed at stderr); for every query subcommand the payload is written by the executor itself, through the same ctx.Output as the chatter, so no choice of writer at the cmd layer can separate them. The split has to be inside the executor, per line, by what the line is", "file": "`mdl/executor/exec_context.go` (`Diagnostics` field + `diagnostics()`, identical to ako/mxcli#716, plus `progress()`: Output in text mode, diagnostics() in JSON mode), `mdl/executor/format.go` (`writeEmptyResult`), `mdl/executor/cmd_catalog.go` (connect/load/build/warn/count lines, `writeCatalogStatusJSON`), `mdl/executor/cmd_search.go`, `cmd_context.go`, `cmd_widgets.go`, `executor_connect.go`, `reference_target.go`; `cmd/mxcli/cmd_check.go` (one structured document on stdout via `finish`), `cmd/mxcli/cmd_query.go` (search: `--json` canonical, `--format json` deprecated alias sets the executor format), `cmd/mxcli/output_stream.go` (`refuseJSONFlag`, used by diff/diff-local); tests `cmd/mxcli/json_output_purity_test.go`, `mdl/executor/progress_stream_test.go`", "insight": "**Classify each line by what it IS, not where it is printed**: an answer goes to Output, commentary about the run goes to `ctx.progress()`. Text mode is byte-for-byte unchanged because progress() IS Output there — assert that too (`TestTextModeKeepsProgressOnStdout`), or the next fix 'cleans' interactive output by sending it all to stderr. **The empty case is where JSON contracts break**: every handler that early-returns a sentence on zero rows must go through writeEmptyResult (or the existing `&& ctx.Format != FormatJSON` idiom) — the sweep found 8 such sites and most list handlers already had the idiom, so grep for the ones that do not. **--json is a ROOT persistent flag**, so every subcommand accepts it; a command with no JSON output must refuse it (stderr, exit 2), since ignoring it hands text to a parser. **Test in a child process** (reuse TestRunMainHelper): stdout and stderr are then genuinely separate, error paths ending in os.Exit are observable, and no cobra flag state leaks between table rows. Proof: forcing progress() to return Output fails 18/18 --json rows, the search alias and the error test; reverting cmd_check.go fails all five check rows. Left alone: the 10,000-line output guard counts pretty-printed JSON lines, so `show widgets --json` on Evora emits the complete document and then exits 1 'output line limit exceeded'", "refs": ["#904", "ako/mxcli#716"]}
Loading
Loading