Skip to content

Sync mendixlabs/mxcli - #877

Closed
ako wants to merge 13 commits into
mendixlabs:mainfrom
ako:main
Closed

Sync mendixlabs/mxcli#877
ako wants to merge 13 commits into
mendixlabs:mainfrom
ako:main

Conversation

@ako

@ako ako commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

No description provided.

claude and others added 13 commits August 11, 2026 19:38
…ut-dir works

`mxcli new` pointed `mx create-project` straight at the output directory.
MxToolset refuses any full destination path over 259 characters — its own
Windows-compatibility limit, not the filesystem's — and aborts extraction PART
WAY THROUGH when it hits that, so a deep output directory was left holding a few
hundred files and no .mpr: output that looks like a project until you open it.

Bisecting the output-directory length on mxbuild 11.13.0 pins the rule exactly:

  77 characters -> project created, .mpr present
  78 characters -> PathTooLongException, 259 files left behind, no .mpr

The blank template's longest relative path is 181 characters there, and
77 + 1 + 181 = 259. The reporter measured 182 on 11.12.0 and saw 258 files, so
the constant drifts a character per release.

Rather than validate a path we can avoid, create the project in a short staging
directory and move it into place. Two things follow:

  * A deep destination WORKS — the limit is MxToolset's, and POSIX allows 4096.
    Relocation is safe because a fresh project embeds no absolute paths: grepping
    a blank 11.13 project for its own directory matches zero files.
  * The destination is never partially populated. Nothing is written there until
    creation has already succeeded, so a failure leaves the user's directory
    exactly as it was.

The template's longest path is measured from the staged tree rather than
hardcoded, and used for a warning — not a refusal — when the finished project
exceeds 259: it works here, but Studio Pro on Windows may not open it, and
refusing would block a machine where it is fine. The warning carries both
numbers and the budget, so nobody has to derive the limit themselves the way the
reporter did.

Verified against mxbuild 11.13.0 at the length that used to fail:

  build     exit  result
  pre-fix   1     PathTooLongException, 259 orphaned files, 0 .mpr
  fixed     0     project created, warning emitted, `mx check` 0 errors

Cross-device staging falls back to os.CopyFS, which os.Rename cannot do.

Fixes mendixlabs#825
Every push to main on this fork left a red X on "Deploy Documentation":

    Failed to create deployment (status: 404) ... Ensure GitHub Pages has
    been enabled: https://github.com/ako/mxcli/settings/pages

A fork inherits the workflow but not the upstream Pages configuration, so
actions/deploy-pages 404s on something unrelated to the change being
pushed. The API confirms both halves for this repo: fork=true and
has_pages=false. It has failed on all three runs since the fork was
active, while Build/Test/Lint is 23/23 green — a permanently red workflow
is how a real failure gets missed.

The upload and deploy steps are now gated on the repository not being a
fork, with an opt-out for a fork that does want to publish its own copy
(enable Pages, then set the repository variable DEPLOY_DOCS=true).

The book is still BUILT everywhere — on forks and on pull requests, as
before — so a docs change is still proven to compile wherever it is
pushed. Only publishing is skipped, and a skipped job does not fail the
run.

