Skip to content

mdl: deprecation registry for MDL aliases (MDL-DEPRnnn) - #727

Merged
ako merged 3 commits into
mainfrom
feature/709-deprecation-registry
Sep 27, 2026
Merged

ako merged 3 commits into
mainfrom
feature/709-deprecation-registry

Conversation

@ako

@ako ako commented Sep 26, 2026 •

Copy link
Copy Markdown
Owner

Closes #709. Plan item 1.2 of PROPOSAL_mdl_beta_syntax_freeze.md, and ADR-0011 decision 1. Tracking: #714.

What

There is now one registry of deprecated MDL spellings, and check and exec warn on each use of one. The only behaviour change is new warnings: nothing is removed, and every script runs as before.

  • mdl/deprecation is the registry. Each entry holds a code (MDL-DEPRnnn), the old form, the canonical form, a mechanical Rewrite (a token swap, for fmt --upgrade in 1.3), RemovedIn (a language version), a note, and two examples: one in the old form and its canonical rewrite.
  • Detection generalises MDL065. Both spellings build the same AST, so the visitor records which one the source used on ast.Program.Deprecations (code, line, column, subject). It does this from the parse tree: ExitCreateStatement and a new ExitShowOrList.
  • executor.ValidateDeprecations runs inside ValidateProgram, so check and exec both get it. Each warning names the line, the canonical form, and the version that will refuse the old form.
  • --deprecations=warn|error is a new flag on check and exec. With error, only MDL-DEPR* findings are promoted to errors. An unknown value exits with code 2 rather than being treated as warn, so a typo cannot quietly pass a CI gate.
  • Alias marking in the grammar: a block comment /* @alias MDL-DEPRnnn */ goes next to the alias token, and ANTLR ignores it. TestGrammarAliasesAreRegistered (in mdl/grammar) reads the .g4 sources. It fails on three things: a marker whose code has no registry entry, a malformed marker, and a registry entry that no marker names. TestAliasMarkerCheckerDetectsProblems is the control: it feeds the checker a grammar that is bad in each of those three ways.
  • Seed entries:
    • MDL-DEPR001 create or replace becomes create or modify, marked at MDLParser.g4 createStatement.
    • MDL-DEPR002 show becomes list, marked at MDLCatalog.g4 showOrList.
  • I added an MDL-DEPRnnn section to docs-site/src/appendixes/error-messages.md. It points to the registry and does not copy it.

Design choices the ADRs did not settle

  1. create or replace is reported only where it is an exact alias. I measured each create kind against the visitors. For four kinds, or replace does not mean or modify today:

    • view entity drops and recreates.
    • translations replaces the whole set instead of merging.
    • user role and demo user ignore replace, so the statement is a plain create.

    Telling users to rewrite those would change their scripts, so those four are exempt. TestCreateOrReplaceMatchesModifyExceptExemptKinds pins this in both directions for every kind in createStatement, which it reads from the grammar, so a new kind fails until it has a case:

    • A non-exempt kind must build DeepEqual statements for or replace and or modify.
    • An exempt kind must build different statements, so a stale exemption also fails.

    Page, snippet and layout keep separate IsReplace/IsModify flags. Every reader of those flags tests IsModify || IsReplace, so the test folds the two together.

  2. show → list, reported only where list is the canonical form (narrowed in review, commit ce68cc6). The proposal's decided mapping (§3, R6) sends plurals and relationship queries to list, single things to describe (show entity|association|page X, show navigation …, show structure, show context of X, show project security, show security matrix, show settings) and session state (show version|status|connections, show catalog status) to REPL commands. list builds the same statement for all of them today, but recommending list entity X or list version would name a non-canonical form and make fmt --upgrade rewrite those scripts twice. So those forms are not reported yet; they get their own entries once their canonical forms exist (3.5). showNotYetList in visitor_deprecations.go holds the exclusions, keyed on the token after show; TestShowRecordsDeprecation pins both sides.

  3. Out of scope for show: show lint rules has no list form, and sql <conn> show … is a different statement. Neither is an alias, so neither is marked. The microflow activities show page and show message are covered by a negative test.

  4. RemovedIn: 2. ADR-0011 and proposal §6 say an alias warns under the version that deprecates it and is refused under the next one. mdl 1 is beta, so these are refused from mdl 2.

  5. MDL065 keeps its code. Moving the split case/else spellings into the registry would rename a warning that existing tests and users key on. I left that as a follow-up.

