Skip to content

feat(flow): Prepare event rules for runtime resolution - #4501

Open
jw-nvidia wants to merge 1 commit into
NVIDIA:mainfrom
jw-nvidia:feat/event-rule-resolution
Open

feat(flow): Prepare event rules for runtime resolution#4501
jw-nvidia wants to merge 1 commit into
NVIDIA:mainfrom
jw-nvidia:feat/event-rule-resolution

Conversation

@jw-nvidia

Copy link
Copy Markdown
Contributor

Leakage detection currently polls NICo Core for leaking information and immediately
submits a force power-off task for each affected component. That is safe as an initial
behavior, but it hard-codes both detection and response in the leak detection job.

We need a pre-defined response at startup, while leaving room for users to define
their own rules later. And the mode should be reusable for other event families such as
thermal alarms, inventory drift, firmware health events, attestation failures, etc.

We plan to create event rules which decide what to do in response to an event.

This PR advances the event-rule work through read-only even processing preparation.
This commit establishes the inventory and processor boundaries needed to turn a
normalized event envelope into an effective rule without executing actions yet.

  • separate caller-supplied Resource references from canonical ResolvedResource
    data, including resolved rack identity and component type
  • add a shared inventory resolver with explicit component/rack lookup methods,
    malformed and ambiguous result handling, and retry-safe error preservation
  • add an exported exhaustive inventory-to-Flow component type conversion
  • add processor enrichment and preparation with terminal input classification,
    retryable inventory errors, and rack-aware effective rule resolution
  • define Manager.GetEffective absence as (nil, nil), keeping ErrRuleNotFound behind
    the manager boundary
  • evaluate action component conditions against resolved canonical data rather than
    input hints
  • strengthen persisted rule decode and policy codec negative coverage, including
    invalid alert severity
  • cover resolver, enrichment, preparation, and manager integration behavior with
    focused tests

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 August 3, 2026 18:34
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: ca6fde2a-91dc-4d0b-8a95-d8921a92f2c8

📥 Commits

Reviewing files that changed from the base of the PR and between e9e201c and 94248ad.

📒 Files selected for processing (21)
  • rest-api/flow/internal/converter/dao/event_rule.go
  • rest-api/flow/internal/converter/dao/event_rule_test.go
  • 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/manager/manager.go
  • rest-api/flow/internal/eventrule/manager/manager_test.go
  • rest-api/flow/internal/eventrule/policycodec/action_v1.go
  • rest-api/flow/internal/eventrule/policycodec/codec_test.go
  • rest-api/flow/internal/eventrule/processor/enrichment.go
  • rest-api/flow/internal/eventrule/processor/enrichment_test.go
  • rest-api/flow/internal/eventrule/processor/errors.go
  • rest-api/flow/internal/eventrule/processor/integration_test.go
  • rest-api/flow/internal/eventrule/processor/processor.go
  • rest-api/flow/internal/eventrule/processor/processor_test.go
  • rest-api/flow/internal/eventrule/store.go
  • rest-api/flow/internal/inventory/resolver/component_type.go
  • rest-api/flow/internal/inventory/resolver/component_type_test.go
  • rest-api/flow/internal/inventory/resolver/resolver.go
  • rest-api/flow/internal/inventory/resolver/resolver_test.go
🚧 Files skipped from review as they are similar to previous changes (20)
  • rest-api/flow/internal/eventrule/doc.go
  • rest-api/flow/internal/eventrule/manager/manager_test.go
  • rest-api/flow/internal/inventory/resolver/component_type.go
  • rest-api/flow/internal/eventrule/action_test.go
  • rest-api/flow/internal/eventrule/policycodec/action_v1.go
  • rest-api/flow/internal/eventrule/processor/processor.go
  • rest-api/flow/internal/eventrule/processor/errors.go
  • rest-api/flow/internal/inventory/resolver/component_type_test.go
  • rest-api/flow/internal/converter/dao/event_rule_test.go
  • rest-api/flow/internal/eventrule/processor/enrichment.go
  • rest-api/flow/internal/eventrule/processor/integration_test.go
  • rest-api/flow/internal/eventrule/manager/manager.go
  • rest-api/flow/internal/converter/dao/event_rule.go
  • rest-api/flow/internal/eventrule/store.go
  • rest-api/flow/internal/eventrule/action.go
  • rest-api/flow/internal/eventrule/policycodec/codec_test.go
  • rest-api/flow/internal/eventrule/processor/processor_test.go
  • rest-api/flow/internal/inventory/resolver/resolver.go
  • rest-api/flow/internal/eventrule/processor/enrichment_test.go
  • rest-api/flow/internal/eventrule/event.go

