Skip to content

feat: SITES-40623 - token architecture in Spacecat#1819

Open
sandsinh wants to merge 18 commits intomainfrom
SITES-40623
Open

feat: SITES-40623 - token architecture in Spacecat#1819
sandsinh wants to merge 18 commits intomainfrom
SITES-40623

Conversation

@sandsinh
Copy link
Contributor

@sandsinh sandsinh commented Feb 17, 2026


Summary

Jira - https://jira.corp.adobe.com/browse/SITES-40623

  • Add grant suggestion handler: New grant-suggestions-handler.js module that provisions tokens and grants top-ranked suggestions for an opportunity, using SuggestionGrant and Token data access
    collections.
  • Gate all grant logic behind isSummitPlgEnabled: Grant filtering, single-suggestion grant checks, autofix grant validation, and opportunity-level grant provisioning only run when the summit-plg audit
    handler is enabled for the site (via Configuration).
  • Extract filterByGrantStatus helper: Deduplicated the PLG-check + grant-filtering pattern used by 4 suggestion list endpoints into a shared function with error handling (returns empty array on
    failure).
  • Use SuggestionGrant collection: All grant operations (splitSuggestionsByGrantStatus, grantSuggestions, isSuggestionGranted) use the new SuggestionGrant data access entity from
    @adobe/spacecat-shared-data-access.

Changes

Source

  • src/support/grant-suggestions-handler.js (new) — getTopSuggestions groups/sorts suggestions by rank with per-opportunity strategy support; grantSuggestionsForOpportunity manages token lifecycle and
    grants top ungranted suggestions.
  • src/controllers/opportunities.js — getByID now calls grantSuggestionsForOpportunity gated behind getIsSummitPlgEnabled, with try/catch for graceful error handling.
  • src/controllers/suggestions.js — Added SuggestionGrant destructuring, extracted filterByGrantStatus helper used by all list endpoints, added PLG-gated grant check in getByID, added PLG-gated grant
    validation in autofixSuggestions.

Tests

  • test/support/grant-suggestions-handler.test.js (new) — Full coverage for getTopSuggestions (sorting, grouping, edge cases) and grantSuggestionsForOpportunity (early returns, token creation, grant
    limiting, error paths).
  • test/controllers/opportunities.test.js — Tests for grant handler invocation, error handling (with and without error message), PLG enablement check.
  • test/controllers/suggestions.test.js — Tests for grant filtering error path, non-PLG site bypass, ungranted suggestion 404, autofix grant validation.

Test plan

  • All 5614 tests passing
  • 100% statement/branch/function/line coverage for opportunities.js and suggestions.js
  • 0 lint errors
  • Non-PLG sites skip all grant logic and return suggestions unfiltered
  • PLG sites filter suggestions by grant status across all list endpoints
  • filterByGrantStatus returns empty array on error
  • getByID returns 404 for ungranted suggestions on PLG sites
  • Autofix rejects ungranted suggestions on PLG sites
  • Grant handler errors in opportunities controller are caught and logged

Please ensure your pull request adheres to the following guidelines:

  • make sure to link the related issues in this description. Or if there's no issue created, make sure you
    describe here the problem you're solving.
  • when merging / squashing, make sure the fixed issue references are visible in the commits, for easy compilation of release notes

If the PR is changing the API specification:

  • make sure you add a "Not implemented yet" note the endpoint description, if the implementation is not ready
    yet. Ideally, return a 501 status code with a message explaining the feature is not implemented yet.
  • make sure you add at least one example of the request and response.

If the PR is changing the API implementation or an entity exposed through the API:

  • make sure you update the API specification and the examples to reflect the changes.

If the PR is introducing a new audit type:

  • make sure you update the API specification with the type, schema of the audit result and an example

Related Issues

Thanks for contributing!

@sandsinh sandsinh marked this pull request as draft February 17, 2026 09:53
@github-actions
Copy link

This PR will trigger a minor release when merged.

@codecov
Copy link

codecov bot commented Mar 15, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@sandsinh sandsinh marked this pull request as ready for review March 16, 2026 11:58
@sandsinh sandsinh requested a review from tarunsinghdev March 16, 2026 11:59
@Kanishkavijay39
Copy link
Contributor

🚨 Blocking Issues (Remove it after testing)

  1. Dependencies pinned to personal GitHub Gists (package.json, package-lock.json)
  2. Personal dev deployment label left in package.json

Logic / Correctness Issues

  1. Double splitSuggestionsByGrantStatus call creates a race window (grant-suggestions-handler.js:772–787)

When no token exists, the code calls splitSuggestionsByGrantStatus once to compute the initial token total, then creates the token, and immediately calls it again to
get notGrantedIds. In concurrent requests these two calls may return inconsistent results, leading to an incorrect suppliedTotal or double-granting.

  1. filterByGrantStatus returns empty array on error (suggestions.js:495–498)

} catch (err) {
ctx.log?.error?.(...)
return [];
}
On a DB failure, users silently see 0 suggestions instead of the actual list. Returning all suggestions unfiltered on error (fail-open) or propagating the error
(fail-closed) would be more intentional than silently hiding all results.

  1. broken-backlinks group rank uses Math.max — worth confirming intent

Groups backlinks by url_to and assigns the group rank as Math.max(...items.map(getSuggestionRank)). Since sort is ascending (lower rank = higher priority), a group
with many high-rank backlinks ends up being deprioritized. Double-check that this is the desired behavior.


Code Quality

  1. /* c8 ignore next / placement (opportunities.js:442, suggestions.js:495)
    /
    c8 ignore next */ } catch (err) {
    c8 ignore next on the same line as the closing } is at best ambiguous; coverage tools typically apply it to the following line. This may produce inconsistent coverage
    reports. The normal pattern is to place it on its own line before the branch.

  2. Weak guard in grantSuggestionsForOpportunity (grant-suggestions-handler.js:764)

if (!Suggestion || !SuggestionGrant || !Token || !siteId || !opptyId || !config) return;
config here is the result of getTokenGrantConfigByOpportunity(oppType). If oppType is defined but the config has no tokenType, this guard passes but tokenType is
undefined. The token lookup Token.findBySiteIdAndTokenType(siteId, undefined) may silently misbehave. An explicit !tokenType guard would be safer.


Tests

Tests are well-structured and cover the main paths: PLG enabled/disabled, error handling, grant filtering, autofix validation. The use of try/finally to restore
shared test state (e.g., opptys[0].type = previousType) is a good pattern.

One gap: no test for the concurrent token-creation path (two simultaneous requests where token is initially null).


@Kanishkavijay39 Kanishkavijay39 self-requested a review March 17, 2026 07:37
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