# Pictures

## Success criteria

A completed photo enrichment needs a supported identity match, actual decodable image bytes, visual inspection for suitability, and a successful stored result in Ray. Since 2026-10-24 Ray refuses a picture that arrives as an address without `image_base64`; `picture_storage: external` appears only on records saved before then. `picture_storage: stored` confirms storage, not that the image depicts the correct person.

Read `get_profile` first. Inspect `picture_storage`, source metadata, prior checks, and protections. A stored picture may be usable even when its original source URL now fails. Do not replace a good stored image merely because the source is no longer accessible.

## Find and check a candidate

1. Establish identity using the research guide. Prefer an official team page or personal site with a named portrait. A verified public GitHub or social account can also provide an image. A firm needs its logo, not a person's portrait.
2. Follow the image URL present in the verified source. Never invent CDN paths, signing parameters, profile slugs, or placeholder URLs. Search images can help locate a source, but a thumbnail without identifying context is not sufficient.
3. Download the actual bytes. Check the HTTP result and decode the file; a `.jpg` suffix, an image-looking URL, or HTTP 200 alone does not establish an image. A login page, HTML response, or plain-text 403 is a failed fetch.
4. Visually inspect it. Check that it is a usable portrait or logo, rather than a site banner, generic silhouette, group shot, or unrelated graphic. Use the source to establish who is pictured; visual appearance alone does not establish identity.
5. Resize and compress with an available image-processing tool. The current contract accepts a single still JPEG, PNG, or WebP, at most 32,000 decoded input bytes and 4 million pixels; Ray normalizes to a WebP within 512 × 512. Verify current limits from the live schema. Keep the whole MCP request within its size limit, currently 64 KiB.
6. Call `enrich_profile` with actual base64 bytes in `enrichment.picture.image_base64` without a data-URL prefix. Retain the original download URL, identifying source page, and observation time. If a picture already exists, pass its current URL as `enrichment.expected_picture_url`, including when storing bytes for that same URL.
7. Respect the returned capture status. After an applied write or approved proposal, read the profile to confirm `picture_storage: stored`. If browser access is available, verify the displayed result as well. Report any display check you could not perform.

If the result says the picture is also on another record, stop there before the next write. Ray saves it and names the other records in the result's summary and `suggestions`, rather than refusing, because a person recorded twice may rightly have the same photo on both records. Check that the source page shows this image for this record by name; remove it with `remove_profile_item` if it does not, and if the two records are one person or firm, follow the [duplicates guide](duplicates.md). A run of records sharing one image is how invented headshots look.

If the environment cannot download, inspect, or upload bytes, explain the incomplete step. Do not substitute a generated face or unrelated image. Follow user instructions for any requested image editing; identity photos should remain faithful to the supplied original.

## Failures and corrections

A 403 means the request was refused. It does not prove that a genuine photo was found, that the URL will work for the user's browser, or that the person has no public picture. Move to a verified alternative source instead of repeatedly guessing URL variants.

When inspecting existing records, distinguish a local network failure from an upstream HTTP error. Record only checks actually performed. Literal `t=placeholder` parameters are evidence of an incomplete URL; they must not count as successful enrichment. If cleanup is requested, use `remove_profile_item` with `platform: "picture"` and the exact current URL to remove confirmed unusable external entries while preserving audit history. An assessment alone does not authorize bulk deletion. Removing a picture also ends its protection, so later research may propose another under the research capture rule.

When identity is uncertain or no suitable source is available, retain initials and explain what would resolve the gap. A user-supplied portrait or confirmed profile can help.

## A photo the user gives you

A photo the user hands over themselves (a file, an attachment, an image pasted into the conversation) has no public address, and needs none. Inspect it as in steps 4 and 5 above, then call `enrich_profile` with `user_requested: true` and `picture` holding only `image_base64` and `observed_at`, the time the user gave it. Leave `picture.url` and `picture.source_url` empty, and write in `identity_evidence` who gave the photo and what they said about who it shows. Never make up an address for it: an invented URL records a source that does not exist. The saved picture is protected as the user's choice.

`get_profile` then shows the picture with no URL; `picture_digest` names it. To replace it, pass that digest as `enrichment.expected_picture_digest`; to remove it, call `remove_profile_item` with `platform: "picture"` and the digest as `url`.

Treat identity verification, download availability, storage, and display as separate facts in your report. Do not describe all four as successful because one succeeded.

## Auditing old external pictures

A repeated CDN identifier across different people or a guessed-looking `/logo.png` path is a reason to investigate, not proof of fabrication by itself. A 403, connection failure or expired URL does not establish how the original value was obtained. Preserve the observed status, response type, observation time and supporting source evidence without guessing authorship. A 200 HTML response is not a verified image; an unchecked URL must remain unchecked, however plausible it looks. Count the itemized records before reporting totals.

A HEAD request can help diagnose a link but cannot validate decoded image bytes or identity, and some servers treat HEAD differently from GET. Ray validates uploaded bytes; it does not fetch submitted URLs, and it no longer saves one on its own. The only path is to retrieve a sourced image in the agent, decode and visually inspect it, then supply `image_base64` and verify stored status. Read `picture_storage` before declaring a profile broken or proposing removal: a stored copy can still work after its source expires. A professional photo on a social service may be suitable if identity and content are verified; the hosting service alone does not decide suitability.
