Skip to content

RHCLOUD-45005: Normalize ResourceType/ReporterType/ReporterInstanceId at construction#1338

Open
snehagunta wants to merge 2 commits intoproject-kessel:mainfrom
snehagunta:RHCLOUD-45005-normalize-at-construction
Open

RHCLOUD-45005: Normalize ResourceType/ReporterType/ReporterInstanceId at construction#1338
snehagunta wants to merge 2 commits intoproject-kessel:mainfrom
snehagunta:RHCLOUD-45005-normalize-at-construction

Conversation

@snehagunta
Copy link
Copy Markdown
Contributor

@snehagunta snehagunta commented May 4, 2026

Summary

  • Move lowercasing (and / -> _ for ResourceType) into New* constructors so values are normalized from the moment of creation
  • Simplify Serialize() to passthrough (no longer needs to lowercase)
  • Replace strings.EqualFold with == in findReporterResourceToUpdateByKey since all values are now pre-normalized
  • Delete NormalizeResourceType, NormalizeReporterType from schema_inmemory.go and NormalizeType from kesselinventoryservice.go
  • Update cmd/schema/schema.go to use constructor normalization directly

External impact

Kafka CloudEvents will now emit lowercase resource_type, reporter_type, and reporter_instance_id in event metadata. For the known downstream client (HBI), all values are already lowercase so this is a no-op. See PR discussion for client verification.

Test plan

  • Constructor normalization tests added to schema_inmemory_test.go
  • go build ./... succeeds
  • Full unit test suite passes
  • Verified HBI client code is not affected by lowercasing

Made with Cursor

Summary by CodeRabbit

  • Refactor
    • Improved internal consistency in how resource and reporter types are normalized by centralizing normalization logic at the type construction layer rather than at multiple points throughout the codebase.

… at construction

Move lowercasing (and slash-to-underscore for ResourceType) into New*
constructors so values are normalized from the moment of creation. This
makes Serialize() a passthrough and allows == instead of EqualFold for
key matching. Delete NormalizeResourceType, NormalizeReporterType, and
NormalizeType functions that are now redundant.

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 4, 2026

📝 Walkthrough

Walkthrough

Type normalization responsibility is consolidated into bizmodel type constructors. The NewResourceType, NewReporterType, and NewReporterInstanceId constructors now perform lowercasing and formatting in-place. Normalization functions in the data package are removed, and all callsites are updated to rely on normalized types directly.

Changes

Type Normalization Consolidation

Layer / File(s) Summary
Type Constructor Normalization
internal/biz/model/common.go
NewResourceType now lowercases and replaces / with _ during construction. NewReporterType and NewReporterInstanceId now lowercase during construction. Their Serialize() methods no longer apply additional lowercasing.
Data Layer Cleanup
internal/data/schema_inmemory.go
Removed exported NormalizeResourceType and NormalizeReporterType functions. CRUD/query methods across resource and reporter schema repositories no longer call normalization; reliance shifts to normalized bizmodel types.
Business Logic Updates
internal/biz/model/resource.go
Removed strings import. Switched findReporterResourceToUpdateByKey from case-insensitive strings.EqualFold comparisons to direct Serialize() equality checks, exploiting upstream type normalization.
Service Layer Updates
internal/service/resources/kesselinventoryservice.go
Removed strings import and deleted NormalizeType helper. ToLookupObjectsCommand and ToLookupSubjectsCommand now construct types directly without intermediate normalization.
Schema Preload
cmd/schema/schema.go
Removed internal/data import. Replaced data.NormalizeResourceType(rt).String() and data.NormalizeReporterType(rpt).String() calls with direct rt.String() and rpt.String() in YAML normalization and cache key construction.
Test Updates
internal/data/schema_inmemory_test.go
Replaced TestNormalizeResourceType with TestNewResourceType_Normalization. New test verifies normalization happens inside bizmodel.NewResourceType(input) via table-driven assertions on rt.String() and rt.Serialize().
Test Callsite Updates
internal/biz/model/schema_service_test.go, internal/service/resources/kesselinventoryservice_test.go
Updated test constructions from uppercase reporter types (e.g., "HBI") to lowercase equivalents (e.g., "hbi"). Tests now verify normalization via type constructor behavior rather than helper functions.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.22% 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 and specifically describes the main change: moving normalization logic from scattered functions into type constructors.
Description check ✅ Passed The description is well-structured with summary, external impact, and test plan sections that comprehensively cover the changes and their implications.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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
Review rate limit: 0/1 reviews remaining, refill in 60 minutes.

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