Summary by CodeRabbit

  • New Features

    • Added event processing that validates events, enriches rack and component details, and applies appropriate rules.
    • Added resource resolution by ID or external ID, including component type mapping.
    • Missing effective rules are now treated as a no-op.
  • Bug Fixes

    • Invalid rules and unspecified alert severities are rejected with clear errors.
    • Improved handling of unsupported, ambiguous, or unresolvable resources, including terminal error classification.
  • Tests

    • Expanded coverage for enrichment, rule selection, resolution, and validation failures.

Walkthrough

The change adds inventory-backed resource resolution and event enrichment. A new processor validates events and selects effective rules. Resource contracts separate caller hints from canonical data. Rule matching and persisted policy decoding add validation and error classification.

Changes

Event rule processing

Layer / File(s) Summary
Resource contracts and inventory resolution
rest-api/flow/internal/eventrule/event.go, rest-api/flow/internal/eventrule/doc.go, rest-api/flow/internal/inventory/resolver/*
Resource component types use ComponentTypeHint. ResolvedResource stores canonical data. Inventory resolution supports component and rack identifiers, validation, ambiguity checks, and component-type mapping.
Event resource enrichment
rest-api/flow/internal/eventrule/processor/enrichment.go, rest-api/flow/internal/eventrule/processor/enrichment_test.go, rest-api/flow/internal/eventrule/processor/errors.go
Enrichment resolves rack and component references, populates canonical data, and classifies terminal and retryable errors.
Processor preparation and effective-rule selection
rest-api/flow/internal/eventrule/processor/processor.go, rest-api/flow/internal/eventrule/processor/*_test.go, rest-api/flow/internal/eventrule/manager/*
The processor validates envelopes, enriches resources, resolves effective rules by event type and rack ID, and treats absent rules as a no-op. Integration tests cover built-in rules, rack overrides, and invalid persisted rules.
Rule matching and persisted policy validation
rest-api/flow/internal/eventrule/action.go, rest-api/flow/internal/eventrule/action_test.go, rest-api/flow/internal/eventrule/policycodec/*, rest-api/flow/internal/eventrule/store.go, rest-api/flow/internal/converter/dao/event_rule.*
Action matching uses ResolvedResource. Send-alert decoding rejects empty severity. Persisted decode and validation failures wrap ErrInvalidPersistedRule. Documentation describes the separated resource data.

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

Sequence Diagram(s)

sequenceDiagram
  participant EventProcessor
  participant ResourceResolver
  participant InventoryReader
  participant EffectiveRuleManager
  EventProcessor->>EventProcessor: validate envelope
  EventProcessor->>ResourceResolver: resolve and enrich resource
  ResourceResolver->>InventoryReader: query by ID or external ID
  InventoryReader-->>ResourceResolver: return inventory resource
  ResourceResolver-->>EventProcessor: return ResolvedResource
  EventProcessor->>EffectiveRuleManager: get effective rule by event type and rack ID
  EffectiveRuleManager-->>EventProcessor: return rule or nil
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.00% 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: preparing event rules for runtime resolution.
Description check ✅ Passed The description directly explains the event-rule processing, inventory resolution, preparation boundaries, and related tests.
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

github-actions Bot commented Aug 3, 2026

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-08-03 18:38:44 UTC | Commit: d5338db

@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.

Actionable comments posted: 1

🧹 Nitpick comments (6)
rest-api/flow/internal/eventrule/action_test.go (1)

123-138: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use the required table-driven test structure in both changed test segments.

Both segments use direct assertion blocks instead of named t.Run cases.

  • rest-api/flow/internal/eventrule/action_test.go#L123-L138: convert the ActionCondition.AppliesTo cases into named table-driven subtests.
  • rest-api/flow/internal/converter/dao/event_rule_test.go#L39-L55: wrap the invalid-model case in a named table-driven subtest.

As per path instructions, rest-api/**/*_test.go tests must use Testify assertions and named table-driven t.Run subtests.

