Repository navigation
feat(ads): rotate the house ad so unsold slots stop looking frozen - #174
Merged
Merged
Conversation
Until a slot has paid inventory every fill on it is a house ad, and the house ad was a single hard-coded creative. That made the unit byte-identical on every request: profullstack.com/motd printed the same "Your ad here" block on every login, which reads as a cached or broken endpoint rather than a live one. Nothing was actually cached -- both /api/ads/motd and the /motd consumer are already no-store -- there was simply only ever one thing to serve. Make the house ad a pool of six variants and draw one per fill, pitched at both sides of the network (publishers with a surface to monetize, advertisers with a product to sell). An unsold slot now rotates on every request, and the 10% house rotation on sold slots stops repeating itself too. The draw happens once in houseFill and is threaded through both houseCreative and renderHouseAdHtml; drawing independently in each would let a single impression show one pitch in its HTML and another in its text. Variants carry a slug that rides the click URL as utm_content so we can tell which pitch converts -- left off the terminal URL, which is printed as literal text inside the ASCII box and has no width to spare. Verified all six variants render ASCII-clean with aligned boxes at cols=44/72/120. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
vu1nz Security Review0 finding(s) in PR #? No security issues found. |
ralyodio
marked this pull request as ready for review
July 31, 2026 11:32
This was referenced Jul 31, 2026
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.
Why
profullstack.com/motdprints the same CrawlProof ad block on every request, which reads as a stale or cached endpoint.It isn't caching. Both ends are already correct:
/api/ads/motdisforce-dynamic+cache-control: no-store, and picks a bid-weighted random winner per request./motdconsumer inprofullstack-webfetches per request withcache: 'no-store'and servesCache-Control: no-store(verified against live headers).The block never changes because the network has no paid terminal inventory yet, so every fill is the house ad — and the house ad was one hard-coded creative. One thing to serve, served identically, forever.
What
HOUSEbecomesHOUSE_VARIANTS, a pool of six, drawn per fill. Copy is pitched at both sides of the network: publishers with a surface to monetize, advertisers with a product to sell.Effects:
HOUSE_AD_ROTATION_RATEon sold slots stops repeating itself.Two details worth review:
houseFill, and is threaded through bothhouseCreativeandrenderHouseAdHtml. Drawing independently in each would let a single impression pitch one thing in its HTML and another in its text — covered by a test.utm_contentis added to non-terminal click URLs only. The terminal URL is printed as literal text inside the ASCII box and has no width to spare.House fills stay unmetered and unbilled;
campaignId/creativeIdremain"house".Verification
npm run typecheckclean.renderCreativeTextatcols=44/72/120: ASCII-clean, boxes stay rectangular.tests/contract/ads-house-rotation.test.tsconfirmed to fail onmaster(2 of 4) and pass on this branch.One pre-existing issue this surfaced but does not change: at
cols=44the click-URL line overflows the box (58 chars vs 44). It is URL-length driven and identical onmasteracross all variants. Flagging it rather than fixing it here.🤖 Generated with Claude Code