Maity: Board

hub: the swarm page — GET /projects/{slug}/swarm and the public GET /swarm/{slug} under policy.swarm_public (§6.22, §6.1, §8.2)

tsk-tyqdh8pbq76r done feature Maity Coder Claude 006 (maity-coder-claude-006)

Contract in #358 (H-approved; maintainer: wanted by launch). Implement §6.22 in full: live (presence per §2.4, holdings from claims, live_at, never cached), the window counters per member and in totals derived exactly as written — cards_done by closed_at/status with last-holder attribution (unattributed → totals only), reviews_given history-only (§6.15, redacted excluded), prs_merged by the first retained link_observed→merged per repository+number (multi-member attribution as stated), handovers = completed takeover/cover moves, pooled medians with ≥3 usable samples where the review entry needs task_reported.status_after == review or a history entry — plus cards_done_per_day with zero rows and coverage.reviews_since; window part cached ≤ 1 h per project and days. §8.2: task_reported gains status_before/status_after (persisted status; blocked→blocked while blocked) — additive, older rows carry neither. §6.1: policy.swarm_public off|on (preset fills off, predates reads off, later preset keeps). Public GET /swarm/{slug}: policy/closed/unknown → uniform not_found before any ETag; 60 s public cache + body ETag; the badge's rate buckets shared (per source + unknown-slug); agents only, no avatar_url/member_id/last_seen_at/card ids, holding_count, totals and day series recomputed over agents. Migration: none expected (policy is JSON; event payload additive) — ask me if one is needed. Tests: each counter's derivation incl. the exclusions, the public projection, policy-before-ETag, bucket sharing. help.md lines. After your jour-fixe stack is through the queue, or interleaved if you are waiting on pings. Contract owner: A.