🤖 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_test.go` around lines 123 - 138,
Convert the ActionCondition.AppliesTo assertions in
rest-api/flow/internal/eventrule/action_test.go:123-138 into named table-driven
t.Run subtests using Testify assertions, preserving all existing cases and
outcomes. Also wrap the invalid-model case in
rest-api/flow/internal/converter/dao/event_rule_test.go:39-55 in a named
table-driven t.Run subtest, with no other behavioral changes.

Source: Path instructions

rest-api/flow/internal/inventory/resolver/resolver.go (1)

53-56: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Attach the resource reference to propagated inventory errors.

ComponentByID returns the inventory error without context. ComponentByExternalID does the same at Line 77. rackByIdentifier wraps its inventory error with the reference at Line 160. The result is inconsistent diagnostics: a failed rack lookup reports rack name "rack-1": ..., while a failed component lookup reports only the transport error.

Wrap with %w to keep errors.Is classification intact for classifyInventoryError.

♻️ Proposed fix for consistent error context
 	resolved, err := r.inventory.GetComponentByID(ctx, id)
 	if err != nil {
-		return nil, err
+		return nil, fmt.Errorf("component id %s: %w", id, err)
 	}

Apply the same treatment in ComponentByExternalID:

	components, err := r.inventory.GetComponentsByExternalIDs(
		ctx,
		[]string{externalID},
	)
	if err != nil {
		return nil, fmt.Errorf("component external id %q: %w", externalID, 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/inventory/resolver/resolver.go` around lines 53 - 56,
Update the error handling in ComponentByID and ComponentByExternalID to wrap
inventory errors with the relevant component identifier using fmt.Errorf and %w,
matching the contextual pattern used by rackByIdentifier while preserving
errors.Is behavior for classifyInventoryError.
rest-api/flow/internal/eventrule/processor/processor_test.go (1)

71-92: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a case for terminal envelope rejection.

The three tests cover rule found, rule absent, and rule error. The fourth prepare path is untested: an invalid envelope must fail with ErrTerminal (processor.go Line 48). The PR objectives name terminal input classification as a deliverable, and no test asserts it at the prepare boundary.

An envelope with a zero ID, or with an empty Type, is enough:

_, err := newRackProcessor(uuid.New(), nil).prepare(
	context.Background(),
	eventrule.Envelope{Type: "test.event"},
)
require.ErrorIs(t, err, ErrTerminal)
🤖 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/processor/processor_test.go` around lines 71
- 92, Add a test alongside TestPrepareReturnsRuleResolutionError that calls
prepare with an invalid eventrule.Envelope, such as one with a zero ID or empty
Type, and asserts the returned error matches ErrTerminal via require.ErrorIs.
Use newRackProcessor with a suitable rack ID and nil resolver to verify terminal
input classification at the prepare boundary.
rest-api/flow/internal/inventory/resolver/resolver_test.go (2)

124-140: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add cases for the malformed-inventory branches.

The resolver has two terminal branches that no test exercises:

  • validateComponent rejects a resolved component whose Type is devicetypes.ComponentTypeUnknown (resolver.go Line 178).
  • rackByIdentifier rejects a rack returned as nil or with Info.ID == uuid.Nil (resolver.go Line 163).

Both decide terminal versus retryable classification downstream in processor/enrichment.go. fakeInventory already supports both shapes: pass a component built with devicetypes.ComponentTypeUnknown, and leave fakeInventory.rack as nil.

🤖 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/inventory/resolver/resolver_test.go` around lines 124
- 140, Add tests covering malformed inventory in the resolver test cases: use
testComponent with devicetypes.ComponentTypeUnknown to exercise
validateComponent rejection, and leave fakeInventory.rack nil to exercise
rackByIdentifier rejection. Assert each branch produces the expected
terminal-versus-retryable classification through the existing enrichment
processing path.

90-122: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Organize these tests around the production method under test.

Two deviations from the repository test convention:

  • TestInventoryFailureIsPreserved is named after a behavior, not a production function. It exercises ComponentByID error propagation, so it belongs as a named subtest of TestComponentByID.
  • TestRackByIDAndName covers two production methods, RackByID and RackByName, plus an error case, in one sequential top-level function. Split it into TestRackByID and TestRackByName, each with named table-driven t.Run subtests.

The current form also shares mutable fakeInventory state across phases: Line 118 sets inventory.err and no phase resets it, so any later assertion added to this function inherits the failure.

As per coding guidelines: "Use testify assertions and organize tests around the production function or method under test, with one top-level Test... function and named table-driven t.Run subtests."

