Skip to content

feat(core): derive consent category metadata from cookie context - #171

Merged
jamiedavenport merged 3 commits into
mainfrom
issue-160
Aug 2, 2026
Merged

feat(core): derive consent category metadata from cookie context#171
jamiedavenport merged 3 commits into
mainfrom
issue-160

Conversation

@jamiedavenport

@jamiedavenport jamiedavenport commented Aug 2, 2026

Copy link
Copy Markdown
Owner

Summary

Derives localized consent category labels, descriptions, and GPC behavior from cookie context so preference panels no longer maintain separate copy tables. Closes #160.

Changes

  • Add optional label, description, and respectGPC metadata to CookieContextEntry
  • Share localized cookie-type fallback logic between policy compilation and consent derivation
  • Update the PolicyStack preference UI, public docs, generated SDK reference, tests, and release changeset

Summary by CodeRabbit

  • New Features

    • Added optional cookie category labels and descriptions for clearer consent experiences.
    • Added per-category control for respecting Global Privacy Control (GPC) signals.
    • Added locale-aware fallback labels and descriptions when custom copy is unavailable.
    • Preserved custom category names and explicitly empty values.
    • Made cookie metadata available through consent context.
  • Documentation

    • Updated consent, policy, and SDK documentation with cookie metadata options, localization, and fallback behavior.

@vercel

vercel Bot commented Aug 2, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
op-demo Ready Ready Preview Aug 2, 2026 11:51am
openpolicy-sh Ready Ready Preview Aug 2, 2026 11:51am
policystack Ready Ready Preview Aug 2, 2026 11:51am

Request Review

@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@jamiedavenport, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 36 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 05922229-5269-4880-ada8-23caaad7cb98

📥 Commits

Reviewing files that changed from the base of the PR and between 2cdb6ee and 78677a1.

📒 Files selected for processing (2)
  • packages/core/src/i18n/cookie-type.ts
  • packages/core/src/i18n/i18n.test.ts
📝 Walkthrough

Walkthrough

Cookie context entries now support labels, descriptions, and respectGPC. Consent categories use explicit metadata or localized cookie-type fallbacks. Preference panels render category descriptions from useConsent().categories.

Changes

Cookie consent metadata

