feat(checkpoints): Add the app's subscriber attributes as a rules dimension (#3996)
### Description
Adds a `subscriberAttributes` dimension provider, so everything the app
has told the SDK about the customer via `setAttributes` is readable by a
local rule. It would look like:
```json
{
"subscriberAttributes": {
"$email": {
"evaluatedAt": 1718452800000,
"updatedAt": 1714521600000,
"value": "jane@example.com"
},
"goal": {
"evaluatedAt": 1718452800000,
"updatedAt": 1718366400000,
"value": "lose_weight"
},
"seats": {
"evaluatedAt": 1718452800000,
"updatedAt": 1714780800000,
"value": "3"
}
}
}
```
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Changes how checkpoint audiences resolve using live subscriber
attributes and identity timing; mis-wiring could target the wrong user,
but attribute read failures are isolated and do not abort evaluation.
>
> **Overview**
> Adds a **`subscriberAttributes`** rules dimension so checkpoint
audiences can target values from `Purchases.setAttributes`. Each
attribute appears as a nested object (`value`, `updatedAt`,
`evaluatedAt`) readable via paths like
`subscriberAttributes.goal.value`.
>
> **Rules engine plumbing:** Introduces
`RulesDimensionValue.ObjectValue` for dot-path access (distinct from
list iteration). `RulesDimensionResolver` drops unreachable attribute
names (empty or containing `.`) with a warning instead of failing the
snapshot. Provider diagnostics now use **`namespace`** instead of a
separate `identifier`.
>
> **Wiring:** `LocalRulesEvaluator` is built **after** `IdentityManager`
so attributes are loaded for `identityManager.currentAppUserID`, not a
stale singleton. Read failures for subscriber attributes degrade to an
empty namespace (other dimensions still evaluate), matching store
dimension behavior.
>
> Unit and integration tests cover predicates, deletions/tombstones,
per-user isolation, and the `setAttributes` → disk cache → resolver
path.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
600517359fafc4a58d5a58d171f19f1223d361a2. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> T
Toni Rico committed
5ca53542c7703c74945bdbcdf68ce849a4789e56
Parent: 97a1356
Committed by GitHub <noreply@github.com>
on 8/19/2026, 8:13:39 AM