From 698abfad8310326ed2e49ad2f399fd8cdb8f0022 Mon Sep 17 00:00:00 2001 From: Dmitriy Vasilev Date: Wed, 23 Sep 2026 14:57:10 +0700 Subject: [PATCH] feat(queen): the board counts .t27 specs, and says the rule it is drawing The score paid the same for any accepted issue, while law L0 - adopted today - names one direction: the stack below the interface becomes .t27. So the tab now shows ".t27 specs" beside "Accepted", and the scoring line says what a spec is worth (BrowserOS feat/xp-counts-specs). The count travels BESIDE the total rather than folded into it. A score that hid which half moved the language would be a score nobody could check against the issues it came from - and the scoring sentence is still read from the server's own `scoring` field, so the rule stated and the rule applied cannot drift. The column appears only when the server sends it, so a board pointed at an older agent still reads correctly instead of printing a zero it did not measure. Language 375/375, fallback parity 193/193, contrast 24 pairs worst 5.39:1, typecheck ratchet unchanged. Co-Authored-By: Claude Opus 5 --- .../src/components/QueenLeaderboard.css | 5 ++++ .../src/components/QueenLeaderboard.tsx | 27 ++++++++++++++----- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/apps/website/src/components/QueenLeaderboard.css b/apps/website/src/components/QueenLeaderboard.css index 7e6629807b..4f571bd8dc 100644 --- a/apps/website/src/components/QueenLeaderboard.css +++ b/apps/website/src/components/QueenLeaderboard.css @@ -181,3 +181,8 @@ color: var(--hud-muted, rgba(255, 255, 255, 0.78)); line-height: 1.5; } + +/* The goal of the game, marked as such where it is counted. */ +.ql-stat.is-spec b { + color: var(--hud-green, #00ff88); +} diff --git a/apps/website/src/components/QueenLeaderboard.tsx b/apps/website/src/components/QueenLeaderboard.tsx index d369456535..05674d3d32 100644 --- a/apps/website/src/components/QueenLeaderboard.tsx +++ b/apps/website/src/components/QueenLeaderboard.tsx @@ -23,6 +23,8 @@ interface Contributor { github?: string keys: number[] accepted: number + /** Accepted issues whose boundary named a .t27 file: the game's own goal. */ + specs?: number finished: number hours: number xp: number @@ -44,7 +46,7 @@ interface Board { /** The window in days, or null for the whole record. */ days: number | null measuredAt: string - scoring: { acceptedXp: number; hourXp: number } + scoring: { acceptedXp: number; specXp?: number; hourXp: number } contributors: Contributor[] } @@ -54,11 +56,12 @@ export interface LeaderboardCopy { howTo: string lanesTitle: string lanesLead: string - scoring: (accepted: number, hour: number) => string + scoring: (accepted: number, spec: number, hour: number) => string rank: string who: string lanes: string accepted: string + specs: string hours: string xp: string unclaimed: string @@ -75,12 +78,13 @@ export const LEADERBOARD_COPY: Record<'en' | 'ru', LeaderboardCopy> = { howTo: 'How to lend one — and which providers forbid it', lanesTitle: 'LANES', lanesLead: 'A lane is named once its lender is written into the swarm\u2019s TRIOS_KEY_OWNERS; until then it is shown as its index rather than invented.', - scoring: (accepted, hour) => - `${accepted} XP for an issue the Queen accepted on that lane, ${hour} XP for an hour her bees spent on it. Summed from the swarm’s own records on every read.`, + scoring: (accepted, spec, hour) => + `${accepted} XP for an issue the Queen accepted on that lane, ${spec} XP more when it was a .t27 spec — the goal law L0 names — and ${hour} XP for an hour her bees spent. Summed from the swarm’s own records on every read.`, rank: '#', who: 'Lane holder', lanes: 'Lanes', accepted: 'Accepted', + specs: '.t27 specs', hours: 'Bee hours', xp: 'XP', unclaimed: 'nobody has claimed this lane', @@ -95,12 +99,13 @@ export const LEADERBOARD_COPY: Record<'en' | 'ru', LeaderboardCopy> = { howTo: 'Как одолжить свой — и кто из провайдеров это запрещает', lanesTitle: 'ПОЛОСЫ', lanesLead: 'Полоса получает имя, когда её владельца впишут в TRIOS_KEY_OWNERS роя; до тех пор показывается её индекс, а не выдуманное имя.', - scoring: (accepted, hour) => - `${accepted} XP за задачу, которую Королева приняла на этой полосе, и ${hour} XP за час работы пчёл на ней. Складывается из записей самого роя при каждом чтении.`, + scoring: (accepted, spec, hour) => + `${accepted} XP за задачу, принятую на этой полосе, ещё ${spec} XP если это была спека .t27 — цель, названная законом L0, — и ${hour} XP за час работы пчёл. Складывается из записей самого роя при каждом чтении.`, rank: '#', who: 'Чья полоса', lanes: 'Полосы', accepted: 'Принято', + specs: 'спек .t27', hours: 'Часы пчёл', xp: 'XP', unclaimed: 'полосу никто не назвал своей', @@ -140,7 +145,7 @@ export default function QueenLeaderboard({ lang }: { lang: 'en' | 'ru' }) {

{c.title}

{c.lead}

-

{c.scoring(board.scoring.acceptedXp, board.scoring.hourXp)}

+

{c.scoring(board.scoring.acceptedXp, board.scoring.specXp ?? 0, board.scoring.hourXp)}

{c.window(board.days)}

{/* This tab invited people to lend a lane and said nothing about how, which made it an advertisement rather than a door. The tutorial is @@ -214,6 +219,14 @@ export default function QueenLeaderboard({ lang }: { lang: 'en' | 'ru' }) { {fmt(row.accepted)} {c.accepted} + {/* The goal, shown beside the total rather than folded into + it: a score that hid which half moved the language would + be a score nobody could check against the issues. */} + {row.specs !== undefined && ( + + {fmt(row.specs)} {c.specs} + + )} {row.hours.toFixed(1)} {c.hours}