Test plan

  • go test ./mdl/visitor ./mdl/executor ./mdl/grammar -run 'Deprecat|CreateOrReplace|RegistryExamples|ShowRecords|Alias': pass.
  • Each fix proven by revert:
    • Removing the recordCreateOrReplace call fails TestRegistryExamplesRecordTheirCode and TestCreateOrReplace… ("recorded [], want [MDL-DEPR001]").
    • Renaming ExitShowOrList fails the show, position and executor tests.
    • Dropping the userrole exemption fails with "or replace and or modify build different statements".
    • Deleting the MDL-DEPR002 registry entry fails TestGrammarAliasesAreRegistered with "domains/MDLCatalog.g4:12: grammar alias MDL-DEPR002 has no entry in mdl/deprecation".
    • Making ApplyDeprecationPolicy a no-op fails TestDeprecationPolicyErrorFailsTheRun.
  • Manual run of bin/mxcli check:
    • A script with create or replace enumeration, show entities and create or replace translations gets 2 warnings and exits 0. The translations statement is correctly not reported.
    • The same script with --deprecations=error gets 2 errors and exits 1.
    • --deprecations=bogus exits 2.
    • The canonical script with --deprecations=error passes.
  • make build: pass.
  • make lint: pass (Go and TS).
  • make test: the first run failed with "no space left on device". The shared /tmp tmpfs was full because other agents are using it, and those failures were in fixture copies and compile output. I re-ran with TMPDIR on the large disk. Everything passed except mdl/backend/modelsdk, which hit the 10-minute default timeout on a loaded machine. Re-run alone with -timeout 40m, it passes (463s). This change does not touch that package.

Review (independent reviewer)

  • Re-ran every revert check above myself; each fails as described.
  • Added mdl/deprecation/deprecation_test.go (the new package had no tests): registry entries well-formed/unique/complete, RemovedIn >= 2, and ParsePolicy refuses unknown values (stubbing the error path fails 4 cases).
  • make build, make lint pass. Full go test ./... with TMPDIR on the large disk: only environment failures (unix-socket chmod on the overlay FS in tui, and two packages that failed to build mid-run while I rebuilt bin/); tui, docker, tunnelhub and cmd/mxcli all pass re-run on their own.
  • bin/mxcli check over show entity M.E; show version; show entities; with --deprecations=error: 1 error (line 3 only), exit 1.

Follow-ups (not in this PR)

  • describe navigation still emits create or replace navigation (cmd_navigation.go). ADR-0011 says describe never emits a deprecated form, so it should switch to create or modify. That is a describe-output change, so it gets its own PR.
  • Help and error texts still teach create or replace (cmd_entities.go "already exists" hint, cmd_misc.go help, the translations messages). The skills and docs also use show/create or replace widely. The 1.4 conformance gate will surface those.
  • Register the remaining show forms (single things → describe, session state → REPL) once those canonical forms exist (3.5).
  • Decide the canonical forms for the four exempt create or replace kinds. They are changes of meaning, not aliases, so they belong to the version header (1.5).
  • Fold MDL065 (the split case/else spellings) into the registry.
  • fmt --upgrade (1.3) consumes Entry.Rewrite.

🤖 Generated with Claude Code

ako and others added 3 commits September 26, 2026 21:00
One registry of deprecated MDL spellings (ADR-0011 decision 1), generalising
the MDL065 pattern: both spellings build the same AST, so the visitor records
which one the source used on ast.Program.Deprecations, and check/exec warn
through ValidateProgram. --deprecations=error fails the run instead.

Grammar aliases are marked with /* @alias MDL-DEPRnnn */ next to the token;
TestGrammarAliasesAreRegistered fails on a marker with no registry entry, or an
entry no marker names.

Seeded with create or replace -> create or modify (MDL-DEPR001) and
show -> list (MDL-DEPR002). create or replace is only reported where it builds
the same statements as create or modify; view entity, translations, user role
and demo user differ today and are exempt, pinned per create kind.

Closes #709

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ist`

The proposal's decided mapping for `show` (PROPOSAL_mdl_beta_syntax_freeze.md
§3, R6) sends single things to `describe` (show entity X, show navigation,
show project security, show structure, show context of X, …) and session
state (show version, show status, show connections, show catalog status) to
REPL commands. Warning "write `list …`" on those named a non-canonical form,
and `fmt --upgrade` consuming the rewrite would have rewritten them twice.
They are left unreported until their canonical forms exist (plan item 3.5).

Also adds tests for the mdl/deprecation package itself: registry entries are
well-formed and unique, and ParsePolicy refuses unknown values.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…on-registry

# Conflicts:
#	mdl/ast/ast.go
#	mdl/executor/validate_program.go
#	mdl/visitor/visitor.go
@ako
ako merged commit 82dccba into main Sep 27, 2026
17 checks passed
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.

Deprecation registry for MDL aliases (MDL-DEPRnnn), generalising MDL065

1 participant