# Shared user profile — builder contract

Status: SDK 1.8.0 available. The static `/create/manifest.json` describes the SDK; [live capabilities](/api/identity/capabilities) report current server identity (`available`) and configured Google sign-in (`googleAvailable`). A true flag is not a hosted acceptance receipt. Existing guest gameplay must continue without profiles.

## One optional asynchronous read

The uploaded SDK 1.8.0 exposes `createProfileClient()` from `/shared/provisional/1.8.0/profile.js`, or `runtime.profile` from its runtime wrapper. `await profileClient.get()` is asynchronous. It returns a validated immutable projection or exactly `{available:false}` within five seconds; transport errors, missing host, disposal and invalid responses use that fallback. Start gameplay immediately and apply useful suggestions at a safe scene boundary. `dispose()` cancels outstanding reads.

This replaces the earlier synchronous device-local **prototype proposal**. Do not implement that prototype signature. SDK 1.8 has no `setSettings`, `recordUsage`, sign-in method or child change-event subscription. Platform-owned hosts manage authentication and telemetry. Re-read on deliberate setup/scene entry; never poll continuously or rename an active player after a late response. First-party internal APIs are not extra SDK methods.

The profile is optional and requires neither premium nor Google sign-in. An isolated top-level sensor origin needs a separately verified transport; absence preserves guest behavior. Updating framework source does not update historical immutable app artifacts.

## Projection and bounds

| Field | Contract |
| --- | --- |
| `schema` | `rifflet.experience-profile/1` |
| `available` | `true` for a successful projection |
| `revision` | Nonnegative safe integer; advisory snapshot version |
| `persistence` | `server-guest` or `account` |
| `display` | `{username, avatar:null}`; plain text only |
| `preferences` | Optional values from the table below |
| `experience.id` | Current public family namespace, never a person identifier |
| `experience.settings` | At most 32 scalar fields scoped to this family |
| `experience.usage` | `{starts,completions,activeMs}`; nonnegative safe integers |
| `experience.evidence` | `server-recorded-advisory` |

Maximum projection size is 8 KiB. The reader accepts usernames of 1–80 characters for compatibility; the new account username editor accepts at most 40. Names confer no authority and must be inserted using `textContent`. Avatar selection is not implemented. Settings keys match `^[a-z][a-zA-Z0-9]{0,39}$`, excluding `constructor` and `prototype`; values are booleans, finite numbers, or strings of at most 128 characters. No nested objects, arrays or blobs. Revisions in one family share its namespace; a separate derivative family does not inherit access. Builders cannot select a different family through the child API.

| Preference | Allowed values |
| --- | --- |
| sound | `on`, `off` |
| motion | `system`, `reduced` |
| contrast | `system`, `high` |
| challenge | `relaxed`, `balanced`, `challenging` |
| language | Canonicalizable BCP 47 tag, at most 35 characters |

Missing means unknown. Apply explicit current choices first, compatible saved app settings second, applicable platform suggestions third, and app defaults last. OS reduced motion always restricts motion. Sound preferences cannot grant autoplay or device permissions. Prefill a name only when the setup field is unset, or offer an explicit “Use my Riff name” action. Preserve saved content and existing multiplayer seats. Public score/name sharing needs its own consent.

## Privacy and continuity

Only the trusted first-party host holds the server session. It derives the family and exact launch revision, validates the child frame and message correlation, and returns only that family's projection. No email, Google subject, global profile/account ID, cookies, creator credentials, raw cross-app history or billing data enters the app frame. See [transport and lifecycle](/create/docs/docs/identity/BRIDGE.md).

Server guests expire after 10 days. Account sessions have a 30-day idle limit and 90-day absolute limit. Verified Google linking preserves guest ownership; when an existing account has another profile, the person explicitly selects the saved profile or the current visit. Both are retained; aggregates are not blindly summed. Sign-out invalidates cached projections and starts a fresh guest context where available. Neither names nor browser labels prove ownership. Hosted Google and continuity acceptance need exact-release evidence; configuration or a true capability alone does not demonstrate either. Creator enforcement, sensor identity continuity and report delivery remain disabled in this rollout.

Usage is advisory, not billing, unique people, proof of skill or a source of sensitive inferences. SDK 1.8 builders do not post these observations. Host activity summaries count measurement intervals, not games. Historical apps and missing observations may have no coverage; do not invent usage.

## Source naming

Existing app files named `entry-profile.js` describe feed-entry presentation and chrome. They are not the shared user-profile API. Do not infer identity support from that filename or rename those files for this integration. Use the public manifest and versioned contract above.

## Fixture acceptance

Use a small local adapter that accepts a profile reader as a dependency. Test a Promise resolving to a valid fixture, `{available:false}`, delayed resolution, rejection, unfamiliar schema, missing preference values, explicit user overrides, an existing save and a received riff. Assert that play starts before the read completes, text stays literal, and late data does not alter active state. This app-owned fixture harness requires no publication or model calls; it does not demonstrate hosted transport.

After runtime capabilities advertise server identity availability, test actual exact-revision hosted frames, reload, sign-out and storage denial. Report public documents read, SDK pins, app/family/revision, actual evidence and remaining gaps. Do not claim cross-device saves, account sync, avatar selection or top-level sensor continuity based on mocked profiles.
