Open Algorithms & Code
Every algorithm that shapes your experience is documented here — in plain language, with the actual formulas, and direct links to the source code.
When an algorithm decides who sees your profile, how your reliability is scored, or which sessions appear in your feed — those decisions affect real-world interactions. A late-cancel penalty isn't just a number; it's the difference between a full table and a canceled game night.
We believe you deserve to understand how every scoring and matching system works. Not in vague marketing terms — in actual math, with the real weights, thresholds, and design tradeoffs explained.
Each section below documents one of our algorithm systems. You'll find the formula, the reasoning behind key decisions, and a direct link to the source code on GitHub. If something seems wrong, you can open an issue.
Algorithm Directory
Player Reliability Score
The Player Reliability Score is an attendance-based metric that reflects your actual track record at game tables — not your popularity, not your social connections, just whether you show up when you say you will.
How It Works
Score = (weighted_sum / game_count) × 100
Clamped to range [0%, 100%]
| Status | Player Weight | Host Weight |
|---|---|---|
| Attended | +1.0 | +1.0 |
| Late Cancel (<24h) | −0.3 | −1.2 |
| No-show | −1.0 | −1.5 |
| Excused | 0.0 | 0.0 |
| Cancelled Early (>24h) | 0.0 | 0.0 |
Tier Classification
≥ 95% and ≥ 5 games
≥ 5 games (any score)
< 5 games
Design Decisions
- Hosts face steeper penalties for late cancellations and no-shows because they affect every participant signed up for that game, not just themselves.
- Grief resistance: attendance is settled by a weighted consensus of reports (see Attendance Resolution), so no single reporter can decide a status — a participation threshold and a majority must agree before any penalty applies.
- Scores are fully recomputed on every attendance change (not delta-based) to guarantee correctness and prevent drift.
Attendance Resolution
When a game ends, the host and participants can each file an attendance report for the same player — and they don't always agree. Attendance Resolution reconciles those reports into a single resolved status that feeds the Player Reliability Score. It is a consensus system with a deliberate default-to-attended bias: an absence has to be proven by a majority, never assumed.
Resolution Methods
Every approved participant files a report, so the status resolves as soon as the game completes — no waiting.
If reporting stalls, the game auto-completes once the window closes and resolves each player from whatever was filed.
An administrator can resolve attendance directly when a dispute needs a human decision.
How a Status Is Decided
At least half of the other participants must file a report. Below that, the player defaults to Attended.
If the host marks a player Excused, that wins — the host is authoritative for excuses only.
More than half of the weighted votes must be "no-show" for an absence to be recorded.
Anything else — a tie, no reports, or a solo game — resolves as Attended.
Reports are accepted for 72 hours after a game ends; games auto-complete 12 hours after their scheduled end time.
Design Decisions
- Default-to-attended: no single report can ever penalize a player. An absence requires a proven majority.
- The host can excuse, but only the consensus can mark a no-show — host authority is deliberately limited.
- Reports are weighted, so low-reliability reporters carry less influence. The exact abuse-defense thresholds are intentionally not published.
GM Ratings & Reviews
GM Ratings aggregate community feedback for game masters into an average score and review count. Only published reviews contribute to the aggregate — reported or hidden reviews are excluded entirely.
How It Works
Average Rating = COALESCE(AVG(rating), 0)
Review Count = COUNT(*) WHERE status = 'published'
Proficiency Badges = TOP 3 tags by frequency across published reviews
Only reviews with status "published" are included. Reviews that are reported or hidden are excluded from all calculations.
Design Decisions
- Only published reviews count toward the average. Reported or hidden reviews are excluded to prevent manipulation and ensure fairness.
- Aggregates are recomputed when a review is created or deleted, and whenever a review changes status (for example, when a reported review is hidden or restored). This keeps the displayed score in sync with the current published set.
People Discovery
People Discovery suggests nearby players based on taste compatibility and social overlap. It uses your game system preferences, vibe preferences, team memberships, and social connections to find people you'd enjoy playing with. Results are precomputed by a background job and served from cache for fast page loads.
Pipeline
Runs a single query across the 4-character geohash tile (~20km) and the surrounding 3-character tile (~100km) at once, so city and regional neighbors are covered together. Blocked users and existing follows are excluded via a SQL subquery. The geographic candidate pool is capped at 50 to keep memory bounded.
If the viewer has favorite game systems, additional candidates who share those preferences are pulled in — even outside the geographic radius — ensuring taste affinity is represented.
A single SQL JOIN query computes all overlap counts (shared game systems, shared vibes, shared teams, mutual follows) server-side, avoiding bulk PHP loading. The database returns at most 100 scored rows.
Computes taste similarity (Jaccard on game systems + vibes) and social overlap (team overlap + mutual follows). Results are privacy-aware: hidden fields reduce available signals.
Results are precomputed by a background job and cached per viewer per geohash tile for 5 minutes. The page reads from cache only — if the cache is cold, a "still looking" state is shown while the job runs. Paginated at 12 per page.
How It Works
Taste: J(A, B) = |A ∩ B| / |A ∪ B|
Computed on game systems + vibes, averaged
Social: (team overlap + mutual follow) / components
Composite:
if taste & social: score = taste × 0.7 + social × 0.3
if taste only: score = taste
if social only: score = social
| Component | Weight (both available) |
|---|---|
| Taste similarity | 0.7 |
| Social overlap | 0.3 |
When only one signal type is available, it receives 100% weight.
Design Decisions
- Privacy-aware reweighting: when a candidate has hidden fields (game systems, vibes, teams), those signals are excluded from scoring and remaining signals get proportionally more weight.
- Blocked users are excluded from the candidate pool entirely — they never appear as discovery results.
- When all signals are hidden (only location visible), the candidate appears with "Nearby" as the sole match reason, so the UI still shows something meaningful.
Session Recommendations
Session Recommendations suggest games and campaigns matched to your preferences. It uses a two-tier approach to surface the best matches first without penalizing users who haven't set vibe preferences.
Two-Query Approach
Matches sessions that share your favorite game systems AND favorite vibes. These are the strongest matches.
Matches sessions by favorite game systems regardless of vibes. Surfaces relevant sessions even without vibe overlap.
Results are deduplicated by type+id, with boosted results shown first. Capped at 12 total recommendations.
Preference Resolution
allowed = (favorites + implied_favorites) − avoided
Boosted: allowed AND favorite_vibes
Fallback: allowed (any vibe)
| Rule | Behavior |
|---|---|
| Base game favorited | Expansions become implied_favorites |
| Explicit avoid | Always wins over favorite or implied |
| Vibe exclusivity | Favoriting one auto-avoids its partner |
Design Decisions
- Favorited base games automatically include their expansions as "implied favorites" — you don't have to favorite every expansion separately.
- Explicit avoid preferences always win over favorite or implied — if you avoid a system, it stays excluded even if it's an expansion of a favorite.
- Vibe mutual exclusivity: favoriting one vibe auto-avoids its partner (e.g., "Competitive" auto-avoids "Cooperative").
Gatherings
A Gathering is a lighter, multi-system session like a board-game night. In discovery feeds, gatherings are capped at roughly one per page and ranked just below focused single-system games on the same date, so they never crowd out specific games. In your recommendations, a gathering appears whenever any of its offered systems matches your favorites — treated like any other game.
Proximity Engine
The Proximity Engine powers geographic queries for finding nearby sessions, players, and venue hubs. It uses a two-phase approach: a fast bounding-box filter followed by precise Haversine distance calculation.
Two-Phase Approach
Uses a composite (latitude, longitude) B-tree index for fast row elimination. The box is the smallest rectangle that contains the search circle — its corners reach past the circle, so nothing is missed.
Applies the Haversine formula for precise distance calculation, filtering results to the exact radius.
How It Works
d = 2R × arcsin(√(
sin²(Δlat / 2) +
cos(lat₁) × cos(lat₂) × sin²(Δlng / 2)
))
where R = 6371 km (Earth's radius)
Geohash Tile Sizes
| Precision | Approximate Size | Use |
|---|---|---|
| 4 chars | ~20km × 20km | City-level caching |
| 5 chars | ~4.9km × 4.9km | Neighborhood-level |
| 6 chars | ~0.6km × 1.2km | Venue-level |
Hub results are cached per geohash tile (5-char ≈ 4.9km × 4.9km) with a 15-minute TTL.
Design Decisions
- The bounding box is the minimal rectangle enclosing the search circle (its corners extend past the circle). The Haversine formula then filters to the precise radius — this two-phase approach uses the B-tree index for speed.
Location Disclosure & Privacy
Every address and distance you see — on a game, campaign, or venue page — is decided by a single service. Location Disclosure graduates how much of a location is revealed based on the nature of the place and your relationship to the host. Privacy is the default, not the exception.
Address Rungs
Full street address
Locality name only
“In your area” (geohash-tile based)
Nothing shown (blocked viewer or unresolvable location)
Decision Matrix (private locations)
| Your relationship to the host | Address shown |
|---|---|
| Owner or approved participant | Exact |
| Friend or teammate | City |
| Stranger or guest | Area |
| Blocked | None |
Verified commercial venues (cafés, game stores, libraries, community centers, conventions, bars) show their exact address to everyone — they are public spaces.
Distance Display
Precise distance (e.g. “4.2 km away”)
Grid-snapped to the nearest 5 km (e.g. “≈ 5 km away”), with a 5 km floor — exact positions cannot be triangulated.
Design Decisions
- Fail-closed: if anything can't be determined, the service reveals the least it can (Area, or nothing) — never more.
- Precise distances are reserved for verified public venues. Private locations always get a grid-snapped distance to prevent triangulation.
- A public venue page requires a commercial type that is verified or admin-managed. “Other” and untyped locations never qualify.
Trending & Popular
Trending Near You shows location-scoped game sessions based on participant engagement within your geographic area.
Selection Criteria
| Parameter | Value |
|---|---|
| Geographic scope | Geohash-4 tile (~20km × 20km) (~20km × 20km) |
| Time window | Next 14 days |
| Visibility | Public sessions only |
| Sort order | participants DESC, created_at DESC |
| Limit | Top 5 per tile |
| Cache TTL | 10 minutes |
Design Decisions
- The 14-day time window prevents historically popular games from dominating — only upcoming sessions are considered.
- Geohash-4 scoping (~20km × 20km) keeps results genuinely local rather than surfacing popular games from the other side of the city.
Platform Score
The Platform Score ranks game systems by community engagement using a weighted formula that accounts for favorites, total games, campaigns, and active (scheduled) sessions.
How It Works
score = (favorites × w₁) + (games × w₂)
+ (campaigns × w₃) + (active_games × w₄)
| Signal | Board Games | TTRPGs |
|---|---|---|
| Favorites | 10 | 10 |
| Total Games | 3 | 3 |
| Campaigns | 5 | 15 |
| Active Games (scheduled) | 20 | 10 |
Design Decisions
- Board games weight active sessions highest (20 pts) because a currently-scheduled game is the strongest signal of community engagement.
- TTRPGs weight campaigns highest (15 pts) because ongoing campaign play is the primary activity metric for tabletop roleplaying groups.
Read the Code Yourself
Every algorithm documented here runs from our open-source repository. Clone it, audit it, open an issue — it's all yours.