feat: diag --check-units + grammar fixes#67
Conversation
…D reuse BSON int32→int64: - All property values in writer serialization changed from int32 to int64 to match Studio Pro's expected BSON types - Array version markers (int32(2), int32(3)) preserved as int32 - Fixes Studio Pro crash: "Sequence contains no matching element" in MprProperty..ctor when type cache expects int64 but finds int32 CREATE OR REPLACE PAGE: - Reuses existing page UUID and calls UpdatePage instead of DeletePage+ CreatePage, producing git "Modified" diff instead of "Deleted+Added" - Prevents RevStatusCache crash when parsing deleted mxunit base files BSON roundtrip test baseline: - Add golden mxunit files for roundtrip testing (pages, microflows, enums) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
diag --check-units: - New command to detect orphan units (DB record, no file) and stale mxunit files (file exists, no DB record) - --fix flag auto-removes stale files - bson dump --format bson output format Grammar fixes for MDL baseline scripts: - Add DISPLAY, STRUCTURE to enumValueName rule - Support String(unlimited) syntax in dataType - Add ATTRIBUTE to attributeName rule - Support parenthesized CREATE ASSOCIATION with optional colons - Add SEND, REQUEST, TABLETWIDTH, PHONEWIDTH keywords Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
AI Code ReviewCritical Issues
Moderate Issues
Minor Issues
What Looks Good
RecommendationRequest changes until either:
Given the truncation of the diff, verify that AST/visitor/executor changes for the grammar modifications exist in the complete diff before proceeding. If they do exist but weren't shown, this concern can be withdrawn. Automated review via OpenRouter (Nemotron Super 120B) — workflow source |
ako
left a comment
There was a problem hiding this comment.
Review
Scope concerns
This PR bundles four independent changes that should be separate PRs per the repo's checklist:
mxcli diag --check-units(new feature)- Grammar compatibility fixes (new tokens, parser rule changes)
bson dump --format bson(enhancement)- All of PR #66's changes (int32→int64, CREATE OR REPLACE PAGE UUID reuse)
The PR description just says "Stacked on #66" — the grammar changes and BSON dump format aren't mentioned at all.
Issues
1. Undisclosed ANTLR visitor generation (+2,635 lines)
Two new generated files are added (mdlparser_base_visitor.go, mdlparser_visitor.go) that don't exist on main. This means the ANTLR code generation config was changed to produce visitors in addition to listeners. This is a significant change:
- It's not mentioned in the PR description
- It's unclear if it was intentional or accidental (e.g., a different ANTLR version or flag)
- The codebase uses the listener pattern (
mdl/visitor/package) — if nobody consumes the visitor interface, these are ~2,600 lines of dead generated code
2. Grammar rules added without visitor/executor wiring
Several new grammar constructs are added but appear to have no corresponding visitor or executor code:
| Grammar addition | Visitor handler? | Executor handler? |
|---|---|---|
PLUGGABLEWIDGET token + widgetV3 rule |
Not in this PR | Not in this PR |
TABCONTAINER / TABPAGE tokens + widgetTypeV3 |
Not in this PR | Not in this PR |
keyword COLON propertyValueV3 (widget property) |
Not in this PR | Not in this PR |
Parenthesized CREATE ASSOCIATION syntax |
Not in this PR | Not in this PR |
DATASOURCE EQUALS dataSourceExprV3 (alterPageAssignment) |
Not in this PR | Not in this PR |
Per the repo's full-stack consistency checklist, new grammar rules must be wired through visitor → executor. Without that, these rules parse but silently do nothing — or worse, hit a nil/unhandled case at runtime.
3. String(unlimited) uses overly broad IDENTIFIER
: STRING_TYPE (LPAREN (NUMBER_LITERAL | IDENTIFIER) RPAREN)?This accepts String(anything) — not just String(unlimited). A dedicated UNLIMITED token or a semantic check would be safer.
4. keyword COLON propertyValueV3 is very broad
Adding keyword as a widget property name alternative means every keyword in the language can appear as a property name. This risks grammar ambiguities — e.g., FROM : someValue inside a widget block could conflict with association syntax. Was this tested for parser conflicts?
5. ListAllUnitIDs silently swallows scan errors
if err := rows.Scan(&unitID); err != nil {
continue // silently skips corrupted rows
}At minimum this should log or count the errors so users know their Unit table has issues.
6. --fix deletes files without confirmation
os.Remove(fpath) is a destructive operation. The --fix flag auto-deletes stale mxunit files without asking for confirmation. Consider either:
- Printing what would be deleted first (dry-run by default), or
- Requiring an explicit
--yes/-yflag for unattended use
The current --fix UX silently deletes and only prints after the fact.
7. All PR #66 issues still apply
Since this is stacked on #66, the same issues apply: debug logging in writer_widgets_custom.go, inconsistent array markers, comment/code mismatches. See PR #66 review.
Minor
safeInt64is still a no-op (inherited from #66)- The
.mxunitgolden files are still not wired to any test functions os.Remove(dir2)/os.Remove(dir1)for cleaning empty parent dirs silently ignore errors — acceptable for non-empty dirs, but a comment explaining the intent would help
Stacked on #66