Skip to content

Commit aaea7a5

Browse files
akoclaude
andcommitted
feat: detect duplicate CREATE in mxcli check (MDL-DUPDEF)
Phase 1 (mxcli check): CheckScriptDuplicates walks the AST in order, tracking live names per document type. Flags a second plain CREATE of the same qualified name as MDL-DUPDEF. CREATE OR MODIFY/REPLACE is never flagged. DROP clears the name so CREATE/DROP/CREATE is clean. RENAME removes the old name and registers the new one; module renames cascade across all tracked names. RENAME DRY RUN leaves the registry unchanged. Phase 2 (mxcli check --references): CheckProjectConflicts loads the project's existing documents once and errors on any plain CREATE that targets a name already present in the project. Names created earlier in the same script are excluded (Phase 1 owns those conflicts). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 3742709 commit aaea7a5

4 files changed

Lines changed: 1003 additions & 0 deletions

File tree

cmd/mxcli/cmd_check.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@ Examples:
118118
}
119119
}
120120

121+
// Check for intra-script duplicate definitions (CREATE X … CREATE X without DROP)
122+
violations = append(violations, executor.CheckScriptDuplicates(prog)...)
123+
121124
if isStructured {
122125
// Always emit structured output (even when clean)
123126
formatter.Format(violations, os.Stderr)
@@ -159,6 +162,10 @@ Examples:
159162

160163
// Validate the program (considers objects defined within the script)
161164
validationErrors := exec.ValidateProgram(prog)
165+
166+
// Check for project conflicts: plain CREATE where the document already exists
167+
validationErrors = append(validationErrors, exec.CheckProjectConflicts(prog)...)
168+
162169
if len(validationErrors) > 0 {
163170
if isStructured {
164171
var refViolations []linter.Violation

mdl/executor/validate.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,14 @@ func (e *Executor) ValidateProgram(prog *ast.Program) []error {
191191
return validateProgram(e.newExecContext(context.Background()), prog)
192192
}
193193

194+
// CheckProjectConflicts walks prog in statement order and returns errors for
195+
// any plain CREATE (non-OR-MODIFY) that targets a document name that already
196+
// exists in the connected project. Names created earlier in the same script are
197+
// excluded — those will be caught by CheckScriptDuplicates.
198+
func (e *Executor) CheckProjectConflicts(prog *ast.Program) []error {
199+
return CheckProjectConflicts(e.newExecContext(context.Background()), prog)
200+
}
201+
194202
// validateWithContext validates a statement, considering objects defined in the script.
195203
func validateWithContext(ctx *ExecContext, stmt ast.Statement, sc *scriptContext) error {
196204
switch s := stmt.(type) {

0 commit comments

Comments
 (0)