Skip to content

Conversation

@adityachoudhari26
Copy link
Contributor

@adityachoudhari26 adityachoudhari26 commented Dec 5, 2025

Summary by CodeRabbit

  • Bug Fixes
    • Fixed gradual rollout start time handling to properly respect skipped policies. Rollouts now start immediately when approval or environment progression policies are marked as skipped, rather than waiting for normal policy evaluation.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 5, 2025

Walkthrough

Refactors gradual rollout evaluator's start-time calculation by extracting two new helper methods for approval and environment progression rules that incorporate skip-aware logic. The main function now aggregates policy skips and delegates per-rule start-time computations to these helpers.

Changes

Cohort / File(s) Summary
Gradual rollout evaluator refactoring
apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/gradualrollout/gradualrollout.go
Extracts two new helper methods—getStartTimeFromApprovalRule and getStartTimeFromEnvironmentProgressionRule—that encapsulate skip-aware start-time determination. Refactors getRolloutStartTime to aggregate skips and delegate per-rule decisions to helpers instead of inline evaluation. Adds skip sorting logic and early nil handling for evaluators.
Gradual rollout test suite
apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/gradualrollout/gradualrollout_test.go
Adds two new test cases: TestGradualRolloutEvaluator_IfApprovalPolicySkipped_RolloutStartsImmediately and TestGradualRolloutEvaluator_IfEnvironmentProgressionPolicySkipped_RolloutStartsImmediately, validating immediate rollout behavior when respective policies are skipped across multiple release targets.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Key areas requiring attention:

  • Skip aggregation and sorting logic in getRolloutStartTime to ensure all policy skips for the target are correctly collected and ordered
  • Helper method implementations—verify that nil evaluators and nil satisfied times are handled correctly
  • Test coverage: confirm test setups properly reflect skip scenarios and assert correct immediate-start behavior across multiple targets

Possibly related PRs

  • ctrlplanedev/ctrlplane#706: Introduced the GradualRolloutEvaluator; this PR refactors its core start-time logic with skip-aware behavior.

Poem

🐰 Skip-aware rollouts, oh what a sight,
Helpers extracted to polish the light,
When policies skip, we start right away—
No waiting, no fuss, just roll into play! 🎢✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title directly describes the main change: implementing skip-aware logic in the gradual rollout evaluator to respect policy skips, which is the core functionality introduced in the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch gradual-rollout-policy-skips

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/gradualrollout/gradualrollout.go (1)

89-163: Consider extracting shared skip-handling logic to reduce duplication.

Both getStartTimeFromApprovalRule and getStartTimeFromEnvironmentProgressionRule share identical skip-filtering and time-calculation logic (lines 90-112 and 128-150). The only difference is the evaluator instantiation.

A possible refactor could extract the common logic into a helper that accepts a function parameter for creating the evaluator:

+func (e *GradualRolloutEvaluator) getStartTimeFromSkipsOrEvaluator(
+	ctx context.Context,
+	rule *oapi.PolicyRule,
+	scope evaluator.EvaluatorScope,
+	allSkips []*oapi.PolicySkip,
+	createEvaluator func() evaluator.Evaluator,
+) *time.Time {
+	skips := make([]*oapi.PolicySkip, 0)
+	for _, skip := range allSkips {
+		if skip.RuleId == rule.Id {
+			skips = append(skips, skip)
+		}
+	}
+
+	if len(skips) > 0 {
+		sort.Slice(skips, func(i, j int) bool {
+			return skips[i].CreatedAt.After(skips[j].CreatedAt)
+		})
+		latestSkipCreatedAt := skips[0].CreatedAt
+		if latestSkipCreatedAt.After(scope.Version.CreatedAt) {
+			return &latestSkipCreatedAt
+		}
+		return &scope.Version.CreatedAt
+	}
+
+	eval := createEvaluator()
+	if eval == nil {
+		return nil
+	}
+	result := eval.Evaluate(ctx, scope)
+	if !result.Allowed || result.SatisfiedAt == nil {
+		return nil
+	}
+	return result.SatisfiedAt
+}

