A public board: who pays for the directory, and who just asks - #180
Merged
Conversation
traffic_hourly has counted who asks and how many we turn away since 2026-09-02. The half it could never answer is the half with money in it: the gateway has been selling day passes and writing none of it down, so a sale existed only for as long as the response took to send. crawl_sales is that half. One row per sale, unique on the payment ref so a settlement delivered twice books once. The hook returns its promise rather than dropping it, because the gateway awaits onSale before the receipt goes out (its JSDoc said otherwise; profullstack/x402-gateway#5), and a rejection is swallowed there, so a database failure still sells the pass it was paid for. The board projects both tables instead of keeping a third copy that could disagree with either. Only badges get a table, being awarded rather than derived. Sales are tagged with classifyAgent, so a family reads the same on both sides. The two sides never share a list. Agents paying are ranked by money; agents asking are ranked by requests and by refusals. 'Paid us $3' and 'asked 209,000 times' are not the same fact. /leaderboard is in OPEN_PATHS with and without the trailing slash: the gateway prefix-matches only entries ending in a slash, so the bare path would open the index and still charge for every board on it. Verified against a local libSQL file: the migration applies, a duplicate ref books once, a sale with no payer still lands, the route handler serves both sides off real traffic_hourly rows, RSS names the side, a share card renders and an unknown board 404s. The existing 382 web tests still pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0144uEVbZK3jdaQkwcLYTXPE
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
traffic_hourlyhas counted who asks and how many we turn away since 2026-09-02. The half it could never answer is the half with money in it: the gateway has been selling day passes and writing none of it down, so a sale existed only for as long as the response took to send.What this adds
crawl_sales(new)traffic_hourly(already there)The usage side has real data the moment this merges, because that table is already being written.
The two sides never share a list. "Paid us $3" and "asked 209,000 times" are not the same fact, and one ranking would say they were. Each side has its own tab, and
actornames the column.The sale write
crawl_salesis one row per sale, unique on the paymentref, so a settlement delivered twice books once. The hook returns its promise rather than dropping it: the gateway awaitsonSalebefore the receipt goes out (its JSDoc claimed the opposite, fixed in x402-gateway#5), and a rejection is swallowed there, so a database failure still sells the pass it was paid for.Sales are tagged with
classifyAgent, so a family likeai-openaireads the same on both sides of the board.No third copy of anything: the board projects the two tables rather than keeping its own rollup that could drift from them. Only badges get a table, since they are awarded at a moment rather than derived from a sum.
Access
/leaderboardis inOPEN_PATHSwith and without the trailing slash. The gateway prefix-matches only entries ending in a slash, so the bare path would open the index and still charge for every board on it. An agent that hits a 402 on the page ranking its own spend cannot read the case for buying a pass.Verified
Against a local libSQL file, driving the real route handler:
refbooks once; a sale with no payer still landstraffic_hourlyrows🤖 Generated with Claude Code
https://claude.ai/code/session_0144uEVbZK3jdaQkwcLYTXPE