diff --git a/modules/mesh-delivery-pipeline/internal/pipeline/hold_test.go b/modules/mesh-delivery-pipeline/internal/pipeline/hold_test.go index d150d00a..39149241 100644 --- a/modules/mesh-delivery-pipeline/internal/pipeline/hold_test.go +++ b/modules/mesh-delivery-pipeline/internal/pipeline/hold_test.go @@ -56,9 +56,20 @@ func TestPipelinesAreHeldForTheNewRunnerAndReleasedWhenItRuns(t *testing.T) { if p.Held == nil || p.Held.Fingerprint != "src2:new" || len(p.Steps) != 0 || len(asks.asks) != 0 { t.Fatalf("held = %+v, steps %d, asks %d", p.Held, len(p.Steps), len(asks.asks)) } - if strings.Join(said, "|") != "wait-held.app.main.c1|wait-held.runner.main.c2" || len(bounds) != 2 || bounds[0] != "src2:new" { + // The runner's own pipeline is never held: it runs on the running runner, so its pass lets the new runner be wanted (A-328). + if p, _, _ := store.Get("main.4.runner"); p.Held != nil || p.Outcome != seat.PipelineOutcomeRunning { + t.Errorf("the runner's own pipeline is held %+v, want it running on the running runner", p.Held) + } + if strings.Join(said, "|") != "wait-held.app.main.c1|pipeline-started.runner.main.c2" || len(bounds) != 1 || bounds[0] != "src2:new" { t.Errorf("said %v, bounds %v", said, bounds) } + // A later take-in of the runner's own module while one is held is not held either (A-328). + if n, err := s.TakenIn(catalog.TakeInTaken{Key: "m.3", Branch: "main", Source: 6, Entries: []catalog.TakeInEntry{{Module: "runner", Commit: "c4", Fingerprint: "src2:new"}}}, view); err != nil || n != 1 { + t.Fatalf("a take-in of the runner alone = %d, %v", n, err) + } + if p, _, _ := store.Get("main.6.runner"); p.Held != nil { + t.Errorf("the runner's own later pipeline is held %+v", p.Held) + } // A later take-in not naming the runner is held for the same version. if n, err := s.TakenIn(catalog.TakeInTaken{Key: "m.2", Branch: "main", Source: 5, Entries: []catalog.TakeInEntry{{Module: "app", Commit: "c3", Fingerprint: "src2:bb"}}}, view); err != nil || n != 1 { t.Fatalf("second take-in = %d, %v", n, err) @@ -72,7 +83,7 @@ func TestPipelinesAreHeldForTheNewRunnerAndReleasedWhenItRuns(t *testing.T) { } said = nil n, err = s.Release(store.memStore, "src2:new", "ran", view) - if err != nil || n != 3 { + if err != nil || n != 2 { t.Fatalf("release = %d, %v", n, err) } p, _, _ = store.Get("main.4.app") @@ -114,7 +125,7 @@ func TestReleaseVerbStartsTheHeldPipelinesByHand(t *testing.T) { } said = nil a, err := v.Release("operator", seat.ReleaseInput{Why: "the new runner will not come"}) - if err != nil || a.Released != 2 { + if err != nil || a.Released != 1 { // the runner's own pipeline was never held (A-328) t.Fatalf("release = %+v, %v", a, err) } if p, _, _ := store.Get("main.4.app"); p.Held != nil || len(p.Steps) == 0 || len(asks.asks) == 0 { @@ -193,7 +204,7 @@ func TestHeldWaitCountsFromTheBuildEndOfTheAwaitedRunner(t *testing.T) { if _, err := s.TakenIn(taken, view); err != nil { t.Fatal(err) } - if len(waits) != 2 || waits[0].ClockFrom != nil || len(armed) != 0 { + if len(waits) != 1 || waits[0].ClockFrom != nil || len(armed) != 0 { // the runner's own pipeline is never held (A-328) t.Fatalf("waits %+v, armed %v", waits, armed) } // A failed end starts no clock; a done end does. @@ -204,10 +215,10 @@ func TestHeldWaitCountsFromTheBuildEndOfTheAwaitedRunner(t *testing.T) { t.Fatalf("heard %q %q %v", m, fp, ok) } waits = nil - if n, err := s.Clocked(store.memStore, "runner", "src2:new"); err != nil || n != 2 { + if n, err := s.Clocked(store.memStore, "runner", "src2:new"); err != nil || n != 1 { t.Fatalf("clocked = %d, %v", n, err) } - if len(waits) != 2 || waits[0].ClockFrom == nil || !waits[0].ClockFrom.Equal(end) || len(armed) != 1 || armed[0] != "src2:new@2026-11-11T12:00:00Z" { + if len(waits) != 1 || waits[0].ClockFrom == nil || !waits[0].ClockFrom.Equal(end) || len(armed) != 1 || armed[0] != "src2:new@2026-11-11T12:00:00Z" { t.Errorf("waits %+v, armed %v", waits, armed) } // A pipeline held after the end is known says the clock at once. diff --git a/modules/mesh-delivery-pipeline/internal/pipeline/start.go b/modules/mesh-delivery-pipeline/internal/pipeline/start.go index b1a0ccec..420fa8ed 100644 --- a/modules/mesh-delivery-pipeline/internal/pipeline/start.go +++ b/modules/mesh-delivery-pipeline/internal/pipeline/start.go @@ -122,7 +122,12 @@ func (s *Starter) Start(b Begin) (bool, error) { if err := s.Fills.refuseStart(key); err != nil { return false, err } - if b.Await == "" && s.Awaiting != nil { + // The runner's own pipeline is never held: it runs on the running runner, as a build module's running version builds its + // successor (§270, A-328), so its pass lets the new runner be wanted (§29). + if b.Module != "" && b.Module == s.Self { + b.Await = "" + } + if b.Await == "" && s.Awaiting != nil && b.Module != s.Self { if fp, ok := s.Awaiting(); ok { b.Await = fp } @@ -403,7 +408,8 @@ func (s *Starter) TakenIn(ev catalog.TakeInTaken, view func(branch string) (Half half, _ := view(ev.Branch) started := 0 var first error - // A take-in giving the runner's own module a new fingerprint holds every pipeline it starts for that runner (§65, A-195). + // A take-in giving the runner's own module a new fingerprint holds every other pipeline it starts for that runner (§65, + // A-195, A-328); the runner's own runs now (Start). await := "" for _, e := range ev.Entries { if s.changesSelf(e.Module, e.Fingerprint) {