# AI Behavior Notes For XmobiTea DeviceId

Read this only when product logic depends on persistence, reset behavior, logging, or platform differences.

## Fast Facts

| Question | Answer |
| --- | --- |
| Does the package create objects? | No |
| Does it need a boot scene? | No |
| Does `CXDevice` cache the value? | No |
| Is the format guaranteed? | No |
| Is the value hardware-backed on every target? | No |
| Is reset behavior identical on every target? | No |

## Default Targets

Default targets are every target except `iOS`, `macOSStandalone`, `tvOS`, and `WebGL`.

Behavior:

1. `CXDevice.GetDeviceId()` calls `Implement.Get()`.
2. `Implement.Get()` returns `SystemInfo.deviceUniqueIdentifier`.
3. The package adds no custom persistence, fallback, hashing, or validation.

Agent consequence: when writing default-target assumptions, inherit Unity's own `SystemInfo.deviceUniqueIdentifier` semantics.

## WebGL

Behavior:

1. Read `PlayerPrefs.GetString("MiniDeviceId_DeviceId", "")`.
2. If empty, create `Guid.NewGuid().ToString()`.
3. Store it back to `PlayerPrefs`.
4. Call `PlayerPrefs.Save()`.
5. Return the stored value.

Consequences:

- The WebGL value is app-generated.
- It is not a hardware identifier.
- It depends on browser-backed `PlayerPrefs` storage.
- Clearing browser/site storage can reset it.
- Deleting `PlayerPrefs` key `MiniDeviceId_DeviceId` and saving resets this package's WebGL ID.

## Apple-Path Assembly

Compile-time selection:

- `com.xmobitea.changx.mini-deviceid.runtime.iOS` is selected for `iOS`, `macOSStandalone`, and `tvOS`.
- This repo ships native bridge implementation sources under `Plugins/iOS` for iOS and tvOS imports.
- No macOS standalone native bridge source is present under `Plugins/iOS`.

Behavior when the native bridge returns the expected JSON payload:

1. The native plugin reads keychain entries `UserID` and `UserUUID`, then returns JSON fields `userId` and `uuid`.
2. Parse it into `CustomId`.
3. Ignore `CustomId.userId` for the returned value.
4. Use `CustomId.uuid` when present.
5. If `uuid` is empty, use `SystemInfo.deviceUniqueIdentifier`.
6. Save that fallback through the native keychain bridge with user slot `"0"`.
7. Log `===Saved uuid on empty: [...]`.
8. Return the final value.

Implementation note:

- The C# layer does not null-check a malformed native payload before reading `customId.uuid`.

Native keychain keys:

```text
UserID
UserUUID
```

Consequences:

- The keychain bridge is package-internal from consumer code.
- `CXDevice.GetDeviceId()` crosses the native bridge on every call.
- Caller-side caching is reasonable if the ID is needed repeatedly.
- An empty `uuid` read writes a value and logs a message.
- Native Apple logs may also include `No user information` when the keychain payload is empty.

Expected fallback-write log:

```text
===Saved uuid on empty: [...]
```

This log is normal package behavior for the empty-uuid fallback path.

## Consumer-Side Caching

The package does not cache at `CXDevice` level.

Use caller-side caching when:

- the ID is needed many times in one session,
- the ID is read in a loop or hot path,
- the native bridge cost matters.

Do not use caller-side caching when:

- product logic intentionally needs to observe an external reset during the same session,
- tests intentionally mutate `PlayerPrefs` or native storage between reads.

## Product Logic Guidance

Use the value as an opaque identifier string.

If the ID is used for analytics, account linking, save ownership, entitlement lookup, or abuse detection, document that:

- lifetime differs by platform,
- reset behavior differs by platform,
- storage may be user-clearable on some targets,
- the package does not add consent, privacy, encryption, hashing, or anti-fraud guarantees.
