From cfede715ac3f4e2a949235aef40936a9ce23a942 Mon Sep 17 00:00:00 2001 From: Henrique Costa Date: Thu, 23 Apr 2026 23:01:55 +0200 Subject: [PATCH 1/2] fix: do not emit annotations before unsupported-action comments When the describer falls back to a placeholder comment for an activity it does not know how to render, preceding `@position(...)`, `@anchor(...)`, or similar annotations become orphaned on re-execution. The grammar accepts annotations only as a prefix of a real microflow statement. A comment placeholder is intentionally not a statement target, so annotation-prefixed comments can fail to parse. Skip object annotations when the formatted statement begins with `--`. The unsupported placeholder remains visible in describe output, but the generated MDL stays parseable. Tests cover unsupported/comment activity output with preceding activity metadata. --- mdl/executor/cmd_microflows_show_helpers.go | 12 ++++++ mdl/executor/cmd_microflows_traverse_test.go | 43 ++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/mdl/executor/cmd_microflows_show_helpers.go b/mdl/executor/cmd_microflows_show_helpers.go index 6c646abb..92c3c3de 100644 --- a/mdl/executor/cmd_microflows_show_helpers.go +++ b/mdl/executor/cmd_microflows_show_helpers.go @@ -374,6 +374,18 @@ func emitActivityStatement( return } + // When the activity is unsupported by the describer (e.g. CallWebServiceAction, + // CastAction, InheritanceSplit placeholder) we fall back to emitting just an + // MDL line comment. Decorating that comment with @position/@anchor/@annotation + // leaves the annotations orphaned — the grammar only accepts `annotation*` + // as a prefix of a real microflowStatement, so line comments preceded by + // annotations cause "no viable alternative at input '@position...end'" during + // exec. Emit the comment on its own instead. + if strings.HasPrefix(strings.TrimSpace(stmt), "--") { + *lines = append(*lines, indentStr+stmt) + return + } + // Emit @ annotations before the statement emitObjectAnnotations(obj, lines, indentStr, annotationsByTarget, flowsByOrigin, flowsByDest) diff --git a/mdl/executor/cmd_microflows_traverse_test.go b/mdl/executor/cmd_microflows_traverse_test.go index f924ddd1..63e78b3e 100644 --- a/mdl/executor/cmd_microflows_traverse_test.go +++ b/mdl/executor/cmd_microflows_traverse_test.go @@ -124,6 +124,49 @@ func TestTraverseFlow_IfElse(t *testing.T) { } } +// TestTraverseFlow_UnsupportedActivitySkipsAnnotations verifies that when the +// describer falls back to a `-- Unsupported action type: ...` placeholder, it +// does NOT also emit @position / @anchor before the comment. Annotations are +// only valid as a prefix of real MDL statements; orphaning them above a pure +// line comment triggers `no viable alternative at input '@position...end'` +// during `exec`. +func TestTraverseFlow_UnsupportedActivitySkipsAnnotations(t *testing.T) { + e := newTestExecutor() + + activityMap := map[model.ID]microflows.MicroflowObject{ + mkID("start"): µflows.StartEvent{BaseMicroflowObject: mkObj("start")}, + mkID("soap"): µflows.ActionActivity{ + BaseActivity: microflows.BaseActivity{BaseMicroflowObject: mkObj("soap")}, + Action: µflows.UnknownAction{TypeName: "Microflows$CallWebServiceAction"}, + }, + mkID("end"): µflows.EndEvent{BaseMicroflowObject: mkObj("end")}, + } + + flowsByOrigin := map[model.ID][]*microflows.SequenceFlow{ + mkID("start"): {mkFlow("start", "soap")}, + mkID("soap"): {mkFlow("soap", "end")}, + } + + var lines []string + visited := make(map[model.ID]bool) + e.traverseFlow(mkID("start"), activityMap, flowsByOrigin, nil, visited, nil, nil, &lines, 0, nil, 0, nil) + + for _, line := range lines { + if contains(line, "@position") { + t.Errorf("expected no @position prefix before unsupported-action comment, got: %v", lines) + } + } + found := false + for _, line := range lines { + if contains(line, "Unsupported action type") { + found = true + } + } + if !found { + t.Errorf("expected unsupported-action comment, got: %v", lines) + } +} + // ============================================================================= // collectErrorHandlerStatements // ============================================================================= From bf04456fe2a69cfb74dc42c6b08e34f97d8cb0d0 Mon Sep 17 00:00:00 2001 From: Henrique Costa Date: Sun, 26 Apr 2026 23:54:39 +0200 Subject: [PATCH 2/2] test: add bug-test reproducer for unsupported-activity annotation fix Adds an MDL script under mdl-examples/bug-tests/ documenting the unsupported-activity comment regression and providing a positive-control microflow that exercises annotated supported activities. Pure MDL cannot create unsupported activities; the negative case is covered by the existing Go test TestTraverseFlow_UnsupportedActivitySkipsAnnotations. Co-Authored-By: Claude Opus 4.7 --- ...annotations-before-unsupported-comment.mdl | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 mdl-examples/bug-tests/306-describer-annotations-before-unsupported-comment.mdl diff --git a/mdl-examples/bug-tests/306-describer-annotations-before-unsupported-comment.mdl b/mdl-examples/bug-tests/306-describer-annotations-before-unsupported-comment.mdl new file mode 100644 index 00000000..2c7deab9 --- /dev/null +++ b/mdl-examples/bug-tests/306-describer-annotations-before-unsupported-comment.mdl @@ -0,0 +1,61 @@ +-- ============================================================================ +-- Bug #306: Annotations emitted before unsupported-activity comments +-- ============================================================================ +-- +-- Symptom (before fix): +-- Activities whose BSON type isn't yet implemented in mxcli's describer +-- render as `-- unsupported: ` comments. Before the fix, the +-- describer still prefixed these comment lines with `@position`, +-- `@anchor`, etc. The grammar only accepts annotations as prefixes of +-- real microflow statements (not comments), so the resulting MDL failed +-- to re-parse with errors like: +-- line N:0 mismatched input '@' expecting {...} +-- +-- After fix: +-- When a formatted statement begins with `--`, `emitObjectAnnotations` +-- is skipped — only the comment is emitted. Annotations on SUPPORTED +-- activities continue to be emitted as before. +-- +-- Reproducibility note: +-- The unsupported-activity branch can only be triggered by an .mpr +-- containing a BSON activity type that mxcli does not yet describe +-- (typical examples are very new or rarely-used activity types). Pure +-- MDL cannot create such an activity. The Go-side regression +-- `TestTraverseFlow_UnsupportedActivitySkipsAnnotations` covers that +-- path directly. +-- +-- This script provides a POSITIVE CONTROL: a microflow whose every +-- activity carries position / caption / anchor annotations. Its describe +-- output must (a) parse with `mxcli check`, and (b) round-trip cleanly, +-- confirming the annotation-emission codepath still works for the +-- common case. +-- +-- Usage: +-- mxcli exec mdl-examples/bug-tests/306-describer-annotations-before-unsupported-comment.mdl -p app.mpr +-- mxcli -p app.mpr -c "describe microflow BugTest306.MF_AnnotatedFlow" +-- The output must re-execute cleanly against the same project. +-- ============================================================================ + +create module BugTest306; + +create microflow BugTest306.MF_AnnotatedFlow ( + $input: string +) +returns string as $result +begin + declare $result string = empty; + + @caption 'log entry' + log info node 'BugTest306' 'flow started'; + + @caption 'guard' + if $input != empty then + @caption 'happy path' + set $result = 'value: ' + $input; + else + set $result = 'no value'; + end if; + + return $result; +end; +/