shorts worker: Street Soccer Pro shorts (posted clips): counts, likes, follows, verdicts, TOP CLIPS, WEEKLY BEST Every /v1 route but /v1/erasure takes Authorization: Bearer INGEST_TOKEN and a universe id (game.GameId); each universe keeps its own shorts, and only those in UNIVERSES are served (403 otherwise). Bodies are shorts.v1 protobuf (proto/shorts.proto), Content-Type application/x-protobuf, POST only. Tapes live in the game's DataStore, not here. POST /v1/post PostRequest -> PostResponse. Stores a short (LIVE). Result 3 and nothing stored when sharing is false or any of its moment keys is blocked for the owner: on one of their HIDDEN or held shorts, or in blocks (kept when a short goes while HIDDEN or held, or by a moderator's REMOVE; only erasure deletes them). Over 30 live shorts per creator the oldest ones not crowned, not on an open shortlist and not HIDDEN or held are retired, listed in retired and queued in forget. Same ref twice: result 1. Never writes the creator's sharing flag. Keeps up to 8 tags (ids 1..64, others ignored); every Short answered carries its tags. Indexes the kind and tag names, owner name and display name and the short's text (first 400 bytes) for search. POST /v1/item ItemRequest -> Result. Stores the RecommendationService ItemId of the owner's short. POST /v1/vis VisRequest -> Result. Owner sets PUBLIC 1, UNLISTED 2, PRIVATE 3 (LIVE shorts only). POST /v1/delete DeleteRequest -> Result. Owner deletes; likes and reports go with it; queued in forget. Result 3 with the short while it is HIDDEN or held (under review): nothing deleted. POST /v1/page PageRequest -> PageResponse. Metadata, counts, liked, following and mark for the refs this viewer may see (LIVE, PUBLIC, creator sharing; owners see their own), in the order asked. POST /v1/events EventsRequest -> EventsResponse. A batch's rows and its outbox row (the verdicts, likes, follows and reports it newly writes, plus its counts) commit in one D1 write, once per batch id; every attempt sends the outbox's sums to the Tally, which dedupes by batch id, so a retry delivers what the first attempt wrote and a replay never writes rows again (result 1 = already delivered). A Tally miss leaves the outbox row for the next cron; delivered rows keep only their reported refs, for 1 day. Verdicts only while the short is PUBLIC and LIVE, one per viewer per short for 2-3 weeks; likes (with reaction), follows (500 per user), reports, votes (open week's nominees, vote phase only) apply at once; counters reach the shorts every 30 min. A LIVE short not held hides once its uncleared w = 1 reporters reach max(3, ceil(engaged / 50)); with engaged >= 200, crowned or on a chart it is held instead (off the charts, in QUEUE) and a moderator decides. hidden lists the batch's reported shorts that are HIDDEN, retries included. forgotten acks removed shorts; forget leases up to 50 still to remove from RecommendationService and DataStore for 5 min (unacked ones come back). POST /v1/chart ChartRequest -> ChartResponse. tab 2 FOLLOWING, 3 TOP (chart 1 TRENDING, 2 WEEK, 3 ALL_TIME), 4 WEEKLY (week 0 = latest; no nominees during review; winner = latest crowned), 5 CREATOR, 6 LINK (ref; UNLISTED too), 7 MINE, 8 SEARCH (query text, else tag; chart 1 TRENDING, 3 ALL_TIME or 4 NEW over the newest 500 matches plus that chart's matching members; TOP's visibility, one per moment). Tab 1 is a 400. POST /v1/suggest SuggestRequest -> SuggestResponse. Live search box: up to 6 creators by username or display name prefix (most followed first) and 6 PUBLIC, LIVE shorts by full-text match (bm25 blended with the trend score; owner_name filled). Text is normalized as @shared/shorts.query: trimmed, one leading @ dropped, whitespace collapsed, ASCII lowercased; outside 2..32 characters = no hits. POST /v1/creator CreatorRequest -> CreatorResponse. Last-known IsContentSharingAllowed; a flip lists PUBLIC items to make Private (hide) or Public again (show). POST /v1/moderate ModerateRequest -> ModerateResponse. action 1 HOLD, 2 CLEAR (lifts the hold and clears its reports; result 1 when neither was there), 3 HIDE, 4 RESTORE (HIDDEN to LIVE, clears its reports), 5 REMOVE (blocks its moment keys for the owner), 6 VETO (this week's shortlist, review and vote phases), 7 BAN (removes every short of user and refuses their posts for duration seconds, 0 = for good; banned_until in the reply), 8 UNBAN (user), 9 QUEUE (up to 25 shorts not removed that are held or carry uncleared reports, heaviest uncleared report weight first, in reported; held marks held ones). Cleared reports stay stored, never count again and keep their reporters from reporting that short again. Removals queue forget. POST /v1/erasure Roblox right-to-erasure webhook, JSON, signed with ERASURE_SECRET (roblox-signature header). Queues the user; the hourly job erases 20 users a run and queues their shorts in forget. Bookmarks: page, chart and suggest read through a D1 session (read replicas) started from the request's bookmark (empty = any replica); every other route writes through a session started on the primary. Every response carries the session's bookmark; send the latest one back on reads to see your own writes. result: 0 ok, 1 already, 2 missing, 3 forbidden, 4 cap (reserved), 5 closed, 6 banned (post from a banned owner). Crons (UTC): :30 undelivered outbox + flush + TRENDING; :00 undelivered outbox + flush + holds + weekly steps (shortlist Monday 00:00, vote Monday 12:00, crown Wednesday 00:00, each caught up if missed) + every chart + erasures; both also merge any spill rows; 04:23 drops old verdict weeks, uncleared reports past 30 days, delivered outbox rows past a day. 400 malformed, 401 auth, 5xx failure, as plain text. X-Body-Encoding: base64 carries protobuf bodies as base64 text.