This would simplify both helpers to one-liners calling the shared function with different evaluator factories.

apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/gradualrollout/gradualrollout_test.go (1)

616-843: Consider adding a test for skip created after version.

The current tests cover the case where skip and version are created at the same time. Consider adding a test for the scenario where a skip is created after the version already exists - in this case, the rollout should start at the skip's CreatedAt time, not the version's.

Example test scenario:

  • Version created at baseTime
  • Skip created at baseTime + 1 hour
  • Expected rollout_start_time should be baseTime + 1 hour

This would verify the latestSkipCreatedAt.After(scope.Version.CreatedAt) branch in the implementation.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between cc88957 and 097583a.

📒 Files selected for processing (2)
  • apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/gradualrollout/gradualrollout.go (4 hunks)
  • apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/gradualrollout/gradualrollout_test.go (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
apps/workspace-engine/**/*.go

📄 CodeRabbit inference engine (apps/workspace-engine/CLAUDE.md)

apps/workspace-engine/**/*.go: Do not add extraneous inline comments that state the obvious
Do not add comments that simply restate what the code does
Do not add comments for standard Go patterns (e.g., noting WaitGroup or semaphore usage)
Write comments that explain why, document complex logic/algorithms, provide non-obvious context, include TODO/FIXME, and document exported functions/types/methods

Files:

  • apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/gradualrollout/gradualrollout.go
  • apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/gradualrollout/gradualrollout_test.go
apps/workspace-engine/**/*_test.go

📄 CodeRabbit inference engine (apps/workspace-engine/CLAUDE.md)

Follow the existing test structure used in *_test.go files

Files:

  • apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/gradualrollout/gradualrollout_test.go
🧠 Learnings (5)
📓 Common learnings
Learnt from: adityachoudhari26
Repo: ctrlplanedev/ctrlplane PR: 658
File: apps/workspace-engine/pkg/engine/policy/rules/environment-version-rollout/rollout_start_time.go:65-80
Timestamp: 2025-08-19T22:58:15.170Z
Learning: In the environment-version-rollout rule's rollout start time logic, the code intentionally returns the latest ApprovedAt time (first non-nil record from records ordered by updatedAt) rather than the earliest. This is because the goal is to find the latest approval that caused all the rules to pass. While the complete logic for determining "the latest that caused all rules to pass" would be too complex, this approximation works well given that the UI prevents approving if all rules are already passing.
Learnt from: adityachoudhari26
Repo: ctrlplanedev/ctrlplane PR: 637
File: packages/events/src/kafka/client.ts:10-16
Timestamp: 2025-08-01T04:41:41.345Z
Learning: User adityachoudhari26 prefers not to add null safety checks for required environment variables when they are guaranteed to be present in their deployment configuration, similar to their preference for simplicity over defensive programming in test code.
Learnt from: adityachoudhari26
Repo: ctrlplanedev/ctrlplane PR: 601
File: e2e/tests/api/policies/retry-policy.spec.ts:23-24
Timestamp: 2025-06-24T23:52:50.732Z
Learning: The user adityachoudhari26 prefers not to add null safety checks or defensive programming in test code, particularly in e2e tests, as they prioritize simplicity and focus on the main functionality being tested rather than comprehensive error handling within the test itself.
📚 Learning: 2025-08-19T22:58:15.170Z
Learnt from: adityachoudhari26
Repo: ctrlplanedev/ctrlplane PR: 658
File: apps/workspace-engine/pkg/engine/policy/rules/environment-version-rollout/rollout_start_time.go:65-80
Timestamp: 2025-08-19T22:58:15.170Z
Learning: In the environment-version-rollout rule's rollout start time logic, the code intentionally returns the latest ApprovedAt time (first non-nil record from records ordered by updatedAt) rather than the earliest. This is because the goal is to find the latest approval that caused all the rules to pass. While the complete logic for determining "the latest that caused all rules to pass" would be too complex, this approximation works well given that the UI prevents approving if all rules are already passing.

Applied to files:

  • apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/gradualrollout/gradualrollout.go
  • apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/gradualrollout/gradualrollout_test.go
📚 Learning: 2025-08-12T18:13:54.630Z
Learnt from: CR
Repo: ctrlplanedev/ctrlplane PR: 0
File: apps/workspace-engine/CLAUDE.md:0-0
Timestamp: 2025-08-12T18:13:54.630Z
Learning: Applies to apps/workspace-engine/**/*.go : Write comments that explain why, document complex logic/algorithms, provide non-obvious context, include TODO/FIXME, and document exported functions/types/methods

Applied to files:

  • apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/gradualrollout/gradualrollout.go
📚 Learning: 2025-08-12T18:13:54.630Z
Learnt from: CR
Repo: ctrlplanedev/ctrlplane PR: 0
File: apps/workspace-engine/CLAUDE.md:0-0
Timestamp: 2025-08-12T18:13:54.630Z
Learning: Applies to apps/workspace-engine/pkg/model/selector/**/*_test.go : Test validation and matching logic separately for condition types

Applied to files:

  • apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/gradualrollout/gradualrollout.go
📚 Learning: 2025-08-12T18:13:54.630Z
Learnt from: CR
Repo: ctrlplanedev/ctrlplane PR: 0
File: apps/workspace-engine/CLAUDE.md:0-0
Timestamp: 2025-08-12T18:13:54.630Z
Learning: Applies to apps/workspace-engine/**/*_test.go : Follow the existing test structure used in *_test.go files

Applied to files:

  • apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/gradualrollout/gradualrollout_test.go
🧬 Code graph analysis (1)
apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/gradualrollout/gradualrollout.go (7)
apps/workspace-engine/pkg/oapi/oapi.gen.go (4)
  • PolicyRule (471-481)
  • PolicySkip (484-514)
  • Id (80-80)
  • CreatedAt (78-78)
apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/evaulator.go (1)
  • EvaluatorScope (25-29)
apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/versionselector/versionselector.go (1)
  • NewEvaluator (29-39)
apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/deploymentdependency/deployment_dependency.go (1)
  • NewEvaluator (24-34)
apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/approval/approval.go (1)
  • NewEvaluator (21-30)
apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/environmentprogression/environmentprogression.go (1)
  • NewEvaluator (29-41)
apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/retry/retry.go (1)
  • NewEvaluator (32-77)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: tests
  • GitHub Check: build (linux/amd64)
  • GitHub Check: workspace-engine-tests
  • GitHub Check: Typecheck
  • GitHub Check: Lint
🔇 Additional comments (4)
apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/gradualrollout/gradualrollout.go (2)

7-7: LGTM!

The sort import is correctly added and used for sorting policy skips by CreatedAt.


183-209: LGTM!

The integration of policy skips into getRolloutStartTime is well-structured:

  • Fetches all relevant skips once and passes them to helper methods
  • Correctly delegates per-rule start-time calculation to the new helpers
  • Preserves the existing logic for aggregating the latest satisfied time across rules

The skip-aware behavior aligns with the PR objective of respecting policy skips in gradual rollout.

apps/workspace-engine/pkg/workspace/releasemanager/policy/evaluator/gradualrollout/gradualrollout_test.go (2)

616-724: LGTM!

The test correctly verifies that when an approval policy is skipped:

  1. The rollout starts at baseTime (version creation time)
  2. Subsequent positions follow the expected linear rollout schedule (60s intervals)

The test follows the existing file structure and naming conventions.


726-843: LGTM!

The test correctly verifies that when an environment progression policy is skipped:

  1. The rollout starts immediately at baseTime
  2. The rollout schedule follows the expected linear intervals

Note: The test doesn't need to create the staging environment because the skip bypasses rule evaluation entirely, which is the intended behavior.

@adityachoudhari26 adityachoudhari26 merged commit 1cdf00b into main Dec 5, 2025
9 checks passed
@adityachoudhari26 adityachoudhari26 deleted the gradual-rollout-policy-skips branch December 5, 2025 03:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants