Skip to content

feat(discovery): apply policy filtering to home feed#27

Merged
poyrazK merged 11 commits intomainfrom
feat/discovery-home-policy-filter
Apr 4, 2026
Merged

feat(discovery): apply policy filtering to home feed#27
poyrazK merged 11 commits intomainfrom
feat/discovery-home-policy-filter

Conversation

@poyrazK
Copy link
Copy Markdown
Owner

@poyrazK poyrazK commented Apr 4, 2026

Summary

  • extend GET /v1/discovery/home to accept optional countryCode and ageVerified policy context parameters with country code validation
  • filter blended home feed items through policy evaluation and return 503 POLICY_SERVICE_UNAVAILABLE if policy checks are unavailable
  • add controller/service tests for home feed policy filtering and update discovery home contract docs

Verification

  • mvn -pl discovery-service spotless:apply checkstyle:check
  • mvn -pl discovery-service test

Summary by CodeRabbit

  • New Features

    • Home discovery feed accepts optional countryCode (ISO 3166-1 alpha-2) and ageVerified parameters for regional/age-aware results
    • Policy-based filtering excludes blocked items from blended feed
  • Behavior Changes

    • Policy evaluation failures now return 503 Service Unavailable with a policy-specific error
  • Documentation

    • API docs updated to describe new params and new 503 status
  • Tests

    • Added tests for countryCode validation and policy-evaluation failure/filtering

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 4, 2026

Warning

Rate limit exceeded

@poyrazK has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 19 minutes and 30 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 19 minutes and 30 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0699e577-86b0-4f68-ba99-2704403feb04

📥 Commits

Reviewing files that changed from the base of the PR and between 75ce5d8 and e4f73da.

📒 Files selected for processing (2)
  • services/java/discovery-service/src/main/java/com/cloudmedia/discovery/api/validation/CountryCodeValidator.java
  • services/java/discovery-service/src/main/java/com/cloudmedia/discovery/policy/HttpPolicyEvaluationClient.java
📝 Walkthrough

Walkthrough

Adds optional countryCode and ageVerified query params to GET /v1/discovery/home, validates country codes, wires PolicyEvaluationClient into HomeFeedService to filter out policy-blocked items before blending, and returns 503 POLICY_SERVICE_UNAVAILABLE on policy evaluation failures.

Changes

Cohort / File(s) Summary
API Documentation
docs/contracts/rest-api-v1.md
Documented optional countryCode (ISO 3166-1 alpha-2 uppercase) and ageVerified params for GET /v1/discovery/home; added 503 status meaning for dependency unavailability (POLICY_SERVICE_UNAVAILABLE).
Controller
services/java/discovery-service/src/main/java/com/cloudmedia/discovery/api/discovery/DiscoveryController.java
Added optional countryCode (@ValidCountryCode) and ageVerified request params; forwards both to homeFeedService.homeFeed(...).
Service Core
services/java/discovery-service/src/main/java/com/cloudmedia/discovery/discovery/HomeFeedService.java
Injected PolicyEvaluationClient; extended homeFeed(...) signature to accept countryCode and ageVerified; added filterByPolicy(...) to call evaluateBatch(...) and exclude blocked items; maps policy errors to ApiException with HttpStatus.SERVICE_UNAVAILABLE / POLICY_SERVICE_UNAVAILABLE.
Policy Client API
services/java/discovery-service/src/main/java/com/cloudmedia/discovery/policy/PolicyEvaluationClient.java
Added default evaluateBatch(Collection<String>, String countryCode, Boolean ageVerified) returning ordered map of contentId→PolicyDecision, skipping nulls and deduplicating by first-seen id.
Validation
services/java/discovery-service/src/main/java/com/cloudmedia/discovery/api/validation/ValidCountryCode.java, .../CountryCodeValidator.java
Added @ValidCountryCode annotation and CountryCodeValidator enforcing null-or-two-uppercase-letter ISO codes from Locale.getISOCountries().
Controller Tests
services/java/discovery-service/src/test/java/com/cloudmedia/discovery/api/discovery/DiscoveryControllerTest.java
Added tests: invalid countryCode returns 400 VALIDATION_ERROR; policy evaluation failure returns 503 POLICY_SERVICE_UNAVAILABLE; updated test config and homeFeed test signature to include countryCode/ageVerified.
Service Tests
services/java/discovery-service/src/test/java/com/cloudmedia/discovery/discovery/HomeFeedServiceTest.java
Constructed HomeFeedService with PolicyEvaluationClient; added RecordingPolicyEvaluationClient test double; updated calls to include countryCode/ageVerified; added test asserting policy-blocked items are filtered and evaluated content IDs recorded.

Sequence Diagram

sequenceDiagram
    participant Client as Client
    participant Controller as DiscoveryController
    participant Service as HomeFeedService
    participant Search as SearchIndexReader
    participant Policy as PolicyEvaluationClient

    Client->>Controller: GET /v1/discovery/home (userId,size,countryCode,ageVerified)
    Controller->>Controller: validate `countryCode`
    Controller->>Service: homeFeed(userId,size,countryCode,ageVerified)
    Service->>Search: fetch candidate buckets
    Search-->>Service: candidate items
    Service->>Policy: evaluateBatch(contentIds,countryCode,ageVerified)
    Policy-->>Service: Map(contentId→PolicyDecision)
    loop per candidate item
        alt decision.allowed == true
            Service->>Service: include item
        else decision.allowed == false
            Service->>Service: exclude item
        end
    end
    Service-->>Controller: HomeFeedResponse(filtered items)
    Controller-->>Client: HTTP 200 (or 503 POLICY_SERVICE_UNAVAILABLE on policy error)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 I hop through feeds both near and wide,

two-letter codes tucked safe inside.
I query rules with a twitchy nose,
banish blocked hops where no carrot grows.
Hooray for tidy, filtered feeds—hip-hop! 🥕✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: applying policy filtering to the home feed. It is specific, directly related to the primary objective of the changeset.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/discovery-home-policy-filter

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
Copy Markdown

@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: 3

🧹 Nitpick comments (2)
services/java/discovery-service/src/test/java/com/cloudmedia/discovery/discovery/HomeFeedServiceTest.java (1)

19-25: Assert the forwarded policy context too.

RecordingPolicyEvaluationClient ignores countryCode and ageVerified, so these tests would still pass if HomeFeedService started calling evaluate(contentId, null, null) or swapped the arguments. Please record those parameters and assert them in at least one happy-path test.

Also applies to: 97-100

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@services/java/discovery-service/src/test/java/com/cloudmedia/discovery/discovery/HomeFeedServiceTest.java`
around lines 19 - 25, The test is not verifying that HomeFeedService.forwarded
the policy context (countryCode and ageVerified) to the policy evaluation;
update the RecordingPolicyEvaluationClient used in the test to capture the
evaluate(...) args (e.g., add fields like recordedCountryCodes and
recordedAgeVerifieds or a list of tuples when evaluate(contentId, countryCode,
ageVerified) is called) and then add assertions in the happy-path test that at
least one recorded invocation contains the expected countryCode ("US") and
ageVerified (true) alongside the recordedContentIds; ensure the
HomeFeedService.homeFeed invocation in the test still uses the same parameters
so the new assertions validate the correct argument forwarding.
services/java/discovery-service/src/test/java/com/cloudmedia/discovery/api/discovery/DiscoveryControllerTest.java (1)

48-52: Add the controller-level 503 case as well.

The PR introduces a new outward-facing POLICY_SERVICE_UNAVAILABLE response for GET /v1/discovery/home, but this suite only covers success and validation. Please add a MockMvc test that has HomeFeedService.homeFeed(...) fail and asserts 503 plus the serialized error code.

Also applies to: 54-83

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@services/java/discovery-service/src/test/java/com/cloudmedia/discovery/api/discovery/DiscoveryControllerTest.java`
around lines 48 - 52, Add a MockMvc test in DiscoveryControllerTest that
simulates HomeFeedService.homeFeed(...) failing and asserts the controller
returns HTTP 503 with the serialized error code POLICY_SERVICE_UNAVAILABLE: mock
the HomeFeedService.homeFeed call (using the same mock used in the suite) to
throw the service-level exception or otherwise produce the failure path the
controller maps to POLICY_SERVICE_UNAVAILABLE, then perform
get("/v1/discovery/home") via mockMvc and assert status().isServiceUnavailable()
and jsonPath("$.error.code").value("POLICY_SERVICE_UNAVAILABLE"); place this
alongside the existing validation and success tests so it covers the new
outward-facing 503 response.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/contracts/rest-api-v1.md`:
- Around line 132-137: Update the docs for the GET /v1/discovery/home endpoint
to document the new 503 response: add that the service may return HTTP 503 with
error code POLICY_SERVICE_UNAVAILABLE when policy evaluation fails (in addition
to the existing blended-feed behavior and filtering note), and also add this
503/POLICY_SERVICE_UNAVAILABLE to the HTTP status usage section so clients know
to retry or surface an appropriate error; reference the endpoint name GET
/v1/discovery/home and the error code POLICY_SERVICE_UNAVAILABLE when making the
additions.

In
`@services/java/discovery-service/src/main/java/com/cloudmedia/discovery/api/discovery/DiscoveryController.java`:
- Line 35: The current regexp in DiscoveryController for the countryCode request
param only enforces format and not real ISO 3166-1 alpha-2 membership; replace
it with a real allowlist or custom validator (e.g., create an annotation like
`@ValidCountryCode` with a CountryCodeValidator) or explicitly validate against
Locale.getISOCountries() (or a maintained Set of valid codes) inside the
controller method before passing countryCode to policy evaluation so values like
"ZZ" are rejected with a 400 and a clear message; reference the countryCode
parameter in DiscoveryController and add/annotate the new validator class
(CountryCodeValidator or similar) to centralize the check.

In
`@services/java/discovery-service/src/main/java/com/cloudmedia/discovery/discovery/HomeFeedService.java`:
- Around line 35-36: The current flow calls blend(candidates, resolvedSize) then
filterByPolicy(...), which truncates to resolvedSize before removing blocked
items and can leave the final feed short; update the logic so policy filtering
happens before the final trim or make blend policy-aware — either (a) run
filterByPolicy on the candidates (or apply policy rules inside blend) and then
call blend(...) with the already-filtered list, or (b) over-fetch by increasing
the count passed to blend (e.g., fetch >resolvedSize), then apply
filterByPolicy(blended, countryCode, ageVerified) and finally truncate to
resolvedSize when constructing the HomeFeedResponse; reference blend,
filterByPolicy, HomeFeedItem, HomeFeedResponse, resolvedSize, and candidates
when making the change.

---

Nitpick comments:
In
`@services/java/discovery-service/src/test/java/com/cloudmedia/discovery/api/discovery/DiscoveryControllerTest.java`:
- Around line 48-52: Add a MockMvc test in DiscoveryControllerTest that
simulates HomeFeedService.homeFeed(...) failing and asserts the controller
returns HTTP 503 with the serialized error code POLICY_SERVICE_UNAVAILABLE: mock
the HomeFeedService.homeFeed call (using the same mock used in the suite) to
throw the service-level exception or otherwise produce the failure path the
controller maps to POLICY_SERVICE_UNAVAILABLE, then perform
get("/v1/discovery/home") via mockMvc and assert status().isServiceUnavailable()
and jsonPath("$.error.code").value("POLICY_SERVICE_UNAVAILABLE"); place this
alongside the existing validation and success tests so it covers the new
outward-facing 503 response.

In
`@services/java/discovery-service/src/test/java/com/cloudmedia/discovery/discovery/HomeFeedServiceTest.java`:
- Around line 19-25: The test is not verifying that HomeFeedService.forwarded
the policy context (countryCode and ageVerified) to the policy evaluation;
update the RecordingPolicyEvaluationClient used in the test to capture the
evaluate(...) args (e.g., add fields like recordedCountryCodes and
recordedAgeVerifieds or a list of tuples when evaluate(contentId, countryCode,
ageVerified) is called) and then add assertions in the happy-path test that at
least one recorded invocation contains the expected countryCode ("US") and
ageVerified (true) alongside the recordedContentIds; ensure the
HomeFeedService.homeFeed invocation in the test still uses the same parameters
so the new assertions validate the correct argument forwarding.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: cd7e3d3c-0b10-4488-99fe-7e13da0d79ae

📥 Commits

Reviewing files that changed from the base of the PR and between 54f920a and a658ddb.

📒 Files selected for processing (5)
  • docs/contracts/rest-api-v1.md
  • services/java/discovery-service/src/main/java/com/cloudmedia/discovery/api/discovery/DiscoveryController.java
  • services/java/discovery-service/src/main/java/com/cloudmedia/discovery/discovery/HomeFeedService.java
  • services/java/discovery-service/src/test/java/com/cloudmedia/discovery/api/discovery/DiscoveryControllerTest.java
  • services/java/discovery-service/src/test/java/com/cloudmedia/discovery/discovery/HomeFeedServiceTest.java

Comment thread docs/contracts/rest-api-v1.md
Copy link
Copy Markdown

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

🧹 Nitpick comments (2)
services/java/discovery-service/src/main/java/com/cloudmedia/discovery/api/validation/CountryCodeValidator.java (1)

14-20: Pre-compile the regex pattern to avoid repeated compilation.

String.matches() compiles a new Pattern on every call. For a validator invoked on each request, consider extracting a pre-compiled pattern.

♻️ Suggested refactor
 public class CountryCodeValidator implements ConstraintValidator<ValidCountryCode, String> {

+	private static final java.util.regex.Pattern FORMAT_PATTERN = java.util.regex.Pattern.compile("^[A-Z]{2}$");
+
 	private static final Set<String> ISO_COUNTRY_CODES = Arrays.stream(java.util.Locale.getISOCountries())
 			.collect(Collectors.toUnmodifiableSet());

 	`@Override`
 	public boolean isValid(String value, ConstraintValidatorContext context) {
 		if (value == null) {
 			return true;
 		}
-		return value.matches("^[A-Z]{2}$") && ISO_COUNTRY_CODES.contains(value);
+		return FORMAT_PATTERN.matcher(value).matches() && ISO_COUNTRY_CODES.contains(value);
 	}
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@services/java/discovery-service/src/main/java/com/cloudmedia/discovery/api/validation/CountryCodeValidator.java`
around lines 14 - 20, The isValid method in CountryCodeValidator currently calls
String.matches which recompiles the regex on every invocation; create a private
static final java.util.regex.Pattern (e.g., COUNTRY_CODE_PATTERN) at class scope
with the "^[A-Z]{2}$" regex and replace value.matches(...) with
COUNTRY_CODE_PATTERN.matcher(value).matches(), keeping the existing null-check
and ISO_COUNTRY_CODES.contains(value) logic intact (use the same
ISO_COUNTRY_CODES reference).
services/java/discovery-service/src/main/java/com/cloudmedia/discovery/discovery/HomeFeedService.java (1)

90-99: Deduplicate policy evaluations across buckets to reduce policy service load.

If the same contentId appears in multiple buckets (e.g., in both trending and fresh), it will be evaluated multiple times. Since evaluate() makes HTTP calls to the policy service (2s connect + 3s read timeout), this introduces unnecessary latency and load.

Suggested approach: collect distinct contentIds from all buckets, evaluate once, then filter each bucket against the cached results. This requires adding a batch evaluation method to PolicyEvaluationClient and updating the filtering logic.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@services/java/discovery-service/src/main/java/com/cloudmedia/discovery/discovery/HomeFeedService.java`
around lines 90 - 99, The current filterByPolicy method calls
policyEvaluationClient.evaluate(item.contentId(), ...) for every HomeFeedItem,
causing duplicate HTTP calls for repeated contentIds; change filterByPolicy to
first collect distinct contentIds from the input List<HomeFeedItem> (using
HomeFeedItem::contentId), call a new batch method on PolicyEvaluationClient
(e.g., evaluateBatch(Collection<String> contentIds, String countryCode, Boolean
ageVerified)) to get a Map<String,PolicyDecision> or Map<String,Boolean> of
allowed results, then apply that cached map to filter each item (lookup by
contentId) instead of calling evaluate per item; preserve the current
PolicyEvaluationException handling (throw ApiException with SERVICE_UNAVAILABLE)
when the batch call fails and ensure references to filterByPolicy,
policyEvaluationClient.evaluate, PolicyEvaluationClient,
HomeFeedItem.contentId(), and PolicyEvaluationException are updated accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@services/java/discovery-service/src/main/java/com/cloudmedia/discovery/api/validation/CountryCodeValidator.java`:
- Around line 14-20: The isValid method in CountryCodeValidator currently calls
String.matches which recompiles the regex on every invocation; create a private
static final java.util.regex.Pattern (e.g., COUNTRY_CODE_PATTERN) at class scope
with the "^[A-Z]{2}$" regex and replace value.matches(...) with
COUNTRY_CODE_PATTERN.matcher(value).matches(), keeping the existing null-check
and ISO_COUNTRY_CODES.contains(value) logic intact (use the same
ISO_COUNTRY_CODES reference).

In
`@services/java/discovery-service/src/main/java/com/cloudmedia/discovery/discovery/HomeFeedService.java`:
- Around line 90-99: The current filterByPolicy method calls
policyEvaluationClient.evaluate(item.contentId(), ...) for every HomeFeedItem,
causing duplicate HTTP calls for repeated contentIds; change filterByPolicy to
first collect distinct contentIds from the input List<HomeFeedItem> (using
HomeFeedItem::contentId), call a new batch method on PolicyEvaluationClient
(e.g., evaluateBatch(Collection<String> contentIds, String countryCode, Boolean
ageVerified)) to get a Map<String,PolicyDecision> or Map<String,Boolean> of
allowed results, then apply that cached map to filter each item (lookup by
contentId) instead of calling evaluate per item; preserve the current
PolicyEvaluationException handling (throw ApiException with SERVICE_UNAVAILABLE)
when the batch call fails and ensure references to filterByPolicy,
policyEvaluationClient.evaluate, PolicyEvaluationClient,
HomeFeedItem.contentId(), and PolicyEvaluationException are updated accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b7df63c6-9b86-447d-8860-3259bc725e19

📥 Commits

Reviewing files that changed from the base of the PR and between a658ddb and 02858a7.

📒 Files selected for processing (7)
  • docs/contracts/rest-api-v1.md
  • services/java/discovery-service/src/main/java/com/cloudmedia/discovery/api/discovery/DiscoveryController.java
  • services/java/discovery-service/src/main/java/com/cloudmedia/discovery/api/validation/CountryCodeValidator.java
  • services/java/discovery-service/src/main/java/com/cloudmedia/discovery/api/validation/ValidCountryCode.java
  • services/java/discovery-service/src/main/java/com/cloudmedia/discovery/discovery/HomeFeedService.java
  • services/java/discovery-service/src/test/java/com/cloudmedia/discovery/api/discovery/DiscoveryControllerTest.java
  • services/java/discovery-service/src/test/java/com/cloudmedia/discovery/discovery/HomeFeedServiceTest.java
🚧 Files skipped from review as they are similar to previous changes (2)
  • services/java/discovery-service/src/main/java/com/cloudmedia/discovery/api/discovery/DiscoveryController.java
  • docs/contracts/rest-api-v1.md

Copy link
Copy Markdown

@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

🧹 Nitpick comments (1)
services/java/discovery-service/src/main/java/com/cloudmedia/discovery/api/validation/CountryCodeValidator.java (1)

5-8: Minor: Import java.util.Locale for consistency.

Locale is referenced with its fully qualified name on line 12, while other java.util classes are imported. Consider adding the import for consistency.

Suggested fix
 import java.util.Arrays;
+import java.util.Locale;
 import java.util.Set;
 import java.util.stream.Collectors;
 import java.util.regex.Pattern;

Then on line 12:

-	private static final Set<String> ISO_COUNTRY_CODES = Arrays.stream(java.util.Locale.getISOCountries())
+	private static final Set<String> ISO_COUNTRY_CODES = Arrays.stream(Locale.getISOCountries())

Also applies to: 12-12

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@services/java/discovery-service/src/main/java/com/cloudmedia/discovery/api/validation/CountryCodeValidator.java`
around lines 5 - 8, CountryCodeValidator uses java.util.Locale fully-qualified
on line 12; add an import for Locale and replace the fully-qualified reference
with Locale to match other java.util imports for consistency — update the
imports block to include Locale and adjust any usages within
CountryCodeValidator (e.g., Locale.getISOCountries()) accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@services/java/discovery-service/src/main/java/com/cloudmedia/discovery/policy/PolicyEvaluationClient.java`:
- Around line 11-20: The default evaluateBatch implementation performs
sequential calls to evaluate for each contentId causing high cumulative latency;
update evaluateBatch (or override it in HttpPolicyEvaluationClient) to perform
calls in parallel (e.g., create uniqueIds from contentIds, launch
evaluate(contentId, countryCode, ageVerified) via CompletableFuture/supplyAsync
with a bounded Executor, collect .join() results into the LinkedHashMap) or,
preferably, implement a true batch call in HttpPolicyEvaluationClient that
invokes a policy service batch endpoint (e.g., POST
/v1/policy/content/evaluate-batch) and maps the single response to the returned
Map<String,PolicyDecision>.

---

Nitpick comments:
In
`@services/java/discovery-service/src/main/java/com/cloudmedia/discovery/api/validation/CountryCodeValidator.java`:
- Around line 5-8: CountryCodeValidator uses java.util.Locale fully-qualified on
line 12; add an import for Locale and replace the fully-qualified reference with
Locale to match other java.util imports for consistency — update the imports
block to include Locale and adjust any usages within CountryCodeValidator (e.g.,
Locale.getISOCountries()) accordingly.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 980b30db-88d2-4184-8a6f-e3776398bc8d

📥 Commits

Reviewing files that changed from the base of the PR and between 02858a7 and 75ce5d8.

📒 Files selected for processing (3)
  • services/java/discovery-service/src/main/java/com/cloudmedia/discovery/api/validation/CountryCodeValidator.java
  • services/java/discovery-service/src/main/java/com/cloudmedia/discovery/discovery/HomeFeedService.java
  • services/java/discovery-service/src/main/java/com/cloudmedia/discovery/policy/PolicyEvaluationClient.java
🚧 Files skipped from review as they are similar to previous changes (1)
  • services/java/discovery-service/src/main/java/com/cloudmedia/discovery/discovery/HomeFeedService.java

Comment on lines +11 to +20
default Map<String, PolicyDecision> evaluateBatch(Collection<String> contentIds, String countryCode,
Boolean ageVerified) {
Map<String, PolicyDecision> decisions = new LinkedHashMap<>();
for (String contentId : contentIds) {
if (contentId != null && !decisions.containsKey(contentId)) {
decisions.put(contentId, evaluate(contentId, countryCode, ageVerified));
}
}
return decisions;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Sequential HTTP calls may cause high latency on home feed requests.

The default implementation makes N sequential HTTP calls to the policy service (one per unique content ID). For a home feed with 30-50 items, this could add 100-300ms+ of cumulative latency under normal conditions, and much worse under load or partial service degradation.

Consider parallelizing the calls or introducing a true batch endpoint on the policy service:

♻️ Option 1: Parallel execution with CompletableFuture
default Map<String, PolicyDecision> evaluateBatch(Collection<String> contentIds, String countryCode,
        Boolean ageVerified) {
    List<String> uniqueIds = contentIds.stream()
            .filter(Objects::nonNull)
            .distinct()
            .toList();
    
    Map<String, CompletableFuture<PolicyDecision>> futures = new LinkedHashMap<>();
    for (String contentId : uniqueIds) {
        futures.put(contentId, CompletableFuture.supplyAsync(
            () -> evaluate(contentId, countryCode, ageVerified)));
    }
    
    Map<String, PolicyDecision> decisions = new LinkedHashMap<>();
    for (var entry : futures.entrySet()) {
        decisions.put(entry.getKey(), entry.getValue().join());
    }
    return decisions;
}

This requires adding import java.util.concurrent.CompletableFuture;, import java.util.List;, and import java.util.Objects;. You may also want to use a bounded executor to limit concurrent requests.

♻️ Option 2: True batch API (preferred if policy service supports it)

Override evaluateBatch in HttpPolicyEvaluationClient to call a batch endpoint (e.g., POST /v1/policy/content/evaluate-batch) that accepts multiple content IDs in a single request.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@services/java/discovery-service/src/main/java/com/cloudmedia/discovery/policy/PolicyEvaluationClient.java`
around lines 11 - 20, The default evaluateBatch implementation performs
sequential calls to evaluate for each contentId causing high cumulative latency;
update evaluateBatch (or override it in HttpPolicyEvaluationClient) to perform
calls in parallel (e.g., create uniqueIds from contentIds, launch
evaluate(contentId, countryCode, ageVerified) via CompletableFuture/supplyAsync
with a bounded Executor, collect .join() results into the LinkedHashMap) or,
preferably, implement a true batch call in HttpPolicyEvaluationClient that
invokes a policy service batch endpoint (e.g., POST
/v1/policy/content/evaluate-batch) and maps the single response to the returned
Map<String,PolicyDecision>.

@poyrazK poyrazK merged commit 66dea9e into main Apr 4, 2026
6 checks passed
@poyrazK poyrazK deleted the feat/discovery-home-policy-filter branch April 4, 2026 14:08
poyrazK added a commit that referenced this pull request Apr 4, 2026
feat(discovery): apply policy filtering to home feed
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