@@ -159,28 +159,24 @@ func TestPlugin_Outcome(t *testing.T) {
159159 timestamp := time .Now ().UnixMilli ()
160160 observations := []* pb.Observation {
161161 {
162- Timestamp : timestamp ,
163- Requests : map [string ]int64 {
164- executionID : 0 ,
165- },
162+ Timestamp : timestamp ,
163+ Requests : map [string ]int64 {executionID : 0 },
164+ PruneExecutions : true ,
166165 },
167166 {
168- Timestamp : timestamp - int64 (time .Second ),
169- Requests : map [string ]int64 {
170- executionID : 0 ,
171- },
167+ Timestamp : timestamp - int64 (time .Second ),
168+ Requests : map [string ]int64 {executionID : 0 },
169+ PruneExecutions : true ,
172170 },
173171 {
174- Timestamp : timestamp + int64 (time .Second ),
175- Requests : map [string ]int64 {
176- executionID : 0 ,
177- },
172+ Timestamp : timestamp + int64 (time .Second ),
173+ Requests : map [string ]int64 {executionID : 0 },
174+ PruneExecutions : true ,
178175 },
179176 {
180- Timestamp : timestamp ,
181- Requests : map [string ]int64 {
182- executionID : 0 ,
183- },
177+ Timestamp : timestamp ,
178+ Requests : map [string ]int64 {executionID : 0 },
179+ PruneExecutions : true ,
184180 },
185181 }
186182
@@ -224,8 +220,9 @@ func TestPlugin_Outcome_SequenceNumberHandling(t *testing.T) {
224220 aos := make ([]types.AttributedObservation , numNodes )
225221 for i := 0 ; i < numNodes ; i ++ {
226222 obs := & pb.Observation {
227- Timestamp : timestamp + int64 (i ),
228- Requests : requests ,
223+ Timestamp : timestamp + int64 (i ),
224+ Requests : requests ,
225+ PruneExecutions : true ,
229226 }
230227 rawObs , err := proto .Marshal (obs )
231228 require .NoError (t , err )
@@ -434,22 +431,10 @@ func TestPlugin_FinishedExecutions(t *testing.T) {
434431 t .Run ("Outcome: remove expired workflow executions" , func (t * testing.T ) {
435432 timestamp := time .Now ().UnixMilli ()
436433 observations := []* pb.Observation {
437- {
438- Timestamp : timestamp ,
439- Requests : map [string ]int64 {},
440- },
441- {
442- Timestamp : timestamp - int64 (time .Second ),
443- Requests : map [string ]int64 {},
444- },
445- {
446- Timestamp : timestamp + int64 (time .Second ),
447- Requests : map [string ]int64 {},
448- },
449- {
450- Timestamp : timestamp ,
451- Requests : map [string ]int64 {},
452- },
434+ {Timestamp : timestamp , Requests : map [string ]int64 {}, PruneExecutions : true },
435+ {Timestamp : timestamp - int64 (time .Second ), Requests : map [string ]int64 {}, PruneExecutions : true },
436+ {Timestamp : timestamp + int64 (time .Second ), Requests : map [string ]int64 {}, PruneExecutions : true },
437+ {Timestamp : timestamp , Requests : map [string ]int64 {}, PruneExecutions : true },
453438 }
454439
455440 aos := make ([]types.AttributedObservation , 4 )
@@ -484,6 +469,47 @@ func TestPlugin_FinishedExecutions(t *testing.T) {
484469 require .NotContains (t , outcomeProto .ObservedDonTimes , "workflow-123" )
485470 })
486471
472+ t .Run ("Outcome: legacy path when only half nodes have PruneExecutions set" , func (t * testing.T ) {
473+ timestamp := time .Now ().UnixMilli ()
474+ emptyID := "empty-workflow"
475+
476+ // Only 2 of 4 nodes have PruneExecutions=true → pruneExecutions stays false → legacy path.
477+ observations := []* pb.Observation {
478+ {Timestamp : timestamp , Requests : map [string ]int64 {}, PruneExecutions : true },
479+ {Timestamp : timestamp - int64 (time .Second ), Requests : map [string ]int64 {}, PruneExecutions : true },
480+ {Timestamp : timestamp + int64 (time .Second ), Requests : map [string ]int64 {}, PruneExecutions : false },
481+ {Timestamp : timestamp , Requests : map [string ]int64 {}, PruneExecutions : false },
482+ }
483+
484+ aos := make ([]types.AttributedObservation , len (observations ))
485+ for i , obs := range observations {
486+ rawObs , err := proto .Marshal (obs )
487+ require .NoError (t , err )
488+ aos [i ] = types.AttributedObservation {Observation : rawObs , Observer : commontypes .OracleID (i )}
489+ }
490+
491+ // prevOutcome contains an entry for emptyID with no timestamps.
492+ prevOutcome := & pb.Outcome {
493+ Timestamp : timestamp - 1000 ,
494+ ObservedDonTimes : map [string ]* pb.ObservedDonTimes {
495+ emptyID : {Timestamps : []int64 {}},
496+ },
497+ }
498+ prevOutcomeBytes , err := proto .Marshal (prevOutcome )
499+ require .NoError (t , err )
500+
501+ outcome , err := plugin .Outcome (ctx , ocr3types.OutcomeContext {PreviousOutcome : prevOutcomeBytes }, query , aos )
502+ require .NoError (t , err )
503+
504+ legacyOutcomeProto := & pb.Outcome {}
505+ err = proto .Unmarshal (outcome , legacyOutcomeProto )
506+ require .NoError (t , err )
507+
508+ // Legacy behavior: empty-timestamps entry is NOT pruned.
509+ require .Contains (t , legacyOutcomeProto .ObservedDonTimes , emptyID )
510+ require .Empty (t , legacyOutcomeProto .ObservedDonTimes [emptyID ].Timestamps )
511+ })
512+
487513 t .Run ("Transmit: delete removed executionIDs" , func (t * testing.T ) {
488514 store .setDonTimes ("workflow-123" , []int64 {time .Now ().UnixMilli ()})
489515
0 commit comments