Skip to content

feat(flow): Add event rule domain model#3881

Merged
jw-nvidia merged 1 commit into
NVIDIA:mainfrom
jw-nvidia:feat/event-rule
Jul 23, 2026
Merged

feat(flow): Add event rule domain model#3881
jw-nvidia merged 1 commit into
NVIDIA:mainfrom
jw-nvidia:feat/event-rule

Conversation

@jw-nvidia

@jw-nvidia jw-nvidia commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Flow needs to respond to operational events such as hardware coolant leaks, so we
add a new feature for the users to define rules to handle various types of events.
This PR is the first one for the new feature, it introduces a small, typed "eventrule"
domain as the foundation for event processing.

Related issues

Type of Change

  • Add - New feature or capability
  • Change - Changes in existing functionality
  • Fix - Bug fixes
  • Remove - Removed features or deprecated functionality
  • Internal - Internal changes (refactoring, tests, docs, etc.)

Breaking Changes

  • This PR contains breaking changes

Testing

  • Unit tests added/updated
  • Integration tests added/updated
  • Manual testing performed
  • No testing required (docs, internal refactor, etc.)

Additional Notes

@jw-nvidia
jw-nvidia requested a review from a team as a code owner July 23, 2026 00:21
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Summary by CodeRabbit

  • New Features

    • Added event-rule models supporting validated events, resources, policies, rules, conditions, and actions.
    • Added actions for submitting tasks, sending alerts, or taking no action.
    • Added deduplication settings and duplicate-action detection.
    • Added a built-in leakage response that submits forced power-off tasks for affected components.
    • Added validation for supported component types and task operation codes.
  • Tests

    • Added comprehensive validation coverage for events, rules, policies, actions, and operation codes.
  • Documentation

    • Added package-level documentation describing event-rule behavior and validation.

Walkthrough

Introduces the event-rule domain model, validation helpers, typed actions, policy and rule validation, task operation-code checks, and a built-in leakage rule that submits a force power-off task.

Changes

Event Rule Domain

Layer / File(s) Summary
Event and validation contracts
rest-api/flow/internal/eventrule/{doc.go,event.go,validation.go}, rest-api/flow/pkg/types/enums.go, rest-api/flow/pkg/types/enums_test.go, rest-api/flow/internal/eventrule/event_test.go
Defines normalized envelopes, resources, supported event values, identifier validation, component-type validation, and corresponding tests and package documentation.
Task operation compatibility
rest-api/flow/internal/task/common/operation_codes.go, rest-api/flow/internal/task/common/operation_codes_test.go, rest-api/flow/internal/task/operations/operations.go
Adds operation-code validation by task type, centralizes the inject-expectation opcode, and tests valid and invalid mappings.
Action, policy, and rule validation
rest-api/flow/internal/eventrule/action.go, rest-api/flow/internal/eventrule/policy.go, rest-api/flow/internal/eventrule/rule.go, rest-api/flow/internal/eventrule/action_test.go
Adds typed action specifications, condition matching, policy deduplication, rule metadata validation, and coverage for valid and invalid domain values.
Built-in leakage response
rest-api/flow/internal/eventrule/leakage/leakage.go, rest-api/flow/internal/eventrule/leakage/leakage_test.go
Adds an enabled leakage rule with one affected-components force power-off action and verifies its identifiers, origin, event type, and target strategy.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant LeakageRule
  participant EventRule
  participant Policy
  participant SubmitTask
  LeakageRule->>EventRule: construct enabled leakage rule
  EventRule->>Policy: embed one action
  Policy->>SubmitTask: validate force power-off operation
  SubmitTask-->>Policy: return validation result
  Policy-->>EventRule: return policy validation result
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: introducing the event rule domain model for Flow.
Description check ✅ Passed The description is directly aligned with the changeset and accurately describes the new typed eventrule foundation.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@github-actions

Copy link
Copy Markdown

🔐 TruffleHog Secret Scan

No secrets or credentials found!

Your code has been scanned for 700+ types of secrets and credentials. All clear! 🎉

🔗 View scan details

🕐 Last updated: 2026-07-23 00:29:56 UTC | Commit: c077f76

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (4)
rest-api/flow/internal/eventrule/event_test.go (1)

14-25: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use explicit test cases for payload validation.

Keep valid and invalid payloads as independent table entries instead of mutating one envelope. As per coding guidelines, “Write tests in table-driven style; group parser, validator, conversion, and similar input variants using the repository's scenario or explicit-case helpers where appropriate.”

