From 5d3965eca62f745458f7c55989d7201877821c40 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Wed, 22 Apr 2026 23:28:47 +0000 Subject: [PATCH 1/3] fix: treat 0/0 release targets as 100% pass rate in policy evaluation When a tier has 0 instances, a minimum pass rate policy (e.g. 80%) was failing because GetSuccessPercentage() returned 0.0 despite the comment saying to treat it as 100% successful. Applied vacuous truth: 0/0 = 100%. Also fixed GetSuccessPercentageSatisfiedAt() to return the version's creation time (not zero time) when there are no targets, consistent with how evaluateJobSuccessCriteria handles this case. Fixes #1040 Co-authored-by: Aditya Choudhari --- .../policy/evaluator/environmentprogression/jobtracker.go | 6 +++--- .../evaluator/environmentprogression/jobtracker_test.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/environmentprogression/jobtracker.go b/apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/environmentprogression/jobtracker.go index 226ad413a..9c4ec0282 100644 --- a/apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/environmentprogression/jobtracker.go +++ b/apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/environmentprogression/jobtracker.go @@ -196,8 +196,8 @@ func (t *ReleaseTargetJobTracker) GetSuccessPercentage() float32 { numRt := len(t.ReleaseTargets) if numRt == 0 { - span.SetAttributes(attribute.Float64("success_percentage", 0.0)) - return 0.0 // If no targets, consider it 100% successful + span.SetAttributes(attribute.Float64("success_percentage", 100.0)) + return 100.0 // vacuous truth: 0/0 targets successful } // Build a set of release target keys for filtering @@ -242,7 +242,7 @@ func (t *ReleaseTargetJobTracker) GetSuccessPercentageSatisfiedAt( } numRt := len(t.ReleaseTargets) if numRt == 0 { - return time.Time{} + return t.Version.CreatedAt } // Build a set of release target keys for filtering diff --git a/apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/environmentprogression/jobtracker_test.go b/apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/environmentprogression/jobtracker_test.go index 71136c941..da3ceced4 100644 --- a/apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/environmentprogression/jobtracker_test.go +++ b/apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/environmentprogression/jobtracker_test.go @@ -77,7 +77,7 @@ func TestReleaseTargetJobTracker_GetSuccessPercentage_NoTargets(t *testing.T) { tracker := NewReleaseTargetJobTracker(ctx, mock, env, version, nil, false) percentage := tracker.GetSuccessPercentage() - assert.InDelta(t, float32(0.0), percentage, 0, "expected 0%% success with no targets") + assert.InDelta(t, float32(100.0), percentage, 0, "expected 100%% success with no targets (vacuous truth)") } func TestReleaseTargetJobTracker_GetSuccessPercentage_WithSuccesses(t *testing.T) { From bd15aa85f1eb76003d7e1a4dadc8a9578fe039be Mon Sep 17 00:00:00 2001 From: Aditya Choudhari Date: Thu, 23 Apr 2026 10:16:12 -0700 Subject: [PATCH 2/3] fixes --- .../evaluator/environmentprogression/jobtracker_test.go | 9 +++++++-- .../evaluator/environmentprogression/passrate_test.go | 6 +++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/environmentprogression/jobtracker_test.go b/apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/environmentprogression/jobtracker_test.go index da3ceced4..5b8c8cb05 100644 --- a/apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/environmentprogression/jobtracker_test.go +++ b/apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/environmentprogression/jobtracker_test.go @@ -941,9 +941,14 @@ func TestReleaseTargetJobTracker_GetSuccessPercentageSatisfiedAt_NoReleaseTarget tracker := NewReleaseTargetJobTracker(ctx, mock, env, version, nil, false) tracker.ReleaseTargets = []oapi.ReleaseTarget{} - // With no release targets, should return zero time + // Vacuous truth: 0/0 targets successful is treated as 100% pass, satisfied at version creation. satisfiedAt := tracker.GetSuccessPercentageSatisfiedAt(50.0) - assert.True(t, satisfiedAt.IsZero(), "expected zero satisfiedAt with no release targets") + assert.Equal( + t, + version.CreatedAt, + satisfiedAt, + "expected satisfiedAt to equal version.CreatedAt with no release targets", + ) } func TestReleaseTargetJobTracker_GetSuccessPercentageSatisfiedAt_NoSuccessfulJobs(t *testing.T) { diff --git a/apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/environmentprogression/passrate_test.go b/apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/environmentprogression/passrate_test.go index baf708015..3552481bb 100644 --- a/apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/environmentprogression/passrate_test.go +++ b/apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/environmentprogression/passrate_test.go @@ -461,9 +461,9 @@ func TestPassRateEvaluator_NoReleaseTargets(t *testing.T) { } result := eval.Evaluate(ctx, scope) - // With no release targets, success percentage is 0% - assert.False(t, result.Allowed, "expected denied with no release targets") - assert.Contains(t, result.Message, "Success rate 0.0% below required 50.0%") + // Vacuous truth: 0/0 release targets is treated as 100% pass rate. + assert.True(t, result.Allowed, "expected allowed with no release targets (vacuous truth)") + assert.Contains(t, result.Message, "Success rate 100.0% meets required 50.0%") } // TestPassRateEvaluator_CustomSuccessStatuses tests that custom success statuses can be used. From ec90dd9317620e4128bca877792c690f42079ba3 Mon Sep 17 00:00:00 2001 From: Aditya Choudhari Date: Thu, 23 Apr 2026 10:28:21 -0700 Subject: [PATCH 3/3] lint --- .../evaluator/environmentprogression/jobtracker_test.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/environmentprogression/jobtracker_test.go b/apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/environmentprogression/jobtracker_test.go index 5b8c8cb05..96e779a5e 100644 --- a/apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/environmentprogression/jobtracker_test.go +++ b/apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/environmentprogression/jobtracker_test.go @@ -77,7 +77,13 @@ func TestReleaseTargetJobTracker_GetSuccessPercentage_NoTargets(t *testing.T) { tracker := NewReleaseTargetJobTracker(ctx, mock, env, version, nil, false) percentage := tracker.GetSuccessPercentage() - assert.InDelta(t, float32(100.0), percentage, 0, "expected 100%% success with no targets (vacuous truth)") + assert.InDelta( + t, + float32(100.0), + percentage, + 0, + "expected 100%% success with no targets (vacuous truth)", + ) } func TestReleaseTargetJobTracker_GetSuccessPercentage_WithSuccesses(t *testing.T) {