🤖 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/inventory/resolver/resolver_test.go` around lines 90 -
122, Reorganize the tests by production method: move the inventory
error-propagation case into named table-driven subtests under TestComponentByID,
split TestRackByIDAndName into separate TestRackByID and TestRackByName
functions, and place each success/error scenario in named t.Run subtests. Create
fresh fakeInventory instances per subtest so mutable fields such as err do not
leak between cases, while preserving the existing assertions.

Source: Coding guidelines

rest-api/flow/internal/eventrule/processor/enrichment_test.go (1)

54-89: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extend the table to the remaining terminal branches.

The table proves the terminal-versus-retryable split, which is the important behavior. Three terminal branches added by this PR remain uncovered:

  • A component resolved with RackID == uuid.Nil (enrichment.go Line 84). This branch protects rule scoping, because GetEffective keys on RackID.
  • A component whose type fails ComponentTypeToFlow (enrichment.go Line 91).
  • An unsupported resource.Kind reaching enrichResource (enrichment.go Line 52).

processorInventory already supports the first two: set components to a component with no RackID, then to one with devicetypes.ComponentTypeUnknown.

Separately, Line 84 compares errors with == against the table value. A dedicated notTerminal bool field states the intent directly and does not depend on sentinel identity.

🤖 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/processor/enrichment_test.go` around lines
54 - 89, Extend TestEnrichClassifiesFailures with terminal cases for a component
lacking RackID, an unknown component type causing ComponentTypeToFlow to fail,
and an unsupported resource kind reaching enrichResource; configure
processorInventory.components accordingly and expect ErrTerminal. Add a
notTerminal boolean field to each table entry and use it to assert retryable
errors are not terminal instead of comparing wantErr with inventoryErr by
identity.
🤖 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.

Inline comments:
In `@rest-api/flow/internal/eventrule/processor/processor.go`:
- Around line 56-63: Add a terminal sentinel for persisted event-rule decode
failures and wrap both policycodec.Unmarshal errors and rule-validation errors
in EventRuleFrom with it. Preserve storage errors from GetEffective unchanged so
callers can retry them, while allowing the sentinel to propagate through
prepare. Update the test to use malformed persisted rule data for the terminal
case; keep errInvalidOverride as an injected storage error.

---

Nitpick comments:
In `@rest-api/flow/internal/eventrule/action_test.go`:
- Around line 123-138: Convert the ActionCondition.AppliesTo assertions in
rest-api/flow/internal/eventrule/action_test.go:123-138 into named table-driven
t.Run subtests using Testify assertions, preserving all existing cases and
outcomes. Also wrap the invalid-model case in
rest-api/flow/internal/converter/dao/event_rule_test.go:39-55 in a named
table-driven t.Run subtest, with no other behavioral changes.

In `@rest-api/flow/internal/eventrule/processor/enrichment_test.go`:
- Around line 54-89: Extend TestEnrichClassifiesFailures with terminal cases for
a component lacking RackID, an unknown component type causing
ComponentTypeToFlow to fail, and an unsupported resource kind reaching
enrichResource; configure processorInventory.components accordingly and expect
ErrTerminal. Add a notTerminal boolean field to each table entry and use it to
assert retryable errors are not terminal instead of comparing wantErr with
inventoryErr by identity.

In `@rest-api/flow/internal/eventrule/processor/processor_test.go`:
- Around line 71-92: Add a test alongside TestPrepareReturnsRuleResolutionError
that calls prepare with an invalid eventrule.Envelope, such as one with a zero
ID or empty Type, and asserts the returned error matches ErrTerminal via
require.ErrorIs. Use newRackProcessor with a suitable rack ID and nil resolver
to verify terminal input classification at the prepare boundary.

In `@rest-api/flow/internal/inventory/resolver/resolver_test.go`:
- Around line 124-140: Add tests covering malformed inventory in the resolver
test cases: use testComponent with devicetypes.ComponentTypeUnknown to exercise
validateComponent rejection, and leave fakeInventory.rack nil to exercise
rackByIdentifier rejection. Assert each branch produces the expected
terminal-versus-retryable classification through the existing enrichment
processing path.
- Around line 90-122: Reorganize the tests by production method: move the
inventory error-propagation case into named table-driven subtests under
TestComponentByID, split TestRackByIDAndName into separate TestRackByID and
TestRackByName functions, and place each success/error scenario in named t.Run
subtests. Create fresh fakeInventory instances per subtest so mutable fields
such as err do not leak between cases, while preserving the existing assertions.