Nothing changes upstream: mendixlabs/mxcli is not a fork, so the condition
is true there exactly as it is today. This is worth sending upstream on its
own merits, since any fork of the repo currently hits the same 404.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LUToAkUx54bNkNjsBpufRH
…ow callers` hiding them

`show callers` and `show references` missed anything reached only from a page
action button, reporting "(no callers found)" — a false negative that reads as
"safe to delete".

Two independent defects behind one symptom, and fixing either alone closes half
the issue.

1. The page reference was never recorded. scanWidgetOwnRefs collects a widget's
   Entity, Microflow and Nanoflow out of raw BSON but not `Form`, which is where
   a PAGE reference lives — "Form" being Mendix's original word for a page, the
   same rename behind ShowFormAction/CloseFormAction. So widgets_data had no page
   column and the refs projection had no page row. `create object … then open
   page` is one action carrying TWO references, and only the entity survived.

2. The microflow reference was recorded and then hidden by the query.
   execShowCallers filtered RefKind = 'call', the kind a microflow CALL ACTIVITY
   produces; a button's microflow is 'action', and that row was sitting in the
   refs table all along.

widgets_data gains a PageRef column, the projection a PAGE/show_page row, and
`show callers` an explicit set of invocation kinds — call, action, show_page,
calculate, and the three navigation kinds.

`show callers` stays narrower than `show references to`: datasource, parameter,
return, retrieve, create, change, delete, associate, generalize and layout are
uses of a TYPE or a LAYOUT, not invocations, and folding them in would make the
two commands synonyms. Both the included and the excluded set are pinned by test.

Verified on a project reproducing the reporter's two scenarios:

  before: (no callers found) for both the button-called microflow and the
          button-opened page
  after:  the page is a caller of its button's microflow; the overview page is a
          caller of the page its "create object … then open page" button opens;
          transitive finds the overview at depth 2

The microflow→microflow control still resolves, and `show callers of <entity>`
is still empty while `show references to <entity>` shows the datasource use.

Fixes mendixlabs#773
ci(docs): only publish Pages where a Pages site exists
fix: deep --output-dir for mxcli new (mendixlabs#825), and reference indexing for page action buttons (mendixlabs#773)
…dropped them

A microflow call bound to a task queue in Studio Pro lost that binding on
`create or replace microflow` — silently. Worse, `mx check` went from

  [CE1613] "The selected task queue 'X' no longer exists."

to 0 errors, because mxcli had deleted the configuration the error was about.
`describe microflow` never showed the binding either, so the loss was invisible
from every angle: the write reported success, the describe looked complete, and
the build looked healthier than before.

Two defects behind one report, fixed here:

1. MDL had no queue surface at all, so a script could not restate a binding even
   in principle. CREATE [OR MODIFY] / DROP / SHOW / DESCRIBE QUEUE now exist,
   wired through grammar → AST → visitor → executor → backend on both engines.

   The BSON is pinned against the four Studio Pro-authored queues in Mendix
   Business Events 3.12.1, which agree exactly: Config is a
   Queues$BasicQueueConfig whose ParallelismExpression is a STRING, with the
   sibling int32 `Parallelism` absent in all four. Parallelism is therefore an
   expression everywhere in MDL, not a number.

2. Rewriting a microflow whose stored calls are queued is now refused, naming
   the queues that would be lost. Binding a call to a queue is deliberately
   still unimplemented — the Retry shape has no Studio Pro-authored sample to
   diff against, and guessing it would put a second unverified shape into user
   projects. Refusing is the only option that does not lose data (ADR-0005).

QUEUE/QUEUES are added to the `keyword` rule, so `queue` remains usable as an
ordinary attribute name.

Verified on Mendix 11.13: the example script leaves a clean project at 0 errors
under both engines, and describe → exec round-trips. The guard's test fails (the
rewrite runs, the binding goes) when its call site is disabled.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LUToAkUx54bNkNjsBpufRH
…at it stores

Scheduled events were read-only: ScheduledEventBackend had List/Get and nothing
else, and there was no MDL surface at all. A project's cron had to be added in
Studio Pro even though everything around it could be scripted.

CREATE [OR MODIFY] / DROP / SHOW / DESCRIBE SCHEDULED EVENT now exist, wired
through grammar → AST → visitor → executor → backend on both engines.

The repeat rule is stored as one of eight ScheduledEvents$*Schedule types that
differ in WHICH fields they carry, not just in their values. MDL mirrors that:
`Repeat: Daily` names the variant and then only that variant's fields are
accepted — a Multiplier on a Daily repeat is refused, by `mxcli check`
(MDL-SCHED01) and by exec, which call the same function so they cannot drift.
Merging the field sets is what produces a document mxbuild accepts and Studio
Pro cannot open.

The read was lossy in both engines and is fixed here too. The legacy parser
never looked at Schedule at all, and the modelsdk reader went through
modelsdk/gen, whose generated types disagree with what Studio Pro writes on two
properties: every integer is stored as int64 where gen declares int32, and
StartDateTime is a BSON datetime where gen declares a string. Both engines now
share one codec (mdl/scheduledevents), pinned by re-serializing three whole
Studio Pro-authored documents — from Workflow Commons 4.11.0, OIDC SSO 4.6.0 and
SAML 4.2.1 — element by element, in order, with matching BSON types.

Those four references cover the Daily and Hourly variants; the other six are
derived from the metamodel and verified to load with 0 errors from `mx check`.

Interval/IntervalType are legacy siblings of Schedule that Studio Pro writes and
does not keep in sync (one shipped module stores 0/"Minute" beside a daily
schedule of 01:00). MDL has no syntax for them: a new event gets the pair
matching its repeat — an empty IntervalType is not valid, the enumeration has no
such member — and OR MODIFY carries the stored pair through untouched.

Verified on Mendix 11.13 under both engines: all eight variants leave a clean
project at 0 errors, DESCRIBE output re-parses and re-validates for every
variant, and a re-run writes nothing (the MXCLI_ALWAYS_WRITE=1 control changes 9
units where the normal run changes 0).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LUToAkUx54bNkNjsBpufRH
… help surface

The two features were implemented but only half-discoverable. Filling the gaps
the CLAUDE.md checklist calls for:

- `mxcli describe` did not know either type. Both are now in the type list, the
  dispatch, the error message, and the live-reader auto-detect map — so
  `mxcli describe -p app.mpr Ops.NightlyCleanup` resolves without naming a type,
  as it already does for every other document.
- `show structure` counted scheduled events but not queues, so a queue was
  invisible at every depth. Added to the depth-1 counts, the compact summary and
  the depth-2/3 listings, and to `project-tree` (which feeds the VS Code tree).
- New user-facing skill `.claude/skills/mendix/scheduled-events-and-queues.md`,
  indexed in the skills README and its LLM loading guide, so `mxcli init` ships
  it into user projects. It leads with the trap: pick the Repeat first, then use
  only that repeat's fields.
- CLAUDE.md: both features added to the implementation status, and the skill to
  the read-this-first list.
- VS Code extension: tree icons, terminal-link type inference, the describe
  fallback type list, and the context-menu viewItem pattern.

Already in place from the feature commits: `mxcli syntax queue` /
`mxcli syntax scheduled-event`, MDL_QUICK_REFERENCE, the docs-site page, the
symptom-table rows and the MDL examples.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LUToAkUx54bNkNjsBpufRH
…lling scheduled microflows dead

Neither document type was in the catalog, and the consequence was worse than a
missing table. A scheduled event produced no edge in the reference graph, so a
microflow run only by one was reported as unused from three directions at once:

  show callers of Ops.SE_Cleanup    -> (no callers found)
  CATALOG.GRAPH_DEAD_ASSETS         -> Ops.SE_Cleanup
  mxcli lint                        -> [QUAL004] Microflow 'SE_Cleanup' is not
                                       called from anywhere.
                                       -> Remove if unused

on a microflow that runs nightly. The table is an absence somebody notices; the
missing edge is a wrong answer three tools state confidently, one of which
recommends deleting the file.

Changes:

- CATALOG.SCHEDULED_EVENTS (microflow, repeat, a readable schedule phrase,
  interval, enabled, timezone, on-overlap) and CATALOG.QUEUES (parallelism as a
  string — Mendix stores an expression — and cluster-wide), both registered in
  Tables() so SHOW CATALOG TABLES lists them.
- A `schedule` edge from each event to its microflow, added to callerRefKinds,
  graphRefKinds and the QUAL004 rule — three consumers, none sharing the others'
  list.
- The linter's interval_seconds is now derived from the Schedule child instead of
  the stored Interval/IntervalType pair. Studio Pro writes that pair and does not
  keep it in sync (Workflow Commons ships 0/"Minute" beside a daily schedule), so
  a "fires too often" rule read a nightly job as every 0 seconds. Rules can now
  also branch on repeat / on_overlap / time_zone, and iterate queues().

Also fixes a regression from the queue feature: QUEUES became a lexer keyword, so
`select * from CATALOG.QUEUES` parsed to nothing — no error, no output — until
QUEUES was added to catalogTableName, the same trap COMMUNITIES hit before.

Both fixes have a control: reverting the interval derivation fails the schedule
tests, and removing the ref edge takes QUAL004 back from 1 to 2 on the test
project.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LUToAkUx54bNkNjsBpufRH
feat(queues): author task queues in MDL, and refuse the rewrite that dropped them
@ako ako closed this Aug 12, 2026
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