Skip to content

Entity DDL safety: alter-path attribute checks + create-or-modify data-loss guard - #30

Merged
ako merged 2 commits into
mainfrom
fix/findings-entity-safety
Jul 25, 2026
Merged

Entity DDL safety: alter-path attribute checks + create-or-modify data-loss guard#30
ako merged 2 commits into
mainfrom
fix/findings-entity-safety

Conversation

@ako

@ako ako commented Jul 25, 2026

Copy link
Copy Markdown
Owner

Two sudoku-app findings, both about entity DDL that passes mxcli check cleanly but bites later in the build.

#6 — ALTER ENTITY ADD ATTRIBUTE skipped every per-attribute check

The reserved-name / AutoX-rename / autonumber-seed checks (MDL021/MDL022/MDL023) only ran on CREATE ENTITY. An attribute added later with alter entity M.E add attribute … escaped all of them — e.g. a seedless autonumber returned "Check passed!" and then failed the build with CE7247 "Value cannot be empty".

  • Extracted the CREATE per-attribute loop body into validateEntityAttribute(attr, persistent, entityName).
  • Added ValidateAlterEntity(stmt) that runs it on the ADD ATTRIBUTE path, wired into both mxcli check and the LSP diagnostics.
  • The entity's persistence kind isn't knowable from an ALTER statement, so the persistent-only MDL020 is skipped there; the kind-independent MDL021/022/023 all run.

#24create or modify entity silently drops omitted attributes

create or modify entity rebuilds the entity from the statement alone and replaces the stored one, so any attribute the statement omits is deleted with no warning (36→2 attributes seen in the sudoku app), later surfacing as CE1613 on widgets/microflows still bound to them. Worse, the "already exists" error that leads users here recommended the destructive create or modify for what is usually a partial edit.

Per the agreed approach this is warn-only, non-blocking (the user asked to modify):

  • Before UpdateEntity, diff existing vs. replacement members (droppedEntityMembers — named attributes case-insensitive, plus the four audit flags) and print exactly what is being removed, pointing at alter entity … add attribute for incremental edits.
  • Fixed the already-exists message to recommend alter entity for a member change and reserve create or modify for a full replace.

Tests & docs

  • Unit test for the ALTER-path validation (TestValidateAlterEntityAddAttribute), the drop-diff helper (TestDroppedEntityMembers), and a mock-backend integration test that the modify still applies while warning (TestCreateOrModifyEntity_WarnsOnDrop).
  • Bug-test examples: f6-autonumber-seed-alter.fail.mdl, f24-create-or-modify-dataloss.mdl.
  • Two new rows in the fix-issue.md symptom table.

🤖 Generated with Claude Code


Generated by Claude Code

claude added 2 commits July 25, 2026 19:25
…a-loss guard

Two sudoku-app findings, both about entity DDL that passes `mxcli check`
but bites later:

#6 (alter path): the per-attribute checks (MDL021 reserved words, MDL022
AutoX rename, MDL023 autonumber seed) only ran on CREATE ENTITY, so an
attribute added via `alter entity ... add attribute` escaped all of them —
a seedless autonumber returned "Check passed!" then failed the build with
CE7247. Extract the CREATE loop body into validateEntityAttribute and add
ValidateAlterEntity for the ADD ATTRIBUTE path, wired into both `check`
and the LSP. The entity kind is unknown from ALTER, so persistent-only
MDL020 is skipped; the kind-independent checks all run.

#24 (data loss): `create or modify entity` rebuilds the entity from the
statement alone and replaces the stored one, so any attribute the
statement omits is silently dropped (36->2 in practice), later surfacing
as CE1613 on widgets still bound to them. Make it warn (non-blocking — the
user asked to modify) and list the dropped members, pointing at
`alter entity ... add attribute` for incremental edits. Also fix the
"already exists" message so it recommends `alter entity` for a member
change and reserves `create or modify` for a full replace.

Adds unit + mock tests and bug-test examples for both, plus fix-issue
symptom rows.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
@ako
ako merged commit ca6f029 into main Jul 25, 2026
3 checks passed
ako pushed a commit that referenced this pull request Jul 27, 2026
Plain `refresh catalog` leaves the analytic tables empty (0 rows, no
error); a query then silently returns nothing. `warnIfCatalogModeInsufficient`
already warns for the FULL-only views, but `xpath_expressions` was missing
from `fullOnlyTables` — so `SELECT … FROM CATALOG.XPATH_EXPRESSIONS` in
fast mode returned empty with no hint (activities/refs were covered, but
xpath was not).

Add `xpath_expressions` to `fullOnlyTables` so a fast-mode query against
it warns "requires refresh catalog full" like the sibling analytic tables.
TestFullOnlyTablesCoverage guards that every FULL-gated view
(activities/refs/xpath_expressions/widgets) is flagged and a fast-mode
table (entities) is not.

Reported from the sudoku "app warehouse" finding (#30) — the
REFRESH-CATALOG-FULL silent-empty papercut.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
ako pushed a commit that referenced this pull request Jul 27, 2026
The catalog is a plain SQLite database at <projectDir>/.mxcli/catalog.db —
exporting it to JSON first (as one might reach for) is strictly worse: it
loses most of the tables, adds human-readable chatter, and goes stale.
Document attaching it directly, plus an external DuckDB "app warehouse"
recipe that joins the catalog to the app's Postgres and the OTLP trace
dump read-only for cross-source questions no single source can answer
(mxcli does not embed DuckDB — this is a dev-container recipe).

Also flag, in both the use-cases page and the REFRESH CATALOG page, that
FULL mode is what populates the analytic tables (activities/refs/
xpath_expressions/widgets) — plain refresh leaves them empty.

Reported from the sudoku "app warehouse" finding (#30).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
ako pushed a commit that referenced this pull request Jul 27, 2026
…alog)

Analyzing an app's runtime behavior is a recurring procedure spanning four
signals — the runtime log, Prometheus metrics, OpenTelemetry traces, and
the catalog (model shape) — so it belongs in a skill, not scattered across
feature docs.

Add `.claude/skills/mendix/analyze-runtime.md`: when to reach for each
signal, how to collect it (`run --local` + `--metrics` / `--trace` /
`--trace-otlp`, `refresh catalog full`), the cross-source "app warehouse"
join (external DuckDB — mxcli does not embed it), the logs↔traces gap, and
a decision guide mapping questions to tools. Registered in the skills
README (Specialized Skills + loading guide); synced into user projects by
`mxcli init`.

Trim the docs-site catalog "app warehouse" block to the catalog-attach
feature note plus a pointer to the skill, so the full procedure has a
single canonical home.

Follow-up to the sudoku "app warehouse" finding (#30).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
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