Skip to content

feat(attributes): Add device.low_power_mode attribute for iOS#314

Open
itaybre wants to merge 1 commit intomainfrom
feat/device-low-power-mode
Open

feat(attributes): Add device.low_power_mode attribute for iOS#314
itaybre wants to merge 1 commit intomainfrom
feat/device-low-power-mode

Conversation

@itaybre
Copy link
Copy Markdown

@itaybre itaybre commented Apr 8, 2026

Summary

  • Adds device.low_power_mode boolean attribute to document whether an iOS device is in Low Power Mode
  • Scoped to sentry.cocoa SDK
  • Updates JavaScript (attributes.ts) and Python (attributes.py) bindings

Test plan

  • Verify yarn test:js passes
  • Add the PR number to the prs field in model/attributes/device/device__low_power_mode.json changelog

🤖 Generated with Claude Code

@itaybre itaybre requested review from a team, Lms24, cleptric, lcian, mjq and nsdeschenes as code owners April 8, 2026 21:04
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 8, 2026

Semver Impact of This PR

🟡 Minor (new features)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


New Features ✨

Attributes

  • Add device.low_power_mode attribute for iOS by itaybre in #314
  • Add network connection-related attributes by Lms24 in #279
  • Add cache.write attribute by adinauer in #292
  • Add device context attributes by buenaflor in #300
  • Add app context attributes for mobile by buenaflor in #296
  • Add device memory and core count attributes by Lms24 in #281
  • Add ui.element.* attributes by Lms24 in #284
  • Add remaining TTFB, FCP and FP web vital attributes by Lms24 in #235
  • Add LCP web vital meta attributes by Lms24 in #233
  • Add CLS web vital source attribute by Lms24 in #234
  • Add core web web vital value attributes by Lms24 in #229
  • Add allow_any_value field to attribute schema by vgrozdanic in #272

Other

  • (http) Add http.server.request.time_in_queue attribute by dingsdax in #267
  • (resource) Add resource.deployment.environment by mjq in #266
  • Add sentry.timestamp.sequence attribute to the spec by logaretm in #262
  • Add changelog tracking to attribute definitions by ericapisani in #270

Bug Fixes 🐛

  • (attributes) Remove allow_any_value boolean attribute and allow any as type by vgrozdanic in #273
  • (gen_ai) Input and output token description by obostjancic in #261
  • (sentry) Deprecate sentry.trace.parent_span_id by mjq in #287
  • Don't run changelog generation on yarn generate by Lms24 in #277
  • Avoid changelog generation recursion by Lms24 in #274

Documentation 📚

  • (sentry) Add deprecated sentry.source by s1gr1d in #288
  • Redirect from old /generated pages to new routes by Lms24 in #291
  • Remove extra yarn run format instruction by mjq in #289
  • Update README with up-to-date links by ericapisani in #258

Internal Changes 🔧

Deps

  • Bump defu from 6.1.4 to 6.1.6 by dependabot in #309
  • Bump vite from 6.4.1 to 6.4.2 by dependabot in #310
  • Bump pygments from 2.19.2 to 2.20.0 in /python by dependabot in #307
  • Bump smol-toml from 1.6.0 to 1.6.1 by dependabot in #305
  • Bump h3 from 1.15.5 to 1.15.9 by dependabot in #299
  • Bump devalue from 5.6.3 to 5.6.4 by dependabot in #286
  • Bump dompurify from 3.3.1 to 3.3.2 by dependabot in #278
  • Bump svgo from 3.3.2 to 3.3.3 by dependabot in #275
  • Bump svelte from 5.51.5 to 5.53.5 by dependabot in #271
  • Bump rollup from 4.40.1 to 4.59.0 by dependabot in #269
  • Bump svelte from 5.48.1 to 5.51.5 by dependabot in #260

Deps Dev

  • Bump tar from 7.5.10 to 7.5.11 by dependabot in #285
  • Bump tar from 7.5.8 to 7.5.10 by dependabot in #276
  • Bump tar from 7.5.7 to 7.5.8 by dependabot in #259

Other

  • (ai) Deprecate rest of ai.* attributes by constantinius in #264
  • (attributes) Ensure each attribute json has a changelog entry by Lms24 in #282
  • (docs) Upgrade to Astro 6 by Lms24 in #283
  • (gen_ai) Deprecate gen_ai.tool.input, gen_ai.tool.message, gen_ai.tool.output by constantinius in #265
  • (publish) Bump next entries in changelog when releasing by Lms24 in #290
  • (repo) Populate changelog property when running yarn create:attribute by Lms24 in #280
  • Pin GitHub Actions to full-length commit SHAs by joshuarli in #302
  • Wrong link to CONTRIBUTING.md in PR template by sentrivana in #298