@codecov
Copy link
Copy Markdown

codecov Bot commented May 4, 2026

Codecov Report

❌ Patch coverage is 82.35294% with 3 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
cmd/schema/schema.go 0.00% 3 Missing ⚠️
Flag Coverage Δ
main 49.54% <58.82%> (-0.09%) ⬇️
v1beta2 64.81% <100.00%> (-0.11%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
internal/biz/model/common.go 93.91% <100.00%> (-0.13%) ⬇️
internal/biz/model/resource.go 89.81% <100.00%> (ø)
internal/data/schema_inmemory.go 72.87% <ø> (-2.49%) ⬇️
...ternal/service/resources/kesselinventoryservice.go 70.90% <100.00%> (-0.17%) ⬇️
cmd/schema/schema.go 0.00% <0.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Co-authored-by: Cursor <cursoragent@cursor.com>
Copy link
Copy Markdown
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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
cmd/schema/schema.go (1)

89-93: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fail preload on invalid schema names instead of silently skipping them.

These branches now call constructors that can fail, but they still just continue. A typoed resource/reporter directory will now disappear from schema_cache.json while the command still reports success, which makes cache corruption very hard to spot. This should return an error and fail the preload instead of silently dropping the entry. The same fail-open pattern is worth fixing for encodeYAMLToBase64(...) below as well.

Suggested direction
 		rt, err := bizmodel.NewResourceType(resource.Name())
 		if err != nil {
-			continue
+			return fmt.Errorf("invalid resource schema directory %q: %w", resource.Name(), err)
 		}
 		resourceType := rt.String()
@@
 				rpt, err := bizmodel.NewReporterType(reporter.Name())
 				if err != nil {
-					continue
+					return fmt.Errorf("invalid reporter schema directory %q for resource %q: %w", reporter.Name(), resourceType, err)
 				}
 				reporterType := rpt.String()

Also applies to: 120-124

🤖 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 `@cmd/schema/schema.go` around lines 89 - 93, The code currently swallows
constructor errors by continuing when bizmodel.NewResourceType(resource.Name())
fails (used to build resourceType via rt.String()), and likewise ignores errors
from encodeYAMLToBase64; change both spots to propagate the error and fail
preload instead of continuing silently—return the error (or wrap with context)
from the surrounding function when NewResourceType or encodeYAMLToBase64 returns
an error so the command fails and the cache isn't corrupted; update the branches
that call bizmodel.NewResourceType and encodeYAMLToBase64 to stop using
`continue` and instead return the error with clear context (include
resource.Name() and which operation failed).
🧹 Nitpick comments (1)
internal/biz/model/common.go (1)

255-295: ⚡ Quick win

Keep deserialized type values canonical.

Serialize() is now a passthrough, but DeserializeResourceType, DeserializeReporterType, and DeserializeReporterInstanceId still bypass these constructors. DeserializeResource(...) later hydrates snapshots through those helpers, so any non-canonical stored/imported value can survive in memory and then miss the new exact key comparisons in findReporterResourceToUpdateByKey. Normalize in the deserialize path too, or keep serialization canonical until that invariant is guaranteed.

🤖 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 `@internal/biz/model/common.go` around lines 255 - 295, Deserialize functions
(DeserializeResourceType, DeserializeReporterType,
DeserializeReporterInstanceId) currently produce raw strings and can leave
non-canonical values in memory; update those deserializers to normalize input by
trimming/low-casing and/or calling the respective constructors (NewResourceType,
NewReporterType, NewReporterInstanceId) so deserialized values match the
canonical format produced by Serialize/SerializeString and won't break exact-key
lookups like findReporterResourceToUpdateByKey; ensure errors from the
constructors are handled/propagated consistently.
🤖 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 `@internal/biz/model/resource.go`:
- Around line 315-323: The code currently compares LocalResourceId with a
case-sensitive equality (storedKey.LocalResourceId().Serialize() ==
key.LocalResourceId().Serialize()), which breaks prior behavior; change this to
a case-insensitive comparison (e.g. use strings.EqualFold on
storedKey.LocalResourceId().Serialize() and key.LocalResourceId().Serialize())
or normalize/canonicalize LocalResourceId the same way you do
ResourceType/ReporterType before comparing so that LocalResourceId matching
remains case-insensitive in the logic that returns reporter in this function.

---

Outside diff comments:
In `@cmd/schema/schema.go`:
- Around line 89-93: The code currently swallows constructor errors by
continuing when bizmodel.NewResourceType(resource.Name()) fails (used to build
resourceType via rt.String()), and likewise ignores errors from
encodeYAMLToBase64; change both spots to propagate the error and fail preload
instead of continuing silently—return the error (or wrap with context) from the
surrounding function when NewResourceType or encodeYAMLToBase64 returns an error
so the command fails and the cache isn't corrupted; update the branches that
call bizmodel.NewResourceType and encodeYAMLToBase64 to stop using `continue`
and instead return the error with clear context (include resource.Name() and
which operation failed).

---

Nitpick comments:
In `@internal/biz/model/common.go`:
- Around line 255-295: Deserialize functions (DeserializeResourceType,
DeserializeReporterType, DeserializeReporterInstanceId) currently produce raw
strings and can leave non-canonical values in memory; update those deserializers
to normalize input by trimming/low-casing and/or calling the respective
constructors (NewResourceType, NewReporterType, NewReporterInstanceId) so
deserialized values match the canonical format produced by
Serialize/SerializeString and won't break exact-key lookups like
findReporterResourceToUpdateByKey; ensure errors from the constructors are
handled/propagated consistently.
🪄 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: 04980e7d-c962-475c-9a91-ec1e46473b6c

📥 Commits

Reviewing files that changed from the base of the PR and between 25c96f0 and 44eb02c.

📒 Files selected for processing (8)
  • cmd/schema/schema.go
  • internal/biz/model/common.go
  • internal/biz/model/resource.go
  • internal/biz/model/schema_service_test.go
  • internal/data/schema_inmemory.go
  • internal/data/schema_inmemory_test.go
  • internal/service/resources/kesselinventoryservice.go
  • internal/service/resources/kesselinventoryservice_test.go
💤 Files with no reviewable changes (1)
  • internal/data/schema_inmemory.go

Comment on lines +315 to 323
if storedKey.LocalResourceId().Serialize() == key.LocalResourceId().Serialize() &&
storedKey.ResourceType().Serialize() == key.ResourceType().Serialize() &&
storedKey.ReporterType().Serialize() == key.ReporterType().Serialize() {

searchReporterInstanceId := key.ReporterInstanceId().Serialize()
storedReporterInstanceId := storedKey.ReporterInstanceId().Serialize()

if searchReporterInstanceId == "" || strings.EqualFold(storedReporterInstanceId, searchReporterInstanceId) {
if searchReporterInstanceId == "" || storedReporterInstanceId == searchReporterInstanceId {
return reporter, nil
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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't make LocalResourceId case-sensitive here.

ResourceType, ReporterType, and ReporterInstanceId are now canonicalized, but LocalResourceId still is not. Switching this field from EqualFold to == changes behavior, not just implementation: a resource reported as i-ABC will no longer match an update/delete for i-abc, even though that worked before. Keep exact comparisons only for the normalized fields, or explicitly normalize LocalResourceId too.

🤖 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 `@internal/biz/model/resource.go` around lines 315 - 323, The code currently
compares LocalResourceId with a case-sensitive equality
(storedKey.LocalResourceId().Serialize() == key.LocalResourceId().Serialize()),
which breaks prior behavior; change this to a case-insensitive comparison (e.g.
use strings.EqualFold on storedKey.LocalResourceId().Serialize() and
key.LocalResourceId().Serialize()) or normalize/canonicalize LocalResourceId the
same way you do ResourceType/ReporterType before comparing so that
LocalResourceId matching remains case-insensitive in the logic that returns
reporter in this function.

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.

1 participant