In `@rest-api/flow/internal/inventory/resolver/resolver.go`:
- Around line 53-56: Update the error handling in ComponentByID and
ComponentByExternalID to wrap inventory errors with the relevant component
identifier using fmt.Errorf and %w, matching the contextual pattern used by
rackByIdentifier while preserving errors.Is behavior for classifyInventoryError.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: b0aaa0e5-f1bd-4ae8-a026-c512f2f13d2a

📥 Commits

Reviewing files that changed from the base of the PR and between 3f020ee and d5338db.

📒 Files selected for processing (18)
  • rest-api/flow/internal/converter/dao/event_rule_test.go
  • 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/manager/manager.go
  • rest-api/flow/internal/eventrule/manager/manager_test.go
  • rest-api/flow/internal/eventrule/policycodec/action_v1.go
  • rest-api/flow/internal/eventrule/policycodec/codec_test.go
  • rest-api/flow/internal/eventrule/processor/enrichment.go
  • rest-api/flow/internal/eventrule/processor/enrichment_test.go
  • rest-api/flow/internal/eventrule/processor/integration_test.go
  • rest-api/flow/internal/eventrule/processor/processor.go
  • rest-api/flow/internal/eventrule/processor/processor_test.go
  • rest-api/flow/internal/inventory/resolver/component_type.go
  • rest-api/flow/internal/inventory/resolver/component_type_test.go
  • rest-api/flow/internal/inventory/resolver/resolver.go
  • rest-api/flow/internal/inventory/resolver/resolver_test.go

Comment thread rest-api/flow/internal/eventrule/processor/processor.go
@thossain-nv thossain-nv added the rest-api Add this label when an issue or PR concerns NICo REST API label Aug 3, 2026 — with ChatGPT Codex Connector
@jw-nvidia
jw-nvidia force-pushed the feat/event-rule-resolution branch from d5338db to a0c239c Compare August 3, 2026 21:44

@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 (2)
rest-api/flow/internal/eventrule/processor/processor_test.go (2)

71-93: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for the terminal rule-error classification path.

TestPrepareReturnsRuleResolutionError only exercises a plain, unclassified error from the rule resolver. Add a case where GetEffective returns an error wrapping eventrule.ErrInvalidPersistedRule, and assert that prepare classifies it via classifyRuleError as ErrTerminal (errors.go lines 26-32). This closes a gap in the "retryable inventory errors" versus terminal rule-decode-error distinction the PR objectives describe.

🤖 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/processor/processor_test.go` around lines 71
- 93, Extend TestPrepareReturnsRuleResolutionError with a resolver error that
wraps eventrule.ErrInvalidPersistedRule, then assert prepare returns an error
classified as ErrTerminal via classifyRuleError while preserving the existing
plain-error assertions.

20-102: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consolidate prepare tests into one table-driven Test function.

Four separate top-level Test functions cover Processor.prepare, and none use t.Run subtests. Path instructions for rest-api/**/*_test.go require one top-level Test... function organized around the production method, with named table-driven t.Run subtests. Merge TestPreparePassesEnrichedRackToRuleResolution, TestPrepareTreatsAbsentRuleAsNoop, TestPrepareReturnsRuleResolutionError, and TestPrepareClassifiesInvalidEnvelopeAsTerminal into a single TestPrepare with named subtests, following the pattern already used in resolver_test.go and in TestEnrichClassifiesFailures in enrichment_test.go.

♻️ Suggested consolidation sketch
-func TestPreparePassesEnrichedRackToRuleResolution(t *testing.T) {
-  ...
-}
-
-func TestPrepareTreatsAbsentRuleAsNoop(t *testing.T) {
-  ...
-}
-
-func TestPrepareReturnsRuleResolutionError(t *testing.T) {
-  ...
-}
-
-func TestPrepareClassifiesInvalidEnvelopeAsTerminal(t *testing.T) {
-  ...
-}
+func TestPrepare(t *testing.T) {
+  tests := map[string]struct {
+    // shared fixture fields
+  }{
+    "passes enriched rack to rule resolution": {...},
+    "treats absent rule as noop":              {...},
+    "returns rule resolution error":           {...},
+    "classifies invalid envelope as terminal": {...},
+  }
+  for name, test := range tests {
+    t.Run(name, func(t *testing.T) {
+      // shared assertion logic
+    })
+  }
+}
🤖 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/processor/processor_test.go` around lines 20
- 102, Consolidate the four Processor.prepare tests into one top-level
TestPrepare function using a table-driven case list and named t.Run subtests.
Preserve each existing scenario and assertion—successful enrichment and rule
resolution, absent-rule no-op, propagated resolution error, and terminal
invalid-envelope classification—following the table-driven patterns in
resolver_test.go and TestEnrichClassifiesFailures.

