Skip to content

Commit 3992198

Browse files
authored
Merge pull request #331 from hjotha/submit/preserve-loop-body-annotations
fix: preserve annotations attached inside loop bodies
2 parents 2949618 + 9a3b804 commit 3992198

12 files changed

Lines changed: 324 additions & 241 deletions

cmd/mxcli/tui/watcher.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"os"
55
"path/filepath"
66
"sync"
7+
"sync/atomic"
78
"time"
89

910
tea "github.com/charmbracelet/bubbletea"
@@ -78,6 +79,7 @@ func newWatcher(mprPath, contentsDir string, sender MsgSender) (*Watcher, error)
7879

7980
func (w *Watcher) run(sender MsgSender) {
8081
var debounceTimer *time.Timer
82+
var debounceSeq atomic.Uint64
8183

8284
for {
8385
select {
@@ -110,7 +112,11 @@ func (w *Watcher) run(sender MsgSender) {
110112
if debounceTimer != nil {
111113
debounceTimer.Stop()
112114
}
115+
seq := debounceSeq.Add(1)
113116
debounceTimer = time.AfterFunc(watchDebounce, func() {
117+
if debounceSeq.Load() != seq {
118+
return
119+
}
114120
sender.Send(MprChangedMsg{})
115121
})
116122

cmd/mxcli/tui/watcher_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,11 @@ func TestWatcherDebounce(t *testing.T) {
3535
}
3636
defer w.Close()
3737

38-
// Rapidly write 5 times — should debounce into a single message
38+
// Rapidly write 5 times — should debounce into a single message.
39+
// Keep the burst tighter than the debounce window so slow CI machines do
40+
// not accidentally let an intermediate timer fire.
3941
for i := range 5 {
4042
_ = os.WriteFile(unitFile, []byte{byte('a' + i)}, 0644)
41-
time.Sleep(50 * time.Millisecond)
4243
}
4344

4445
// Wait for debounce to fire (500ms + margin)
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
-- ============================================================================
2+
-- Bug #330: Annotations inside loop bodies disappeared after describe/exec
3+
-- ============================================================================
4+
--
5+
-- Symptom (before fix):
6+
-- `@annotation 'note'` attached to a statement nested inside `loop ... end loop;`
7+
-- (or `while ... end while;`) survived the first execution but disappeared
8+
-- on the next describe → exec roundtrip. The annotation existed in the
9+
-- loop's local object collection but the parent microflow graph never
10+
-- saw it, so the next describer pass dropped it. Annotations on nested
11+
-- decisions (IF inside a LOOP) were the most visible casualty — the
12+
-- notes that explain WHY a loop exists were silently lost.
13+
--
14+
-- Root cause:
15+
-- The microflow builder copied nested loop sequence flows back to the
16+
-- parent graph but did not copy nested ANNOTATION flows. The describer
17+
-- then collected annotation captions only from the top-level object
18+
-- collection, ignoring captions stored inside nested loop collections.
19+
--
20+
-- After fix:
21+
-- - Builder: loop/while statement handlers also copy
22+
-- `nested.AnnotationFlows` into the parent graph.
23+
-- - Describer: `collectAnnotationCaptions` walks recursively into
24+
-- nested loop object collections, and `emitLoopBody` merges the
25+
-- loop-local annotation map into the per-body traversal.
26+
--
27+
-- Scope note:
28+
-- The Go-side regression `TestLoopBodyIfAnnotationPromotedToParentFlows`
29+
-- covers the AST→BSON build path. This MDL script reproduces the
30+
-- describer side: after exec, the annotation must appear in the
31+
-- describe output. A full describe → exec → describe FIXPOINT for
32+
-- nested IF inside LOOP additionally depends on the nearest split-merge
33+
-- pairing fix (issue #326 / PR #327); on a branch that includes both
34+
-- fixes, this script round-trips cleanly.
35+
--
36+
-- Usage:
37+
-- mxcli exec mdl-examples/bug-tests/330-preserve-loop-body-annotations.mdl -p app.mpr
38+
-- mxcli -p app.mpr -c "describe microflow BugTest330.MF_LoopWithAnnotations"
39+
-- The describe output must contain `@annotation 'note on nested if'`
40+
-- on the IF inside the loop body.
41+
-- ============================================================================
42+
43+
create module BugTest330;
44+
45+
create entity BugTest330.Item (
46+
Name : string(100)
47+
);
48+
/
49+
50+
-- LOOP body containing an annotated IF — the case that originally lost the
51+
-- annotation. The note on the IF must appear in the describe output.
52+
create microflow BugTest330.MF_LoopWithAnnotations (
53+
$Items: list of BugTest330.Item
54+
)
55+
begin
56+
loop $Item in $Items
57+
begin
58+
@annotation 'note on nested if'
59+
if $Item/Name != empty then
60+
log info node 'BugTest330' 'has name';
61+
end if;
62+
end loop;
63+
end;
64+
/

0 commit comments

Comments
 (0)