You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Part of #1058 · Advances #1022 (ops/stats/self-improve) · Depends on #1011 (unified engine) and #1025 (historical backfill)
Why
Every PR gittensory handles is proof the system works — and we've already handled 1000+ across the repos we run. We have the data (review_targets, review_audit, gate_outcomes) but no public exposure. Surface it on the homepage hero, above the fold, as a live counter: an onboarding asset and a credibility signal for a technical audience. Lead with both volume and accuracy.
This issue also owns the shared pr_outcome ground-truth plumbing that the close-the-loop epic's accuracy/trust and feedback-loop children depend on (see deliverable 1).
Data sources (already exist — no new capture needed for volume)
Lifetime handled: COUNT(*) FROM review_targets per project (migrations/0050)
Outcome split (merged / closed / held / manual): review_targets.verdict + status
Human-reversal rate: review_audit WHERE event_type LIKE 'reversal_%' (migrations/0049)
Existing aggregation logic (currently bearer-gated, to be reused): src/review/stats.ts (computeStats), src/review/ops.ts (computeCalibration)
Requirements
The lifetime number must reflect the true total, including PRs handled by reviewbot pre-convergence — not just post-cutover gittensory-native records.
Accuracy must be defined honestly and defensibly (reversal-grounded: a decision is "correct" unless a human later overrides/reverts it). The definition must be documented publicly.
The public endpoint must be cheap to serve (cached, O(1)) and expose no sensitive data — aggregates only, no PR content, actor logins, scores, or rewards.
The hero counter must match the existing design system and reuse existing patterns (no new realtime infra).
Deliverables
pr_outcome ground-truth plumbing — write a pr_outcome event to review_audit on pull_request.closed / merged (event type exists; review_targets.terminal_at is the hook). Enables real accuracy = agree(verdict, outcome) / decided. (Shared foundation for the epic.)
Rollup tablepr_handling_stats(date, project, handled, merged, closed, held, blocked, reversed, accuracy) refreshed by the existing */30 cron (wrangler.jsonc).
Public endpointGET /v1/public/stats (Hono, no auth, Cache-Control: public, max-age=60, stale-while-revalidate=300) in src/api/routes.ts; regenerate OpenAPI via npm run ui:openapi (src/openapi/spec.ts).
Hero band component — new RealtimeStatsCounter in apps/gittensory-ui/src/components/site/, placed between <Hero/> and <MetaStrip/> in apps/gittensory-ui/src/routes/index.tsx. Reuse the Stat primitive, the useApiStatus 60s polling pattern (lib/api/status.ts / GithubStatsChip), and the motion count-up. Four stats: PRs handled · auto-merged · decision accuracy · slop blocked, with a "Live · updated Ns ago" freshness line.
/stats detail page (optional follow-up) — per-repo breakdown + trend, and the public accuracy-definition writeup.
Acceptance criteria
Homepage hero shows four live stats above the fold, polling every 60s, matching the design system in light + dark mode.
GET /v1/public/stats returns cached aggregates with no auth and no sensitive fields; OpenAPI updated.
Part of #1058 · Advances #1022 (ops/stats/self-improve) · Depends on #1011 (unified engine) and #1025 (historical backfill)
Why
Every PR gittensory handles is proof the system works — and we've already handled 1000+ across the repos we run. We have the data (
review_targets,review_audit,gate_outcomes) but no public exposure. Surface it on the homepage hero, above the fold, as a live counter: an onboarding asset and a credibility signal for a technical audience. Lead with both volume and accuracy.This issue also owns the shared
pr_outcomeground-truth plumbing that the close-the-loop epic's accuracy/trust and feedback-loop children depend on (see deliverable 1).Data sources (already exist — no new capture needed for volume)
COUNT(*) FROM review_targetsperproject(migrations/0050)review_targets.verdict+statusgate_outcomes.blocker_codes_json,overridden(migrations/0041)review_audit WHERE event_type LIKE 'reversal_%'(migrations/0049)src/review/stats.ts(computeStats),src/review/ops.ts(computeCalibration)Requirements
Deliverables
pr_outcomeground-truth plumbing — write apr_outcomeevent toreview_auditonpull_request.closed/merged(event type exists;review_targets.terminal_atis the hook). Enables real accuracy =agree(verdict, outcome) / decided. (Shared foundation for the epic.)review_targets/review_auditso the counter shows the true 1000+. Blocker for an honest lifetime number.pr_handling_stats(date, project, handled, merged, closed, held, blocked, reversed, accuracy)refreshed by the existing*/30cron (wrangler.jsonc).GET /v1/public/stats(Hono, no auth,Cache-Control: public, max-age=60, stale-while-revalidate=300) insrc/api/routes.ts; regenerate OpenAPI vianpm run ui:openapi(src/openapi/spec.ts).RealtimeStatsCounterinapps/gittensory-ui/src/components/site/, placed between<Hero/>and<MetaStrip/>inapps/gittensory-ui/src/routes/index.tsx. Reuse theStatprimitive, theuseApiStatus60s polling pattern (lib/api/status.ts/GithubStatsChip), and themotioncount-up. Four stats: PRs handled · auto-merged · decision accuracy · slop blocked, with a "Live · updated Ns ago" freshness line./statsdetail page (optional follow-up) — per-repo breakdown + trend, and the public accuracy-definition writeup.Acceptance criteria
GET /v1/public/statsreturns cached aggregates with no auth and no sensitive fields; OpenAPI updated.review_targets+ backfilled records.Out of scope
Labels:
roadmap,maintainer-only,visual· Assignee: @JSONbored