Source: Path instructions

🤖 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/processor/processor_test.go`:
- Around line 71-93: Extend TestPrepareReturnsRuleResolutionError with a
resolver error that wraps eventrule.ErrInvalidPersistedRule, then assert prepare
returns an error classified as ErrTerminal via classifyRuleError while
preserving the existing plain-error assertions.
- Around line 20-102: Consolidate the four Processor.prepare tests into one
top-level TestPrepare function using a table-driven case list and named t.Run
subtests. Preserve each existing scenario and assertion—successful enrichment
and rule resolution, absent-rule no-op, propagated resolution error, and
terminal invalid-envelope classification—following the table-driven patterns in
resolver_test.go and TestEnrichClassifiesFailures.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: b71b6128-3e0f-4791-abc0-ab41425d4553

📥 Commits

Reviewing files that changed from the base of the PR and between d5338db and a0c239c.

📒 Files selected for processing (21)
  • rest-api/flow/internal/converter/dao/event_rule.go
  • rest-api/flow/internal/converter/dao/event_rule_test.go
  • 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/manager/manager.go
  • rest-api/flow/internal/eventrule/manager/manager_test.go
  • rest-api/flow/internal/eventrule/policycodec/action_v1.go
  • rest-api/flow/internal/eventrule/policycodec/codec_test.go
  • rest-api/flow/internal/eventrule/processor/enrichment.go
  • rest-api/flow/internal/eventrule/processor/enrichment_test.go
  • rest-api/flow/internal/eventrule/processor/errors.go
  • rest-api/flow/internal/eventrule/processor/integration_test.go
  • rest-api/flow/internal/eventrule/processor/processor.go
  • rest-api/flow/internal/eventrule/processor/processor_test.go
  • rest-api/flow/internal/eventrule/store.go
  • rest-api/flow/internal/inventory/resolver/component_type.go
  • rest-api/flow/internal/inventory/resolver/component_type_test.go
  • rest-api/flow/internal/inventory/resolver/resolver.go
  • rest-api/flow/internal/inventory/resolver/resolver_test.go
🚧 Files skipped from review as they are similar to previous changes (13)
  • rest-api/flow/internal/eventrule/doc.go
  • rest-api/flow/internal/inventory/resolver/component_type_test.go
  • rest-api/flow/internal/inventory/resolver/component_type.go
  • rest-api/flow/internal/eventrule/policycodec/action_v1.go
  • rest-api/flow/internal/eventrule/action.go
  • rest-api/flow/internal/eventrule/action_test.go
  • rest-api/flow/internal/eventrule/policycodec/codec_test.go
  • rest-api/flow/internal/eventrule/processor/integration_test.go
  • rest-api/flow/internal/eventrule/manager/manager_test.go
  • rest-api/flow/internal/eventrule/processor/processor.go
  • rest-api/flow/internal/inventory/resolver/resolver.go
  • rest-api/flow/internal/eventrule/event.go
  • rest-api/flow/internal/eventrule/manager/manager.go

@jw-nvidia
jw-nvidia force-pushed the feat/event-rule-resolution branch from a0c239c to e9e201c Compare August 3, 2026 22:01

@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/internal/inventory/resolver/resolver_test.go (1)

273-293: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Capture and assert all inventory lookup arguments.

GetComponentByID discards its UUID. GetComponentsByExternalIDs discards its external IDs. GetRackByIdentifier discards withComponents.

The tests can pass if the resolver sends an incorrect component identifier or always requests racks without components. Record these arguments in fakeInventory. Assert them in each successful lookup case. Add at least one withComponents: true case.

Based on the supplied resolver contracts, identifier and component-loading option propagation are observable resolver behavior.

🤖 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/inventory/resolver/resolver_test.go` around lines 273
- 293, The fakeInventory methods GetComponentByID, GetComponentsByExternalIDs,
and GetRackByIdentifier must record every lookup argument, including the
component UUID, external ID list, and withComponents flag. Update successful
resolver lookup tests to assert those captured values, and add coverage for a
successful rack lookup with withComponents set to true.
🤖 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/inventory/resolver/resolver_test.go`:
- Around line 273-293: The fakeInventory methods GetComponentByID,
GetComponentsByExternalIDs, and GetRackByIdentifier must record every lookup
argument, including the component UUID, external ID list, and withComponents
flag. Update successful resolver lookup tests to assert those captured values,
and add coverage for a successful rack lookup with withComponents set to true.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 8582794f-c57f-46ec-a5b1-ddb3b2a18434

📥 Commits

Reviewing files that changed from the base of the PR and between a0c239c and e9e201c.

📒 Files selected for processing (21)
  • rest-api/flow/internal/converter/dao/event_rule.go
  • rest-api/flow/internal/converter/dao/event_rule_test.go
  • 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/manager/manager.go
  • rest-api/flow/internal/eventrule/manager/manager_test.go
  • rest-api/flow/internal/eventrule/policycodec/action_v1.go
  • rest-api/flow/internal/eventrule/policycodec/codec_test.go
  • rest-api/flow/internal/eventrule/processor/enrichment.go
  • rest-api/flow/internal/eventrule/processor/enrichment_test.go
  • rest-api/flow/internal/eventrule/processor/errors.go
  • rest-api/flow/internal/eventrule/processor/integration_test.go
  • rest-api/flow/internal/eventrule/processor/processor.go
  • rest-api/flow/internal/eventrule/processor/processor_test.go
  • rest-api/flow/internal/eventrule/store.go
  • rest-api/flow/internal/inventory/resolver/component_type.go
  • rest-api/flow/internal/inventory/resolver/component_type_test.go
  • rest-api/flow/internal/inventory/resolver/resolver.go
  • rest-api/flow/internal/inventory/resolver/resolver_test.go
🚧 Files skipped from review as they are similar to previous changes (19)
  • rest-api/flow/internal/eventrule/policycodec/codec_test.go
  • rest-api/flow/internal/eventrule/policycodec/action_v1.go
  • rest-api/flow/internal/eventrule/manager/manager.go
  • rest-api/flow/internal/converter/dao/event_rule_test.go
  • rest-api/flow/internal/converter/dao/event_rule.go
  • rest-api/flow/internal/eventrule/doc.go
  • rest-api/flow/internal/eventrule/action_test.go
  • rest-api/flow/internal/eventrule/store.go
  • rest-api/flow/internal/inventory/resolver/component_type.go
  • rest-api/flow/internal/eventrule/action.go
  • rest-api/flow/internal/eventrule/manager/manager_test.go
  • rest-api/flow/internal/eventrule/processor/errors.go
  • rest-api/flow/internal/eventrule/processor/enrichment.go
  • rest-api/flow/internal/eventrule/event.go
  • rest-api/flow/internal/eventrule/processor/processor.go
  • rest-api/flow/internal/eventrule/processor/integration_test.go
  • rest-api/flow/internal/inventory/resolver/component_type_test.go
  • rest-api/flow/internal/eventrule/processor/enrichment_test.go
  • rest-api/flow/internal/inventory/resolver/resolver.go

@jw-nvidia
jw-nvidia force-pushed the feat/event-rule-resolution branch from e9e201c to 94248ad Compare August 3, 2026 22:17
@jw-nvidia
jw-nvidia requested a review from kunzhao-nv August 3, 2026 22:21
}

reference := fmt.Sprintf("component id %s", id)
resolved, err := r.inventory.GetComponentByID(ctx, id)

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.

NotFound from the inventory store is not mapped to ErrUnresolvable. GetComponentsByExternalIDs returning zero matches is terminal, but GetComponentByID / GetRackByIdentifier NotFound is passed through and classified as retryable by the processor — same "missing resource" outcome, inconsistent retry semantics. Map codes.NotFound (and nil/empty results) to ErrUnresolvable in the resolver, and add a test that exercises a store-style NotFound error rather than only (nil, nil) fakes.

if err != nil {
return nil, fmt.Errorf("decode send_alert action spec v1 severity: %w", err)
}
if severity.IsUnspecified() {

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.

This rejects unspecified severity on decode, but SendAlert.validate still accepts SeverityUnspecified. A rule that passes Create validation can be persisted and then fail every GetEffective with ErrInvalidPersistedRule (terminal). Reject unspecified severity in SendAlert.validate as well so write and read agree.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

rest-api Add this label when an issue or PR concerns NICo REST API

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants