contract + hub + web: profile pictures on public pages (humans with public_profile, agents), resized and cached
tsk-q155psrk6tzz in progress Maity Coder Claude 004 (maity-coder-claude-004)
Oliver decided this in seq 76508, after eyq5's profile inventory (76470): profile pictures are shown on public pages, scaled to their size and cached. Privacy: a person who sets the profile to private (public_profile off) shows no picture to the public.
Today this is excluded on purpose, in four places, and all four change in this card (inventory §3):
- Contract:
docs/api.md~9903 says "A public page grants no image (§16.9)". This becomes the new rule: a public person page withpublic_profileon, and every public agent page, grant their picture. - Read rule:
avatars.may_read(hub/src/maity_hub/avatars.py:251-305) andGET /avatars/{id}, which currently requires a session and a shared project. It becomes public for the cases in (1), withCache-Control: publicand a long max-age plus ETag or a versioned URL, so a change is still seen. Outside those cases it stays as today (private). - Size: serve fitting sizes (for example 32/64/128/256 px), scaled once at upload or on first request and kept, not scaled on every request. Re-encoding to PNG stays.
- Public pages:
public_people.pyandpublic_agents.pydraw the picture. The CSP inpublic_pages.py:37getsimg-src 'self'. Draw a placeholder when there is none. - KTW:
context/members.md:345-350rejected "a public page is enough to read the picture". That entry becomessupersededby a new one with Oliver's decision and the reason. Also resolve the contradiction withcontext/projects.md:547-548.
Not in this card: how agent pictures without an upload look (req-ms9y03z7a5g5 is still open with Oliver). This card shows whatever exists today: the upload, otherwise the placeholder.
Tests:
- a public read with
public_profileon and off; - an agent's page;
- the cache headers;
- the size variants;
- the CSP;
- a per-human test for anything newly stored about a person (deletion and export);
- PostgreSQL first if the change adds a migration or raw SQL.
The contract goes first as its own PR. Before the merge, check any new §1.3 codes against web/js/errors.js.
Notes
Maity Coder Claude 004 (maity-coder-claude-004) ·
Step 1 of 3 (contract): #1408, merge-ready at bf3657287fd6707419a6af71346197b6dc527f5a. Step 2 is the hub PR, step 3 the web PR. The card is reported once, with the last PR (lotse 77799).