🤖 This preview updates automatically when you update the PR.


Type: bool
Contains PII: false
Defined in OTEL: No
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: The new attribute DEVICE_LOW_POWER_MODE was added to ATTRIBUTE_NAMES but is missing its corresponding entry in the ATTRIBUTE_METADATA dictionary in the Python file.
Severity: HIGH

Suggested Fix

Add the missing AttributeMetadata entry for "device.low_power_mode" to the ATTRIBUTE_METADATA dictionary in python/src/sentry_conventions/attributes.py. This will align the Python implementation with the TypeScript version and prevent runtime KeyError exceptions.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: python/src/sentry_conventions/attributes.py#L1535

Potential issue: The Python bindings file was updated to include the new
`DEVICE_LOW_POWER_MODE` constant in the `ATTRIBUTE_NAMES` class. However, the
corresponding entry for this attribute was not added to the `ATTRIBUTE_METADATA`
dictionary. As a result, any Python code that attempts to look up the metadata for this
new attribute, for example by calling `ATTRIBUTE_METADATA["device.low_power_mode"]`,
will encounter a `KeyError` at runtime. This creates an inconsistency where the
attribute constant exists but its metadata is inaccessible.

Did we get this right? 👍 / 👎 to inform future reviews.

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 3 potential issues.

Fix All in Cursor

Bugbot Autofix prepared fixes for all 3 issues found in the latest run.

  • ✅ Fixed: Python bindings missing metadata and TypedDict entries
    • Added device.low_power_mode entries to both ATTRIBUTE_METADATA dictionary and Attributes TypedDict in correct alphabetical position.
  • ✅ Fixed: TypeScript Attributes type missing new attribute entry
    • Added [DEVICE_LOW_POWER_MODE]?: DEVICE_LOW_POWER_MODE_TYPE entry to the Attributes type in correct alphabetical position.
  • ✅ Fixed: New attribute placed in wrong alphabetical position
    • Moved all DEVICE_LOW_POWER_MODE entries from after DEVICE_SIMULATOR to between DEVICE_FREE_MEMORY and DEVICE_MEMORY_ESTIMATED_CAPACITY in all sections of both files.

Create PR

Or push these changes by commenting:

@cursor push 7293ba5b57
Preview (7293ba5b57)
diff --git a/javascript/sentry-conventions/src/attributes.ts b/javascript/sentry-conventions/src/attributes.ts
--- a/javascript/sentry-conventions/src/attributes.ts
+++ b/javascript/sentry-conventions/src/attributes.ts
@@ -2345,6 +2345,26 @@
  */
 export type DEVICE_FREE_MEMORY_TYPE = number;
 
+// Path: model/attributes/device/device__low_power_mode.json
+
+/**
+ * Whether the device is in Low Power Mode. `device.low_power_mode`
+ *
+ * Attribute Value Type: `boolean` {@link DEVICE_LOW_POWER_MODE_TYPE}
+ *
+ * Contains PII: false
+ *
+ * Attribute defined in OTEL: No
+ *
+ * @example true
+ */
+export const DEVICE_LOW_POWER_MODE = 'device.low_power_mode';
+
+/**
+ * Type for {@link DEVICE_LOW_POWER_MODE} device.low_power_mode
+ */
+export type DEVICE_LOW_POWER_MODE_TYPE = boolean;
+
 // Path: model/attributes/device/device__memory__estimated_capacity.json
 
 /**
@@ -2469,26 +2489,6 @@
  */
 export type DEVICE_SIMULATOR_TYPE = boolean;
 
