Append-only attendance ledger
Every point ever awarded is a row that is never edited or deleted. Every total is just a sum over those rows.
One row per member per settled raid: guild, user, party, points, reason, an optional season id, and a timestamp. Rows are only appended — the two reasons the bot writes are settlement and undo, and an undo does not delete the original, it writes the negative of it. This was in the very first schema, before anything displayed it, because attendance is the one thing that genuinely cannot be backfilled: if it was not captured when the raid settled, the data does not exist. Everything downstream reads a SUM over this one table.
The ⚖️ counter, ×1 to ×5
One click on the 🧩 Roles panel says this raid counts for more. Same button in the builder and on the live raid.
Each raid stores a weight, and every attending member earns that many points at settle. The cap is deliberate: high enough to mark a CTA as worth a handful of gank squads, low enough that one raid cannot dominate a season split or a weighted draw. On the posted raid’s console the button is officer-gated even though its neighbours are open to the raid’s caller — attendance points are economics, and a caller may be a non-officer.
The weight is printed on the raid card
Above ×1 the public post says "⚖️ Counts ×3 for attendance — each raider earns 3 points instead of 1."
A weighted raid is a recruiting argument, so members are told before they sign up rather than afterwards. The line is suppressed at ×1 and on casual raids, whose mode line already says nothing is tracked. It renders the raw stored weight rather than a rounded one — a legacy raid stored at 1.5 shows ×1.5, because settle awards exactly what is stored and the card must promise what settle does.
Awarded at settle, and only at settle
Closing a raid, calling it off, or letting the reaper auto-close it writes zero attendance rows.
There is exactly one place attendance points are created: the settle transaction, alongside the silver. It has its own regression test — an auto-closed raid that an officer later settles awards its points exactly once, no more. The practical consequence is that a raid which ran but looted nothing still has to be settled to count. Enter a gross of 0, optionally with a participation bonus, and the settle becomes pure attendance pay.
Bench attendance policy
Decide whether standbys earn attendance points, independently of whether they get silver.
The bench is the flex pool: people who turned up but held no slot because the comp was full. What they get is one stored policy with two independent axes — silver and attendance — so a guild can pay a standby without letting them bank season weight for a fight they did not take, or grant the points without the silver. /settings → Raids shows the current answer as a Bench gets line and carries a button per axis, each labelled with what a press would turn on (🪑 Bench: share loot, 🪑 Bench: count attendance) or off. The policy resolves guild default → content profile → per-raid snapshot frozen at creation, so a change can never rewrite what a live raid already promised.
Caller bonus points
An optional flat attendance bonus for whoever led the raid, on top of any member award.
Set per guild in /settings → Economy as Caller bonus points, default 0. Above zero, the settle writes one extra attendance row for the raid’s caller in addition to whatever they earned as a participant. Leading a raid is work a plain participation count does not capture, and this is the attendance half of caller compensation — the silver half is a separate off-the-top caller cut. It applies to both immediate and season-pool settles.
/stats me and /stats player
Raids attended, raids benched, attendance points, lifetime earned, paid out, balance and ratings, in one private reply.
/stats me is open to anyone; /stats player <user> is officers only and refuses a non-officer with a pointer to /stats me. Attended-versus-benched counts come from the frozen settlement snapshot, so later edits to a roster never rewrite history. Earned and paid out are split by the SIGN of each ledger entry rather than by reason, which makes them reconcile by construction: earned minus paid out always equals the current balance.
/stats caller — caller efficiency
Raids called, gross total and average, repair as a percentage of gross, average party size, and the outcome tally.
Anyone can run /stats caller on themselves or name another caller. Casual raids are excluded from every figure on purpose: a casual raid’s gross is typed by whoever ran it with no officer review, and a non-officer can both call and settle their own — counting them would let anyone inflate their own caller reputation at will. Two regear lines are shown when they apply: regear the person approved as an officer, and regear their own raids cost the guild. They are never merged, because two similar numbers under one label is how a stats card stops being trusted.
Raid outcome captured at settle
A one-click ✅ Success / ➖ Partial / 💀 Wipe picker on the settle board, feeding the per-caller record.
The outcome sits on the settle preview board as a dropdown, not in the modal. It used to be a free-text field expecting one of three magic words and silently coercing anything else to "unknown", which meant the statistic it fed was mostly "unknown". One click costs nothing and gets answered. An unanswered picker still stores "unknown" rather than inventing a result.
Mutual post-raid ratings
Crew rate the caller, the caller rates the crew, 1 to 5. Opt-in per raid via the builder’s ⭐ toggle.
Ratings are off by default and turned on for a specific raid in the builder. When on, the settled raid post keeps a single ⭐ Rate this raid button. Who you are decides what the ephemeral panel shows: a confirmed crew member gets one row of 1⭐ to 5⭐ buttons for the caller; the caller gets a dropdown of the crew, then a score row for the person they picked, and the picker stays so they can work through the roster. Someone who was not on the raid is told "You weren’t part of this raid." Each score is one upsert keyed on raid, rater and ratee, so clicking again revises rather than stacking.
Ratings split by the role you held
Your average as a caller and your average as crew are reported separately, never blended, on /stats.
The summary query classifies each rating by whether the person being rated was that raid’s caller. So one member can carry "as caller 4.6⭐ (12) · as crew 4.3⭐ (28)" and the two numbers stay honest — one average over both would tell you neither. Someone with no ratings yet simply reads "no ratings yet" rather than a fake zero.
Opt-in public rating leaderboard
/rating public state:on puts you on /rating board. Off is the default and stays off until you choose.
Nobody appears on the public board without explicitly opting in, stored per guild. /rating public state:off removes you again at any time. The board lists up to 25 opted-in members ranked by average score with the number of ratings in brackets, ties broken by the number of ratings, and it is posted as a private reply so it never becomes a permanent wall-of-shame message in a channel. An empty board tells you how to opt in rather than showing nothing.
Season pool split by weighted attendance
Loot accrues over a season and is divided at the end in proportion to each member’s points.
While a season is open, guild raids settle into a pool instead of paying out per raid. Outsiders are still paid immediately per content; member shares go into the pot. Attendance rows written during a season carry that season’s id, so the split reads exactly the points earned inside it. /season end divides the pool proportionally, floors every payout so silver stays whole, and sweeps the rounding remainder into the regear bank. /season status shows any member their own points, the guild total, and what their share would be right now.
Attendance-weighted giveaway odds
One ticket, plus one per attendance point in the last 28 days, up to ten. The rule is on the card and your own ticket count is shown when you enter.
A giveaway’s ⚖️ Odds panel can weight the draw by attendance. Points rather than a raid count is the point: points already carry content weight, so a ZvZ counts more than a gank squad. The floor of one ticket is load-bearing twice — a newcomer with no history can still win, and negative points from an undo can never zero somebody out. The cap of ten is the fairness lever: without it a single dedicated raider would own every draw and everyone else would stop entering. Weights resolve at the draw, so a raid attended after entering still counts.
Alliance attendance sharing
A hub guild can credit member guilds with their own players’ attendance from alliance CTAs. No money ever crosses.
Linking takes two acts in two servers, so neither side gains anything unilaterally. A source officer runs /alliance, picks the Discord role in their server that marks the other guild’s players, and gets a one-time code. A subscriber officer opens /alliance → Follow with a code and enters it. From then on, when the alliance settles a raid, each attendee holding that role is credited into their own guild’s records. Balances, banks and the settlement reconciliation invariant are per guild and untouched.
Alliance attribution can never block a settle
The whole attribution step is wrapped so that any failure yields nothing and the money settle proceeds.
Attribution happens inside the settle: the bot resolves attendees’ roles with a bounded member fetch by explicit user ids — no privileged intent needed — and runs a pure matcher whose rules are unit-tested. That entire block sits inside a try/catch that returns an empty list on any error and logs a line saying the settle was unaffected. When rows are produced they are inserted inside the settlement transaction, so they are atomic with the silver. A cross-guild convenience must never be able to stop an officer paying their members.
Kill activity beside raid attendance
/killboard activity pairs each linked member’s kills and deaths with their attendance points.
The question an officer actually has is who is showing up and who is only showing up on the killboard — an active ganker with no raid attendance, or a loyal raider whose PvP never registers. Neither number means anything alone. The query LEFT JOINs throughout so a member with attendance and no kills, or kills and no attendance, both appear; those are precisely the interesting rows. No standalone killbot can produce this pairing, because it has never heard of the attendance ledger.