Proposed refactor
 func TestEnvelopeValidatePayload(t *testing.T) {
-	envelope := Envelope{
-		ID:       uuid.New(),
-		Type:     "test.event",
-		Resource: Resource{Kind: ResourceKindRack},
-		Payload:  json.RawMessage(`{"value":42}`),
+	tests := map[string]struct {
+		payload json.RawMessage
+		wantErr string
+	}{
+		"valid JSON":   {payload: json.RawMessage(`{"value":42}`)},
+		"invalid JSON": {payload: json.RawMessage(`{"value":`)}, wantErr: "payload must be valid JSON"},
 	}
-	require.NoError(t, envelope.Validate())
 
-	envelope.Payload = json.RawMessage(`{"value":`)
-	require.ErrorContains(t, envelope.Validate(), "payload must be valid JSON")
+	for name, test := range tests {
+		t.Run(name, func(t *testing.T) {
+			envelope := Envelope{
+				ID:       uuid.New(),
+				Type:     "test.event",
+				Resource: Resource{Kind: ResourceKindRack},
+				Payload:  test.payload,
+			}
+			if test.wantErr != "" {
+				require.ErrorContains(t, envelope.Validate(), test.wantErr)
+				return
+			}
+			require.NoError(t, envelope.Validate())
+		})
+	}
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rest-api/flow/internal/eventrule/event_test.go` around lines 14 - 25,
Refactor TestEnvelopeValidatePayload into explicit table-driven test cases, with
separate valid and invalid payload entries rather than mutating a shared
envelope. Keep the existing validation assertions and expected invalid-payload
error message, using the repository’s established scenario or explicit-case
helper if available.

Source: Coding guidelines

rest-api/flow/internal/eventrule/leakage/leakage_test.go (1)

21-25: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Pin the operation code/type in the assertion.

The test verifies TargetStrategy but not OperationType/OperationCode. Given this rule submits a forced hardware power-off in response to a leak, a regression that silently downgrades the operation (e.g., to a graceful power-off) would slip through undetected.

✅ Proposed strengthening
 	spec, ok := rule.Actions[0].Spec.(eventrule.SubmitTask)
 	require.True(t, ok)
 	assert.Equal(t, eventrule.TargetStrategyAffectedComponents, spec.TargetStrategy)
+	assert.Equal(t, taskcommon.TaskTypePowerControl, spec.OperationType)
+	assert.Equal(t, taskcommon.OpCodePowerControlForcePowerOff, spec.OperationCode)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rest-api/flow/internal/eventrule/leakage/leakage_test.go` around lines 21 -
25, Strengthen the assertion block for the SubmitTask spec in the leakage rule
test by verifying the expected forced hardware power-off
OperationType/OperationCode in addition to TargetStrategy. Use the existing
eventrule constants for that operation and preserve the current type and
action-count assertions.
rest-api/flow/internal/eventrule/leakage/leakage.go (1)

32-38: 🩺 Stability & Availability | 🔵 Trivial

Confirm queue latency is acceptable for a safety-critical fallback.

The built-in leakage response uses ConflictStrategyQueue for its force-power-off task. Since ConflictStrategy currently only offers queue or reject (Lines 76-88 of action.go) with no priority/preemption option, a conflicting in-flight task would delay this emergency shutdown rather than pre-empt it. Reject would be worse (the safety action is dropped entirely), so Queue is the right choice today — but it's worth confirming with the Flow task-orchestration layer that queued conflict resolution doesn't introduce unacceptable delay for leak-driven power-offs, or whether a future priority/pre-emption strategy is needed.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rest-api/flow/internal/eventrule/leakage/leakage.go` around lines 32 - 38,
Validate with the Flow task-orchestration layer that ConflictStrategyQueue in
the leakage response’s SubmitTask preserves acceptable latency for the
force-power-off safety action during conflicts. Keep the current queue strategy
unless orchestration requirements mandate a supported priority or pre-emption
strategy; do not switch to ConflictStrategyReject, which would drop the
shutdown.
rest-api/flow/internal/eventrule/action.go (1)

21-47: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Extract the repeated "non-nil but empty" slice guard.

The empty-slice check is duplicated verbatim for Severities (Lines 22-24) and ComponentTypes (Lines 36-38). A small generic helper would remove the duplication and make it trivial to apply the same rule to future condition fields.

♻️ Proposed refactor
+func validateNonEmptyIfSet[T any](name string, values []T) error {
+	if values != nil && len(values) == 0 {
+		return fmt.Errorf("%s cannot be an empty array", name)
+	}
+	return nil
+}
+
 func (c ActionCondition) validate() error {
-	if c.Severities != nil && len(c.Severities) == 0 {
-		return fmt.Errorf("severities cannot be an empty array")
+	if err := validateNonEmptyIfSet("severities", c.Severities); err != nil {
+		return err
 	}
 	...
-	if c.ComponentTypes != nil && len(c.ComponentTypes) == 0 {
-		return fmt.Errorf("component_types cannot be an empty array")
+	if err := validateNonEmptyIfSet("component_types", c.ComponentTypes); err != nil {
+		return err
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rest-api/flow/internal/eventrule/action.go` around lines 21 - 47, In
ActionCondition.validate, extract the duplicated non-nil-but-empty slice check
for Severities and ComponentTypes into a small generic helper, then reuse it for
both fields while preserving their existing field-specific error messages and
validation behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@rest-api/flow/internal/eventrule/action.go`:
- Around line 21-47: In ActionCondition.validate, extract the duplicated
non-nil-but-empty slice check for Severities and ComponentTypes into a small
generic helper, then reuse it for both fields while preserving their existing
field-specific error messages and validation behavior.

In `@rest-api/flow/internal/eventrule/event_test.go`:
- Around line 14-25: Refactor TestEnvelopeValidatePayload into explicit
table-driven test cases, with separate valid and invalid payload entries rather
than mutating a shared envelope. Keep the existing validation assertions and
expected invalid-payload error message, using the repository’s established
scenario or explicit-case helper if available.

In `@rest-api/flow/internal/eventrule/leakage/leakage_test.go`:
- Around line 21-25: Strengthen the assertion block for the SubmitTask spec in
the leakage rule test by verifying the expected forced hardware power-off
OperationType/OperationCode in addition to TargetStrategy. Use the existing
eventrule constants for that operation and preserve the current type and
action-count assertions.

In `@rest-api/flow/internal/eventrule/leakage/leakage.go`:
- Around line 32-38: Validate with the Flow task-orchestration layer that
ConflictStrategyQueue in the leakage response’s SubmitTask preserves acceptable
latency for the force-power-off safety action during conflicts. Keep the current
queue strategy unless orchestration requirements mandate a supported priority or
pre-emption strategy; do not switch to ConflictStrategyReject, which would drop
the shutdown.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 08910621-e569-4a92-bf57-e93403c25177

📥 Commits

Reviewing files that changed from the base of the PR and between 862b66a and c077f76.

📒 Files selected for processing (15)
  • rest-api/flow/internal/eventrule/action.go
  • rest-api/flow/internal/eventrule/action_test.go
  • rest-api/flow/internal/eventrule/doc.go
  • rest-api/flow/internal/eventrule/event.go
  • rest-api/flow/internal/eventrule/event_test.go
  • rest-api/flow/internal/eventrule/leakage/leakage.go
  • rest-api/flow/internal/eventrule/leakage/leakage_test.go
  • rest-api/flow/internal/eventrule/policy.go
  • rest-api/flow/internal/eventrule/rule.go
  • rest-api/flow/internal/eventrule/validation.go
  • rest-api/flow/internal/task/common/operation_codes.go
  • rest-api/flow/internal/task/common/operation_codes_test.go
  • rest-api/flow/internal/task/operations/operations.go
  • rest-api/flow/pkg/types/enums.go
  • rest-api/flow/pkg/types/enums_test.go

type OperationCode string

// Inject-expectation operation codes.
const OpCodeInjectExpectation = "inject_expectation"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Would better to make the type restriction stronger:

const OpCodeInjectExpectation OperationCode = "inject_expectation"

const (
	OpCodePowerControlPowerOn       OperationCode = "power_on"
	...
)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Don't enforce the type since the current operation codes are defined as string. Don't want to touch other codes in this PR. Will leave this enforcement and refactor of existing codes in a future PR.

OperationType: taskcommon.TaskTypePowerControl,
OperationCode: taskcommon.OpCodePowerControlForcePowerOff,
TargetStrategy: eventrule.TargetStrategyAffectedComponents,
ConflictStrategy: eventrule.ConflictStrategyQueue,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

In the current implementation, there are only two options: queue and reject. When a leak is detected, it chooses queue, meaning it waits for the current task to finish. Should we consider a more advanced approach where the current task should be interrupted immediately instead?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes if achievable. This PR only lays out the foundation for event processing. This kind of fine-tunes and improvements will be done in the future after we complete the framework.

return ActionTypeSendAlert
}

func (s SendAlert) validate() error {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

SendAlert allows an empty severity, but ActionCondition rejects it — intentional, or should SendAlert.validate() require a severity too?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is intentional. SubmitTask is much heavier than SendAlert, so we don't allow users to define a rule to trigger SubmitTask for an event with unknown severity. For SendAlert, it is OK.

@kunzhao-nv kunzhao-nv left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Leaving #3881 (comment) as a TODO

- Introduce the focused internal/eventrule domain for event envelopes,
  resources, rules, policies, deduplication, typed actions, action conditions,
  and named target strategies.
- Add immutable leakage defaults using the new rule model. Share component-type
  validation and define typed task operation codes with task-type-specific
  validation, including the inject-expectation operation code.
- Add unit coverage for event-rule validation, leakage defaults, component
  types, and operation-code compatibility.
@github-actions

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
rest-api/flow/pkg/types/enums.go (1)

25-38: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Consolidate the component-type validation contract.

ComponentType.Validate() duplicates the allowlist in rest-api/flow/internal/eventrule/event.go Lines 26-38. Because these are distinct package types, a future component type could pass validation here but fail during event normalization. Make one type/constant set authoritative, or centralize validation and convert explicitly at the package boundary.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rest-api/flow/pkg/types/enums.go` around lines 25 - 38, Consolidate the
supported component-type allowlist used by ComponentType.Validate and event
normalization in rest-api/flow/internal/eventrule/event.go so only one
definition is authoritative. Update the other validation path to reuse that
authority, adding an explicit conversion at the package boundary where the types
differ, and ensure newly supported types cannot pass one validator while failing
the other.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@rest-api/flow/pkg/types/enums.go`:
- Around line 25-38: Consolidate the supported component-type allowlist used by
ComponentType.Validate and event normalization in
rest-api/flow/internal/eventrule/event.go so only one definition is
authoritative. Update the other validation path to reuse that authority, adding
an explicit conversion at the package boundary where the types differ, and
ensure newly supported types cannot pass one validator while failing the other.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 07bce9b0-6fdf-47cc-bd27-90c52d31e376

📥 Commits

Reviewing files that changed from the base of the PR and between c077f76 and 7cb0c4c.

📒 Files selected for processing (15)
  • rest-api/flow/internal/eventrule/action.go
  • rest-api/flow/internal/eventrule/action_test.go
  • rest-api/flow/internal/eventrule/doc.go
  • rest-api/flow/internal/eventrule/event.go
  • rest-api/flow/internal/eventrule/event_test.go
  • rest-api/flow/internal/eventrule/leakage/leakage.go
  • rest-api/flow/internal/eventrule/leakage/leakage_test.go
  • rest-api/flow/internal/eventrule/policy.go
  • rest-api/flow/internal/eventrule/rule.go
  • rest-api/flow/internal/eventrule/validation.go
  • rest-api/flow/internal/task/common/operation_codes.go
  • rest-api/flow/internal/task/common/operation_codes_test.go
  • rest-api/flow/internal/task/operations/operations.go
  • rest-api/flow/pkg/types/enums.go
  • rest-api/flow/pkg/types/enums_test.go
🚧 Files skipped from review as they are similar to previous changes (13)
  • rest-api/flow/internal/eventrule/rule.go
  • rest-api/flow/internal/eventrule/action_test.go
  • rest-api/flow/internal/task/operations/operations.go
  • rest-api/flow/internal/eventrule/validation.go
  • rest-api/flow/internal/eventrule/leakage/leakage.go
  • rest-api/flow/internal/eventrule/event_test.go
  • rest-api/flow/pkg/types/enums_test.go
  • rest-api/flow/internal/task/common/operation_codes_test.go
  • rest-api/flow/internal/task/common/operation_codes.go
  • rest-api/flow/internal/eventrule/policy.go
  • rest-api/flow/internal/eventrule/event.go
  • rest-api/flow/internal/eventrule/action.go
  • rest-api/flow/internal/eventrule/leakage/leakage_test.go

@jw-nvidia
jw-nvidia enabled auto-merge (squash) July 23, 2026 17:44
@jw-nvidia
jw-nvidia merged commit 2bf92a2 into NVIDIA:main Jul 23, 2026
120 checks passed
@jw-nvidia
jw-nvidia deleted the feat/event-rule branch July 23, 2026 19:12
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