# Community interactions — 2026-11-01 ## Scope and viewer extension Only idol-commons-dev is changed. The original Scenario Space is untouched. The minimum viewer extensions are an orbit-direction getter on the splat engine, optional community metadata in the collection adapter, a same-origin refresh/hide message, and an inspector layout override. Spatial placement, d3 navigation, search, original download bytes and engine lifetime are preserved. The shared canvas is not replaced. Community metadata changes do not recreate a selected WebGL scene. ## Thumbnail selection `POST /api/generations/{uuid}/thumbnail` accepts only a strict unit direction vector and an Idempotency-Key. Session, origin, CSRF, owner and TTL are checked; authenticated sessions are reverified with HF. No image, URL, path, camera target, projection or browser screenshot is accepted. The server fits the validated PLY bounds at the existing 35-degree field of view, with IDOL's -Y up axis. Zoom is normalized for consistent collection framing; the chosen angle is retained. Limits: 12 updates per anonymous session/day, 30 per HF account/day, 100 globally per hour. Anonymous quotas are not per-person quotas. One preview renderer runs at a time with the existing process memory/time limits. Preview failure remains recoverable without inference. Requests with the same key and body are idempotent. Publication is locked out until the new PNGs, hashes, crop and camera are ready. The private bucket acknowledges files before the ready state. A publication reservation prevents later edits to that private generation. Authors can edit the published thumbnail separately through My contributions. PLY bytes remain unchanged. The preview URL includes its hash to invalidate the private browser image cache. ## Likes and activity `PUT /api/assets/{uuid}/like` accepts only `{"liked": true|false}`. A real verified HF account owns one vote, independently of the browser session. The desired-state API makes repeats safe; unlike decrements the current total. `GET /api/basket` establishes a signed, HttpOnly browser cookie and returns the current private version. `PUT /api/basket` accepts only a version and a bounded list of asset IDs, with session/origin/CSRF checks. It replaces that browser's selection atomically; repeated syncs cannot add duplicate memberships. Version conflicts trigger a refresh/retry. Adding, removing, clearing, reopening, going back online and cross-tab storage changes synchronize the full local selection. The cookie survives sign-in/sign-out, so these are browser baskets, not people or account counts. Browsers are counted separately. No asset list is returned by the read endpoint; only aggregate counts are public. The viewer's `baskets` value counts memberships synchronized within 90 days. The signed cookie and private hashed membership records expire after 90 days of inactivity. The app renews active baskets; local selections remain local even if a count sync fails. Removed/unknown objects are excluded on synchronization. Old cumulative `basket_adds` values are preserved separately; historical occupancy cannot be reconstructed. Existing baskets enter the new count when the app is reopened. Dataset stats schema 1.1.0 adds `baskets` and still accepts 1.0.0 snapshots. No old totals are relabelled as current memberships. `POST /api/assets/{uuid}/activity` accepts only `basket_add` or `download_request`. These are app activity signals, available to valid anonymous sessions as well as verified contributors. Identity is HMAC-derived server-side. Each kind is counted at most once per asset/actor/UTC day. `basket_adds` is cumulative additions, NOT current basket occupancy. `download_requests` includes requesting a ZIP, PLY, script or copying the download command; it does NOT prove a file was saved and excludes direct Hub downloads. Cancellations/network failures can still count. A reset anonymous session can count again; these are estimates, not unique people. Activity tracking is best-effort in the client and never blocks local basket use or original-file downloads. Votes show recoverable errors and require sign-in. Quota: 60 changes per actor/10 minutes and 2,000 globally/10 minutes. Recent activity deduplication records are removed after 48 hours; rate windows after one day. Active vote hashes remain to support unlikes; inactive rows expire after 7 days. Only aggregates enter the public dataset. The existing private encrypted HF bucket is reused; no extra secrets or infrastructure are introduced. Keep SESSION_SECRET stable: it keys the private actor identities. `social/stats.json` is the validated versioned aggregate envelope; `social/stats.jsonl` exposes rows keyed by asset_id; `social/stats.schema.json` documents strict types and limits. No usernames, subjects, actor hashes or event logs are exported. Canonical records retain their declared licence and schema; new publications use 1.2.0. A stream ID prevents silent replacement of public totals by a fresh/incorrect private journal. Remote-newer revisions fail closed and persist a synchronization guard; later clicks cannot advance an older restored journal until it overwrites lost votes. An operator must restore and verify the correct private journal; never delete the guard merely to reset counts. Updates use the dataset-only writer, parent-commit CAS, bounded retry and lost-response reconciliation. The maintenance loop flushes at most once per minute when dirty; no per-click git commit. Rows for withdrawn assets disappear on the next successful flush. Public historical counters may remain in Git. The viewer reads private-journal aggregates through /api/catalogue immediately; the dataset snapshot is eventually consistent. Personal liked state and report visibility are included in a private no-store ETag, never a shared cached response. The catalogue refresh interval is 15 seconds; explicit successful actions request an earlier refresh. Navigation and zoom are retained. HTML entry points revalidate on navigation. The explorer frame URL includes the host's hashed bundle name to invalidate previously cached unversioned HTML. A reload therefore upgrades both workspaces together; hashed asset files are kept available for already-open sessions. ## Reports A successful verified report now quarantines the object from **all public viewer responses**, including anonymous requests. Existing open reports are included. Author/moderator inspection is through private management APIs, not an exception in the public catalogue. Selection and basket reconcile on refresh (up to 15 s). Hiding is not removal from the public dataset: immutable file URLs still work. Reports are private; authors do not receive reporter details/messages. Current report messages are available only to the configured moderator subjects. See [ASSET-MANAGEMENT.md](ASSET-MANAGEMENT.md) for authorization, removal and post-publication thumbnail updates. This supersedes reporter-only hiding. ## Publishing UX and rights An inline panel replaces the long modal: Details, then Rights & publish. SVG signals supplement text; they never replace affirmative rights/consent checks. Input and prompt remain private. Publication terms/schema 1.2.0 offer five per-asset licences with explicit consent, full legal documents and retained prior grants. No existing contribution is automatically relicensed. The IDOL repo declaration does not independently clear its demo images. See [LICENSING.md](LICENSING.md) for the precise source/result distinction and restrictions. ## Validation boundaries Automated API tests use isolated HF issuer/repository fixtures, including both local and encrypted bucket backends. They are not real multi-account OAuth tests. Browser acceptance uses the actual public PLY and its recorded camera, with mocked local API identity/actions so tests cannot create public votes, reports, metrics or assets. WebGL, software renderer, viewport sizes and physical-device limits are recorded separately in the acceptance report. Inference kernels, model weights, ZeroGPU scheduling and secrets are not changed by this release.