Layer / File(s) Summary
Metadata contract and shared resolver
packages/core/src/types.ts, packages/core/src/i18n/cookie-type.ts, packages/core/src/documents/cookie.ts
CookieContextEntry supports optional metadata. Shared resolution provides localized labels and descriptions for known and custom cookie types.
Consent derivation and validation
packages/core/src/consent/..., packages/core/src/policy-version.test.ts, packages/react/src/*test*
Derived categories preserve explicit metadata and respectGPC, apply independent localized fallbacks, and include regression coverage.
Preference panel wiring and documentation
apps/web/src/..., apps/web/content/docs/..., packages/sdk/..., .changeset/...
The preference panel renders category descriptions from consent data. Application policy examples and documentation describe the new metadata and fallback behavior.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CookieContextEntry
  participant deriveConsentConfig
  participant resolveCookieTypeMeta
  participant useConsent
  participant CookiePreferences
  deriveConsentConfig->>CookieContextEntry: Read metadata
  deriveConsentConfig->>resolveCookieTypeMeta: Resolve localized fallbacks
  deriveConsentConfig->>useConsent: Expose derived categories
  useConsent->>CookiePreferences: Provide category metadata
  CookiePreferences->>CookiePreferences: Render labels and descriptions
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes deriving consent category metadata from cookie context, which is the primary pull request change.
Linked Issues check ✅ Passed The changes add label, description, and respectGPC fields, derive localized category metadata, and remove duplicated preference-panel copy as required by issue #160.
Out of Scope Changes check ✅ Passed The implementation, tests, documentation, UI updates, and release changeset directly support the linked issue and pull request objectives.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-160

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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 `@packages/core/src/consent/derive.ts`:
- Around line 27-37: Update the locale passed to createT in the category
fallback path within derive so it uses the same effective locale selected for
the returned consent configuration, giving options.locale precedence over
policy.locale. Ensure resolveCookieTypeMeta receives that effective locale
through the shared translator, and add a regression test covering an
options.locale override.

In `@packages/core/src/i18n/cookie-type.ts`:
- Around line 14-16: Update the dictionary lookup in the cookie type resolution
logic to verify that key is an own property of known before reading known[key].
For inherited keys such as constructor or toString, skip the entry branch and
return t.cookie.types.fallback({ key }); preserve the existing label and
description behavior for valid own entries.
🪄 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 Plus

Run ID: 27b8b79a-288e-4793-81a7-84809f7c48b6

📥 Commits

Reviewing files that changed from the base of the PR and between 7e5c1b6 and 530ab6b.

📒 Files selected for processing (16)
  • .changeset/quiet-cookies-describe.md
  • apps/web/content/docs/consent/index.md
  • apps/web/content/docs/policy/configuration.md
  • apps/web/content/docs/policy/policies/cookies.md
  • apps/web/src/components/CookiePreferences.tsx
  • apps/web/src/policystack.ts
  • packages/core/src/consent/derive.test.ts
  • packages/core/src/consent/derive.ts
  • packages/core/src/documents/cookie.ts
  • packages/core/src/i18n/cookie-type.ts
  • packages/core/src/policy-version.test.ts
  • packages/core/src/types.ts
  • packages/react/src/consent.test.tsx
  • packages/react/src/provider.test.tsx
  • packages/sdk/llms.txt
  • packages/sdk/src/llms.ts

Comment thread packages/core/src/consent/derive.ts Outdated
Comment thread packages/core/src/i18n/cookie-type.ts Outdated
An explicit `options.locale` already overrode `policy.locale` for the
returned consent config, but the cookie-type dictionary behind derived
category copy still read `policy.locale`, so the config could report one
locale while its labels came from another. Resolve the locale once and
feed both, coercing through `coerceLocale` so a free-string locale maps
to the same `Locale` `resolveLocale` picks downstream without warning
twice.

Also note in the changeset that categories without explicit copy now
render dictionary labels instead of the capitalised key.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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 @.changeset/quiet-cookies-describe.md:
- Around line 5-7: Update the release note’s fallback-copy description to state
that derived categories use options.locale when provided, otherwise
policy.locale. Keep the existing explanation of dictionary fallback and
custom-category behavior unchanged.

In `@packages/core/src/consent/locale.ts`:
- Around line 14-17: Update deriveConsentConfig to compute one effective locale
using the same fallback precedence as resolveLocale, including
navigator.language when options.locale and policy.locale are absent, then pass
that locale to both coerceLocale and resolveLocale so derived category copy and
the consent configuration use the same result.
🪄 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 Plus

Run ID: 395d008f-3fbc-41d6-9f17-64f584841082

📥 Commits

Reviewing files that changed from the base of the PR and between 530ab6b and 2cdb6ee.

📒 Files selected for processing (4)
  • .changeset/quiet-cookies-describe.md
  • packages/core/src/consent/derive.test.ts
  • packages/core/src/consent/derive.ts
  • packages/core/src/consent/locale.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/core/src/consent/derive.test.ts
  • packages/core/src/consent/derive.ts

Comment thread .changeset/quiet-cookies-describe.md
Comment thread packages/core/src/consent/locale.ts
…Object

`cookies.used` keys are user-authored, so a bare index into the
dictionary's label map resolved `constructor`/`toString` up the prototype
chain to a truthy non-entry and threw `entry.label is not a function`
instead of returning the locale's generic fallback. Guard the lookup with
`Object.hasOwn`, matching the check in consent/triggers.
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.

CookieContextEntry: allow label/description so preference panels don't hardcode copy

1 participant