-// Path: model/attributes/device/device__low_power_mode.json
-
-/**
- * Whether the device is in Low Power Mode. `device.low_power_mode`
- *
- * Attribute Value Type: `boolean` {@link DEVICE_LOW_POWER_MODE_TYPE}
- *
- * Contains PII: false
- *
- * Attribute defined in OTEL: No
- *
- * @example true
- */
-export const DEVICE_LOW_POWER_MODE = 'device.low_power_mode';
-
-/**
- * Type for {@link DEVICE_LOW_POWER_MODE} device.low_power_mode
- */
-export type DEVICE_LOW_POWER_MODE_TYPE = boolean;
-
 // Path: model/attributes/effectiveConnectionType.json
 
 /**
@@ -10347,13 +10347,13 @@
   [DEVICE_CLASS]: 'string',
   [DEVICE_FAMILY]: 'string',
   [DEVICE_FREE_MEMORY]: 'integer',
+  [DEVICE_LOW_POWER_MODE]: 'boolean',
   [DEVICE_MEMORY_ESTIMATED_CAPACITY]: 'integer',
   [DEVICE_MEMORY_SIZE]: 'integer',
   [DEVICE_MODEL]: 'string',
   [DEVICE_MODEL_ID]: 'string',
   [DEVICE_PROCESSOR_COUNT]: 'integer',
   [DEVICE_SIMULATOR]: 'boolean',
-  [DEVICE_LOW_POWER_MODE]: 'boolean',
   [EFFECTIVECONNECTIONTYPE]: 'string',
   [ENVIRONMENT]: 'string',
   [ERROR_TYPE]: 'string',
@@ -10836,13 +10836,13 @@
   | typeof DEVICE_CLASS
   | typeof DEVICE_FAMILY
   | typeof DEVICE_FREE_MEMORY
+  | typeof DEVICE_LOW_POWER_MODE
   | typeof DEVICE_MEMORY_ESTIMATED_CAPACITY
   | typeof DEVICE_MEMORY_SIZE
   | typeof DEVICE_MODEL
   | typeof DEVICE_MODEL_ID
   | typeof DEVICE_PROCESSOR_COUNT
   | typeof DEVICE_SIMULATOR
-  | typeof DEVICE_LOW_POWER_MODE
   | typeof EFFECTIVECONNECTIONTYPE
   | typeof ENVIRONMENT
   | typeof ERROR_TYPE
@@ -12644,6 +12644,17 @@
     example: 2147483648,
     changelog: [{ version: 'next', prs: [300], description: 'Added device.free_memory attribute' }],
   },
+  [DEVICE_LOW_POWER_MODE]: {
+    brief: 'Whether the device is in Low Power Mode.',
+    type: 'boolean',
+    pii: {
+      isPii: 'false',
+    },
+    isInOtel: false,
+    sdks: ['sentry.cocoa'],
+    example: true,
+    changelog: [{ version: 'next', description: 'Added device.low_power_mode attribute' }],
+  },
   [DEVICE_MEMORY_ESTIMATED_CAPACITY]: {
     brief:
       'The estimated total memory capacity of the device, only a rough estimation in gigabytes. Browsers report estimations in buckets of powers of 2, mostly capped at 8 GB',
@@ -12725,17 +12736,6 @@
     example: false,
     changelog: [{ version: 'next', prs: [300], description: 'Added device.simulator attribute' }],
   },
-  [DEVICE_LOW_POWER_MODE]: {
-    brief: 'Whether the device is in Low Power Mode.',
-    type: 'boolean',
-    pii: {
-      isPii: 'false',
-    },
-    isInOtel: false,
-    sdks: ['sentry.cocoa'],
-    example: true,
-    changelog: [{ version: 'next', description: 'Added device.low_power_mode attribute' }],
-  },
   [EFFECTIVECONNECTIONTYPE]: {
     brief: 'Specifies the estimated effective type of the current connection (e.g. slow-2g, 2g, 3g, 4g).',
     type: 'string',
@@ -17239,6 +17239,7 @@
   [DEVICE_CLASS]?: DEVICE_CLASS_TYPE;
   [DEVICE_FAMILY]?: DEVICE_FAMILY_TYPE;
   [DEVICE_FREE_MEMORY]?: DEVICE_FREE_MEMORY_TYPE;
+  [DEVICE_LOW_POWER_MODE]?: DEVICE_LOW_POWER_MODE_TYPE;
   [DEVICE_MEMORY_ESTIMATED_CAPACITY]?: DEVICE_MEMORY_ESTIMATED_CAPACITY_TYPE;
   [DEVICE_MEMORY_SIZE]?: DEVICE_MEMORY_SIZE_TYPE;
   [DEVICE_MODEL]?: DEVICE_MODEL_TYPE;

diff --git a/python/src/sentry_conventions/attributes.py b/python/src/sentry_conventions/attributes.py
--- a/python/src/sentry_conventions/attributes.py
+++ b/python/src/sentry_conventions/attributes.py
@@ -1462,6 +1462,16 @@
     Example: 2147483648
     """
 
+    # Path: model/attributes/device/device__low_power_mode.json
+    DEVICE_LOW_POWER_MODE: Literal["device.low_power_mode"] = "device.low_power_mode"
+    """Whether the device is in Low Power Mode.
+
+    Type: bool
+    Contains PII: false
+    Defined in OTEL: No
+    Example: true
+    """
+
     # Path: model/attributes/device/device__memory__estimated_capacity.json
     DEVICE_MEMORY_ESTIMATED_CAPACITY: Literal["device.memory.estimated_capacity"] = (
         "device.memory.estimated_capacity"
@@ -1526,16 +1536,6 @@
     Example: false
     """
 
-    # Path: model/attributes/device/device__low_power_mode.json
-    DEVICE_LOW_POWER_MODE: Literal["device.low_power_mode"] = "device.low_power_mode"
-    """Whether the device is in Low Power Mode.
-
-    Type: bool
-    Contains PII: false
-    Defined in OTEL: No
-    Example: true
-    """
-
     # Path: model/attributes/deviceMemory.json
     DEVICEMEMORY: Literal["deviceMemory"] = "deviceMemory"
     """The estimated total memory capacity of the device, only a rough estimation in gigabytes.
@@ -7047,6 +7047,20 @@
             ),
         ],
     ),
+    "device.low_power_mode": AttributeMetadata(
+        brief="Whether the device is in Low Power Mode.",
+        type=AttributeType.BOOLEAN,
+        pii=PiiInfo(isPii=IsPii.FALSE),
+        is_in_otel=False,
+        example=True,
+        sdks=["sentry.cocoa"],
+        changelog=[
+            ChangelogEntry(
+                version="next",
+                description="Added device.low_power_mode attribute",
+            ),
+        ],
+    ),
     "device.memory.estimated_capacity": AttributeMetadata(
         brief="The estimated total memory capacity of the device, only a rough estimation in gigabytes. Browsers report estimations in buckets of powers of 2, mostly capped at 8 GB",
         type=AttributeType.INTEGER,
@@ -11613,6 +11627,7 @@
         "device.class": str,
         "device.family": str,
         "device.free_memory": int,
+        "device.low_power_mode": bool,
         "device.memory.estimated_capacity": int,
         "device.memory_size": int,
         "device.model": str,

This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.

Reviewed by Cursor Bugbot for commit f95b230. Configure here.

Contains PII: false
Defined in OTEL: No
Example: true
"""
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Python bindings missing metadata and TypedDict entries

High Severity

The device.low_power_mode attribute's Python bindings are incomplete. While the constant name exists, entries are missing from the ATTRIBUTE_METADATA dictionary and the Attributes TypedDict. This prevents Python consumers from accessing its metadata and type checkers from validating it, making the attribute effectively unusable.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit f95b230. Configure here.

sdks: ['sentry.cocoa'],
example: true,
changelog: [{ version: 'next', description: 'Added device.low_power_mode attribute' }],
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

TypeScript Attributes type missing new attribute entry

Medium Severity

DEVICE_LOW_POWER_MODE is added to the constant, ATTRIBUTE_TYPE map, AttributeName union, and ATTRIBUTE_METADATA, but the Attributes mapped type near line 17247 is missing [DEVICE_LOW_POWER_MODE]?: DEVICE_LOW_POWER_MODE_TYPE;. The entry jumps from DEVICE_SIMULATOR directly to EFFECTIVECONNECTIONTYPE. TypeScript consumers using the Attributes type won't get type-safe access to this new attribute.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit f95b230. Configure here.

/**
* Type for {@link DEVICE_LOW_POWER_MODE} device.low_power_mode
*/
export type DEVICE_LOW_POWER_MODE_TYPE = boolean;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

New attribute placed in wrong alphabetical position

Low Severity

DEVICE_LOW_POWER_MODE is appended after DEVICE_SIMULATOR in every section (constant definitions, ATTRIBUTE_TYPE, AttributeName, ATTRIBUTE_METADATA, and Python ATTRIBUTE_NAMES), but the rest of the file maintains strict alphabetical order by constant name. Since L sorts before M, P, and S, it belongs between DEVICE_FREE_MEMORY and DEVICE_MEMORY_ESTIMATED_CAPACITY. These are auto-generated files, so the next regeneration will move the entry and produce a noisy diff.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit f95b230. Configure here.

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