Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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.md
Original file line number Diff line number Diff line change
Expand Up @@ -473,3 +473,4 @@ extracting `OffsetExpression`/`LimitExpression`.
| An association's line anchors — where the connector attaches to the entity boxes in the domain model editor — are absent from `DESCRIBE ASSOCIATION`, and manual adjustments made in Studio Pro do not survive an mxcli round trip | `DomainModels$Association.ParentConnection`/`ChildConnection` (the string `"x;y"`) were **hardcoded** to `"0;50"`/`"100;50"` in BOTH writers and never read by either parser. Because every association write rebuilds the whole element, this was not an omission but active destruction: a documentation-only `alter association … set comment` reset them | `sdk/domainmodel/connection.go` (new: `ParseConnectionPoint`/`FormatConnectionPoint`, `Default*Connection`), `sdk/domainmodel/domainmodel.go` (fields → `*model.Point`), `sdk/mpr/parser_domainmodel.go` + `sdk/mpr/writer_domainmodel.go`, `mdl/backend/modelsdk/domainmodel.go` + `domainmodel_write.go`, `mdl/executor/cmd_associations.go` (`describeConnectionPoints`) | **A feature request that says "X is not exposed" may be hiding "X is destroyed"** — check the write path before scoping the read path. The A/B that settled it: a blank 11.13 app's own `Administration.AccountPasswordData_Account` stores `0;54/100;54`, so a Studio-Pro-authored association is a free fixture for "did mxcli overwrite this?" — no Studio Pro needed. **Learn the value's constraints from the LOADER, not from the shape**: hand-patch and run `mx check` — `"0.5;50"` dies with `StorageLoadException` (integers required) while `"0;500"` and `"-20;50"` load with 0 errors (no range check), so out-of-range values must round-trip untouched. **A zero value is not an absent value** — `{0,0}` is a real anchor (top-left), which forces the field to be a POINTER; a plain `model.Point` cannot distinguish "unset" from "top-left" and would silently rewrite it. **Fix both engines**: they share the semantic model, and a fix in one is invisible to a user on the other. **Emit unauthorable data as a COMMENT** — DESCRIBE output must stay re-executable, and inventing syntax (`@anchor(parent: bottom-left, …)`) would bake in a vocabulary the storage does not have: the pair is CONTINUOUS, not 8 named anchors (observed x values 0 9 11 17 18 47 49 50 65 77 78 84 87 100). **The marketplace is the sample** when you need to know what Studio Pro actually writes: `mxcli marketplace download <id>` gives real Mendix-authored models, and a module .mpk holds either a raw BSON `project.mpr` or an MPR v1 SQLite one — 88 coordinate pairs from three modules turned "looks like percentages" into a measurement (all 0..100; 85 of 88 pin one coordinate to exactly 0 or 100). **Rule a unit out from the model, not the values**: pixels is impossible because `DomainModels$EntityImpl` stores only `Location` and NO size — the box is sized by the editor from the name and attribute list, so a pixel anchor would have nothing to measure against. Not applicable to `CrossAssociation`, which has no connection properties and crashes Studio Pro if given them (#50). Tests `sdk/domainmodel/connection_test.go`, `mdl/backend/modelsdk/association_connection_test.go`, `sdk/mpr/writer_domainmodel_test.go`, example `mdl-examples/bug-tests/872-association-line-anchors.mdl`. upstream #872 |
| An association's line anchors can be preserved but not AUTHORED — a scripted domain model cannot lay out its own connector lines, so `@Position(x, y)` gets you boxes and nothing gets you the lines between them | Feature gap, not a defect. `DomainModels$Association.ParentConnection`/`ChildConnection` had no MDL surface | `mdl/grammar/domains/MDLDomainModel.g4` (`SET ANCHOR`/`anchorPoint` — the ONLY grammar change), `mdl/visitor/visitor_association.go` (`anchorAnnotation`, `annotationParenPoint`, `anchorCoord`), `mdl/ast/ast_association.go` (`FromAnchor`/`ToAnchor` on both create and alter), `mdl/executor/cmd_associations.go` (`applyAnchors`, `describeConnectionPoints`) | **Look for an existing annotation before inventing one** — `@anchor(from:, to:)` already existed for microflow sequence flows, asking the same question (where does the connector attach), and `annotationParamName` already admitted FROM and TO, and `(x, y)` was already `annotationParenValue`: CREATE needed **zero** grammar. The two forms cannot be confused because the microflow one names its inner params (`(from: right, to: left)`) while a coordinate pair is positional. **Let the storage pick the value type**: the measured pair is continuous (x takes 14 distinct values across 88 samples), so named anchors were never an option — see the preservation row above for how that was established. **Silence must mean "preserve", not "default"** — naming one end sets it and omitting one keeps what is stored, which is what stops a `create or modify association` about the delete behaviour from flattening a hand-tuned line; the AST carries POINTERS so "not mentioned" and "mentioned as (0, 0)" stay distinguishable. **Reject what the LOADER rejects, at check time**: a fractional coordinate must error, not be truncated to 0 — Mendix refuses to open such a project, and a silently-wrong value in a file that still loads is the worse failure. **Prove DESCRIBE round-trips by parsing its own output** — asserting on a string literal passes against a formatter emitting something nothing can read. Tests `mdl/visitor/visitor_association_anchor_test.go`, `mdl/executor/cmd_associations_anchor_test.go`, example `mdl-examples/bug-tests/872-association-line-anchors.mdl`. upstream #872 |
| `ALTER PAGE` over `--mcp` fails against Studio Pro **11.13** with `pg_patch_page: … PROP_NOT_PRIMITIVE: Property 'widgets' is not a primitive property`. `CREATE PAGE` is fine; the page itself is left intact | 11.13 gave `pg_read_page` a **`depth` argument defaulting to 4**, replacing anything deeper with the literal string `"..."`. ALTER PAGE is read-modify-**replace-whole-page**, so the truncated read went straight back as the new page body. Measured live: `Administration.Account_Overview` read 32,594 bytes at full depth but **1,052 bytes** at the default, its entire tree reduced to `{"widgets":["...","..."]}`. Every ordinary page truncates — three of three PgTest pages did | `mdl/backend/mcp/page.go` (`pgReadPage`, `pgReadFullDepth`, `hasTruncationSentinel`), `mdl/backend/mcp/client.go` (`SupportsToolArg`) | Request the full depth, and **guard rather than trust it**: refuse a read still carrying the sentinel instead of letting a partial page reach a write (ADR-0005 guard-don't-drop). Two traps. (1) **Do not send `depth` unconditionally** — 11.11/11.12 declare `pg_read_page` `additionalProperties:false` without it, so the whole call fails; gate on a live `tools/list` probe of the tool's input schema, because `serverInfo.version` is frozen at `1.0.0` across 11.11/11.12/11.13 and cannot discriminate releases. (2) **Match the sentinel only as an array element** — a caption or title legitimately reading `"..."` is real content, and a naive substring scan rejects valid pages. The release notes announced none of this, exactly as 11.12 silently removed `pg_write_page` (#697): on any Studio Pro upgrade, re-probe `tools/list` and diff the input schemas, not just the tool names. Tests `mdl/backend/mcp/page_depth_test.go`; controls: stub the depth arg (full-depth test fails) and stub the guard (truncation test fails) |
| `mxcli run --ensure-db` fails to start PostgreSQL when no service manager becomes ready (e.g. Arch): `exec: "pg_ctlcluster": executable file not found in $PATH`, though `initdb`/`pg_ctl`/`psql` are present | `startLocalPostgres` only knew the `service`/`pg_ctlcluster` helpers (the latter a placeholder that could never run), and role/database provisioning assumed `sudo -u postgres`, which a user-owned cluster does not need | `cmd/mxcli/docker/ensuredb.go` (`startLocalPostgres`, `startUserCluster`, `resolveSuperuser`) | Fall back to a user-owned `initdb`/`pg_ctl` cluster under `~/.mxcli/postgres`, but never initialize a competitor when the requested TCP port is already owned by a service-started server that is still recovering. Enforce the passwordless-superuser boundary instead of assuming it: explicitly tighten an existing socket directory to `0700`, set the socket itself to `0700`, and persist `listen_addresses`/`port`/`unix_socket_directories` in `postgresql.conf` so a plain later `pg_ctl start` stays safe. Refuse, with a cleanup path, a cluster made by the earlier development revision if its host authentication is still `trust`. Reuse a running cluster only when both the port and socket directory in `postmaster.pid` match. Keep `sudo -u postgres` for system clusters. Tests stub every external tool and exercise slow service startup, legacy-cluster refusal, permissions, persisted settings, and repeated/running cases. Issue #823 |
10 changes: 8 additions & 2 deletions .claude/skills/mendix/run-local.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,14 @@ association catalog only at startup; behavioural changes are hot-reloaded.
- A **PostgreSQL** database (defaults: `127.0.0.1:5432`, user `mendix`, db derived
from the project name; override with `--db-host/--db-name/--db-user/--db-password`).
- **`--ensure-db`** provisions it for a fresh session: starts local Postgres if the
port is down and creates the role + database if missing (local superuser via
`sudo -u postgres`). Remote hosts are only checked, not provisioned.
port is down and creates the role + database if missing. It uses a service
manager, or a user-owned `initdb`/`pg_ctl` cluster under `~/.mxcli/postgres`
when no service becomes ready (e.g. Arch) — needing no `postgres` OS account or `sudo`.
Remote hosts are only checked, not provisioned.
The user-owned cluster persists across sessions; its server log is
`~/.mxcli/postgres/server.log`. Stop it with
`pg_ctl -D "$HOME/.mxcli/postgres/data" stop`. To remove it, stop it first and
then delete `~/.mxcli/postgres` (this permanently deletes its databases).
- Without `--ensure-db`, create it once and the command errors if it's unreachable:

```bash
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ Headline: **A full Mendix build-and-test loop that fits on an iPad** — you can
- **`run --local` robustness** — the web client bundle is verified after boot, not before; stale ports are refused and the holding process is named; a relative project path resolves where MxBuild is called; the browser bundle is re-served after a structural `--watch` change; boot uses live-preview flags so `mxcli oql` can reach the app; the hub tunnel retries forever and re-registers on a heartbeat 404.
- **Theme** — `mxcli theme remove` with no name now reads the installed theme from the `mxcli:theme` markers instead of removing the built-in default and reporting a silent no-op; switching themes no longer orphans the previous theme's block in `_mxcli-atlas-map.scss`; the topbar language selector, filter-operator popovers, login page, and Data Grid 2 now follow the palette (the language selector went from 1.13:1 to 17.79:1 / 19.47:1 measured contrast).
- **JavaScript action sources were written to the wrong directory** — `CREATE JAVASCRIPT ACTION` wrote to `javascriptsource/<ModuleName>/actions/`, but Mendix reads a **lowercased** module directory. MxBuild found nothing there, generated a stub whose body throws `JavaScript action was not implemented`, and bundled that — so the action parsed, passed `mxcli check`, built cleanly, and threw the moment it ran. Only reproduced on a case-sensitive filesystem, which is why it went unnoticed on macOS and Windows.
- **`mxcli run --ensure-db` can start PostgreSQL without a working service manager (#823)** — on hosts that ship neither `service` nor Debian's `pg_ctlcluster` (e.g. Arch Linux), `--ensure-db` failed with `exec: "pg_ctlcluster": executable file not found in $PATH` even though the portable `initdb`/`pg_ctl`/`psql` tools were present. `startLocalPostgres` now falls back to a user-owned cluster under `~/.mxcli/postgres` when no service becomes ready, but never starts a competitor while another process owns the requested port. The cluster is idempotent and needs neither a `postgres` OS account nor passwordless `sudo`: its listen address, port, private socket directory, and `0700` socket permissions persist in PostgreSQL's own configuration; loopback TCP uses SCRAM while role/database provisioning uses local trust only through that private socket. Anyone who ran an earlier development revision of this fix must stop PostgreSQL, remove `~/.mxcli/postgres`, and rerun `--ensure-db`; reuse detects and refuses its insecure host-trust records. The existing `sudo -u postgres psql` path remains for system clusters.
- **Widget sync wrote duplicate GUIDs and corrupted the project** — reconciliation now removes stale properties and syncs attributes via `AugmentTemplate` so the widget `Type` is exact.

## [0.16.0] - 2026-07-12
Expand Down
Loading
Loading