Lay domain-model entities out instead of stacking them in one row - #395
Conversation
A generated domain model opened in Studio Pro as a single horizontal line of entities with the boxes touching — unreadable at any zoom. Reported against a 40-entity model (ako/CapTrackV2, Mendix 11.13). The default position for a CREATE ENTITY with no @position was: location = model.Point{X: 100 + len(dm.Entities)*150, Y: 100} Same y for every entity ever created. 40 entities is a 6,950px row, and 150px is narrower than an entity box, so they overlapped as well. Two changes, because there are two different questions. **The default** (mdl/dmlayout.GridSlot) is now a wrapping grid. It cannot be better than that: the first entity of a script is placed before the last one exists, so no create-time rule can see the association graph. Slot n stays a function of n alone, so adding an entity never moves one already written. Those same 40 entities now span ~1,400px. **mxcli layout** does the real thing, from the whole model once it exists. Entities are layered on the association graph — an entity referencing nothing else in the module is a lookup and goes left, everything else one column past the furthest thing it references — so association lines mostly run one way instead of crossing the diagram. Entities with no association at all go in a band underneath rather than among the lookups, which is where the non-persistent helpers belong. Run against CapTrack's own 01-domain.mdl, the layering falls out of the model: six lookups in one column, then Team/GoalBucket, then PlanScope's band, out to EmployeeMonth/Movement. mx check 0 errors, and the positions round-trip into MDL as @position. It is opt-in and it overwrites hand-arranged positions in the modules it touches, so --dry-run lists the moves first. Marketplace modules and System are skipped, and NAMING one is an error rather than a silent skip — a silent skip reports success having done nothing. Three properties the tests pin, each measured rather than assumed: - idempotent: a second run detects nothing to move and never calls the writer (16 of 16 moved, then "already laid out"). - local: adding one entity with one association moved 3 of 17, not the model. A layout that reshuffled everything would make each domain-model commit an unreadable diff. - deterministic: an unsorted walk gives a different diagram every run, which rewrites the unit every time — the churn ADR-0008 exists to prevent. The control fails on run 0. Two constraints that shaped the geometry: an entity stores only Location and NO Size (Studio Pro derives the box when it draws), so spacing is estimated from name length and attribute count; and a Mendix position is the box's CENTRE, so placement adds half a box rather than none. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018hifgRSawfaRWXS44YKtSJ
The layout change landed with CLAUDE.md and the Cobra help updated and nothing
else. The three that were missed are the user-facing ones.
`mxcli syntax domain-model.entity.alter` did not document SET POSITION AT ALL —
a gap that predates this work — so the topic now lists it, says the coordinate
is the box's CENTRE rather than its top-left, and points at `mxcli layout` for
arranging a whole module.
The generate-domain-model skill was actively wrong:
IMPORTANT: All entities MUST have @position annotation
Without it, entities appear at (0,0) or random locations.
Neither half held. An entity without a position took the next slot in a
deterministic row — now a grid — and never (0,0). The "MUST" was advice nothing
enforced, and the model that prompted this work ignored it, which is part of how
it came out as a 6,000px line. The section now says positions are optional, that
a grid is a default rather than a layout, and that a generated domain model is
better served by writing none and running `mxcli layout` afterwards.
New docs-site page tools/domain-model-layout.md, linked from SUMMARY.md: what
the layering does, the measured column breakdown, the flags, the fact that it
replaces hand-placed positions, and the idempotence/locality properties that
make it safe to leave in a build script.
make check-skill-mdl passes (205 blocks).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018hifgRSawfaRWXS44YKtSJ
|
The job runs GitHub's Copilot autofix agent ( The real code scanning is unaffected: There is no fix to port — the failure is inside GitHub's own action, not in this repository — so I am standing down on it rather than re-running or working around it. I'll follow up on Generated by Claude Code |
A generated domain model opens in Studio Pro as a single horizontal line of entities with the boxes touching — unreadable at any zoom. Reported against a 40-entity model (ako/CapTrackV2, Mendix 11.13).
The default position for a
CREATE ENTITYwith no@Positionwas one line:Same
yfor every entity ever created. 40 entities is a 6,950px row — and 150px is narrower than an entity box, so they overlapped as well.Two changes, because there are two different questions.
The default: a wrapping grid
mdl/dmlayout.GridSlot. It cannot be much better than a grid, and that is the design point: the first entity of a script is placed before the last one exists, so no create-time rule can see the association graph. Slot n stays a function of n alone, so adding an entity never moves one already written. Those same 40 entities now span ~1,400px.mxcli layout: the real thing, from the whole modelEntities are layered on the association graph — an entity referencing nothing else in the module is a lookup and goes left, everything else one column past the furthest thing it references — so association lines mostly run one way instead of crossing the diagram. Entities with no association at all go in a band underneath rather than among the lookups, which is where the non-persistent helpers belong.
Run against CapTrack's own
01-domain.mdl, the layering falls out of the model with no hints:mx check0 errors, and the positions round-trip into MDL as@Position(1180, 157).It is opt-in and it overwrites hand-arranged positions in the modules it touches, so
--dry-runlists the moves first. Marketplace modules and System are skipped — and naming one is an error rather than a silent skip, because a silent skip reports success having done nothing.Three properties the tests pin, each measured
moved 16 of 16, thenalready laid out (16 entities).The controls also cover the old behaviour directly — restoring the single-row formula fails the wrap, width and overlap tests.
Two constraints that shaped the geometry
An entity stores only
Locationand noSize— Studio Pro derives the box when it draws, and mxcli never sees the result — so spacing is estimated from name length and attribute count, deliberately generous. And a Mendix position is the box's centre, not its top-left, so placement adds half a box.Not verified
I checked geometry,
mx check, the round-trip and idempotence, but I have not opened the result in Studio Pro. If the estimated box sizes are off for unusually wide entity names, boxes could still crowd — that is the one claim I cannot make from here.Validation
go test ./...clean,make vetclean,make check-mdlclean (422 examples),mx check0 errors on the laid-out CapTrack model,check-findings908 records OK.🤖 Generated with Claude Code
https://claude.ai/code/session_018hifgRSawfaRWXS44YKtSJ
Generated by Claude Code