# Profile pictures

Document: SPEC-019. Revision: 1.2. Date: 2026-10-30. Lifecycle: D-096/R-102 requested upload/crop/preview/removal and circular presentation confirmed; engineering completion under existing implementation authority. Supersedes: nickname-only profile presentation, retaining nickname and qualified-identity rules.

## Contract

An approved home-account device can upload, replace or remove its profile picture. The client accepts PNG, JPEG and WebP files, offers square crop position/zoom with a circular preview, and re-encodes the selected crop as a static 256-by-256 PNG. Only the cropped image is uploaded; source files and source metadata are not retained. Render as a 56-CSS-pixel circle at default UI scale (D-100 supersedes D-096’s original 72-pixel target) beside right-sidebar people, with a neutral initials circle when absent or unavailable. Keep the username, action icons and recorded channel context in their requested vertical order alongside it. Pictures never identify a user for trust, permissions, message signing or routing.

Advertise `profile-pictures/1`. Extend the existing self-only, ticketed `account.profile` command to accept `profileRevision` plus at least one of `nickname`, `picture` or SPEC-020 `sounds`. A picture input is canonical base64url PNG bytes; null removes it; omission preserves it. Unknown fields reject. Both changes share the existing optimistic profile revision, conflict/draft/reconciliation behavior and home-device authorization. Profile changes do not rotate identity keys or alter room/media authority.

Store current image bytes separately from identity/history/address-book rows. Public profile metadata contains only an optional random UUID `picture` reference, bound to the person's home domain. Replacement/removal invalidates the prior reference and deletes its current stored bytes. Existing downloaded copies cannot be remotely erased. Resolve foreign home origins through authenticated identity discovery; never accept a user-supplied image URL or forward login credentials to a picture resource.

`GET api/profile-picture/<reference>` returns `{picture: <base64url PNG>}` only for an existing current reference whose owner is active. References are unguessable bearer read capabilities shared with viewers of existing profile projections, not a public account-directory lookup. Anyone possessing a reference can retrieve that image until replacement/removal/account disablement; these presentation images are server-readable, not E2EE content. Do not expose reference enumeration, account lookup through the image endpoint, external URL fetches or historical versions. Responses are no-store and use existing origin/body controls, with a fixed read budget of 240 requests per peer per minute. Clients fetch bounded JSON without credentials/referrers/redirects and render only validated PNG data URLs. Failed images use the fallback circle without disrupting messaging or voice.

D-185 adds bounded known-profile refresh under SPEC-005/008, updating only verified presentation labels and current picture references. Local current profile projections refresh picture references; saved/Recent foreign identities remain snapshots until a verified update is available. Never infer presence or query private membership to refresh a picture. Image bytes are neither copied into message author evidence nor persisted in contact/Recent vault records. Schema 6 (SPEC-012) remains sufficient: image records and optional references are additive within it.

## Configuration

No deployment setting or picture-specific size preference. Fixed limits: input file 10 MiB, decoded source at most 4096 pixels per dimension and 16,777,216 pixels total; cropped output 256 by 256 pixels; canonical PNG at most 300,000 bytes, at most 400,000 base64url characters; displayed circle 56 CSS pixels at 100% UI scale. SPEC-005’s whole-interface scale applies to pictures as well; the stored 256-pixel thumbnail and larger crop editor remain unchanged. Accept static PNG with 8-bit RGB/RGBA, no interlace, valid signature/chunk bounds/CRC, one IHDR, consecutive IDAT and one final IEND. Reject animated/metadata/unknown chunks in the uploaded canonical form; the client canvas output strips source metadata. The server validates this bounded PNG structure without expanding compressed pixel data. The browser must decode successfully for preview before upload and safely falls back on a decode failure while displaying. Default picture is absent. Store one current picture per account; removal/disablement stops resource reads. Reuse existing profile revision, ticket, account/body limits, origin handling and storage placement. Transient image caching stays bounded, account-scoped in rendered component lifetime, and is not retained in recovery/history copies.

## Testing

Unit coverage checks bounded canonical PNG structure, signature/dimension/CRC/trailing/animated/metadata rejection, profile authorization, stale revisions, retry idempotency, replace/remove resource invalidation, disabled owners, no secret/profile-key changes and persistence across restart. Browser coverage checks image selection, circular crop/zoom preview, save/cancel/remove, another client's rendered picture, directory/Friends/Recent presentation, fallback and narrow/light/dark layout. Foreign origin resolution must use the person's verified home and send no account credentials.

## Acceptance criteria

- User settings lets an approved device upload PNG/JPEG/WebP, position/zoom a circular preview, save the crop, cancel or remove the picture.
- The server stores only the current bounded canonical thumbnail and exposes its reference with the existing profile; full source files and image bytes do not enter identities/history/contact vault snapshots.
- Right-sidebar pictures render as 56-CSS-pixel circles at 100% UI scale with readable identities, icons and encounter context; absent/unavailable images show a fallback.
- Replacing/removing invalidates the old resource; stale or unauthorized writes cannot alter another account, and existing keys, calls and messages remain intact.
- Local and foreign profile viewing uses verified authorities and preserves credential boundaries; image failures do not block the rest of the client.
