ramble 0.11.0: eggs are earned (reward economy phase 3) - #342
Open
kh0pper wants to merge 20 commits into
Open
Conversation
added 20 commits
September 9, 2026 13:26
- B1: paintPet now clears rb-nextegg-warm's disabled state whenever it repaints the card visible, not just on incubate()'s own failure path — a successful warm otherwise leaves the button dead the next time a gift, claimed nest, or lapsed swap re-shows it. - N5: restore the static "One's waiting on your shelf." copy when the waiting card repaints, instead of leaving a failed warm's error message stuck there for the life of the page. - N1: correct the rb-pet-nextegg comment, which claimed an auto-mint this branch removed. - N7: correct the prologue comment, which claimed a dismissal control that does not exist — only the Go button closes it. Claude-Session: https://claude.ai/code/session_01BpkA6EtBWm2rnr7miS8yAV
B2: both guides claimed the incubating slot auto-promotes from the shelf whenever it empties. promoteFromShelf's docstring in bundles/ramble/server/eggs.js is explicit that it is called from exactly one place, hatchIfReady — a gift, a swap, or an egg a lapsed swap frees while the slot is empty all wait on the shelf instead, with a one-tap Warm it on the pet page. Warmth earned with an empty slot still vanishes even while eggs sit on the shelf, so the old text materially overstated how safe it is to walk around without warming a waiting egg first. Claude-Session: https://claude.ai/code/session_01BpkA6EtBWm2rnr7miS8yAV
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.
Phase 3 of the reward-economy spec (
docs/superpowers/specs/2026-09-08-ramble-reward-economy-design.md§4 entire) — the risky phase, deliberately late. The four parts ship together because removing the free egg without the laying floor is exactly the harshness the design exists to avoid.lay.days(default 14) you lay one yourself. Days need not be consecutive, and the count runs only while eggless — a floor, not a faucet.No schema change, no migration, no
SCHEMA_GENERATIONbump. Laying rides the existingramble_wallet(kind='layday'/'lay',deltaalways the literal1); the prologue flags rideramble_settings.servers/andscripts/are untouched entirely —git diff --stat main..HEAD -- servers/ scripts/is empty.init-tables.jsis comment-only.Ramble is installed on grackle only — crow primary and r4 have no Ramble bundle.
Spec §4.2 says: "When the incubating slot empties, the oldest shelf egg is promoted into it automatically. The user is therefore only ever eggless when they genuinely have none."
As shipped,
promoteFromShelfhas exactly one caller:hatchIfReady. Three paths leave the slot empty without promoting — a gift or swap arriving while eggless, a lapsed or declined swap unlocking your last shelf egg, and a sync apply that empties the slot while only'user'shelf eggs remain. In those states the egg waits on the shelf and the pet card offers a one-tap Warm it.This matters because
creditWarmthburns its dedup key whether or not an egg exists:visit_place:<cell>:<isoweek>is consumed with zero warmth banked and cannot pay again that week. So warmth earned with an empty slot is lost even if eggs are sitting on the shelf. Both guides now say so explicitly.Two alternatives were tried during plan review and both reverted, for reasons recorded in
promoteFromShelf's docstring:applyRambleEgg'sisUserShelvecarve-out exists precisely because the replacement egg "follows in the same drain", so a GET landing in that window drafts the egg you just parked and it then out-ranks your real choice on both machines. The mitigation (marking such a promote'sync') launders provenance that the nest shelf cap,shelf_count,RAMBLE_EGG_REPROMOTE_SQLand a panel label all read.expireTradesstrands an in-flightcompletedenvelope, so the hand-overUPDATEmatches nothing while the received egg still inserts and the user keeps both eggs. A free-egg race, in the phase built to remove the free egg.The engineering call stands, but it is a spec deviation and it was decided inside the plan rather than escalated. If §4.2 should hold literally, the clean version is promote-on-gift-receipt as its own change, with
expireTradesdeliberately left alone.Other recorded deviations
loadOrCreateIdentitygenerates a random per-instance seed, socrowIddiffers between your own machines and deriving from it would grant two eggs — the outcome it was written to prevent. A fixed constant is worse: a contact could gift you their starter egg and the ids would collide. A genuine race now resolves through the existing convergence rule (older survives incubating, younger is shelved with its warmth).creditWarmthkeepscreditedmeaning "this ledger key was new" and writes the row even with no egg.feedAllgates the pet feed on that flag, so reportingfalsewould stop walking, meeting crows and checking in from feeding energy — exactly while eggless, which is when laying needs you happy. That would have made the floor unreachable.shelf_origin='sync'and does not consume the nest shelf cap. A replicated per-user salt is the cheap fix if a second instance ever installs Ramble.checkin 5 + 3 × chore 8 = 29/day, so a player who never posts a location fix banks three happy days and then sits below the happy threshold permanently. §4.3 framed 14 days as protecting a housebound player; it does not. Operator ruling: leave it — the point of the game is to go outside, and the queued pedometer arc is the proper fix.Tests
4394 pass / 0 fail, against a 4340 baseline — +54, nothing regressed. Multi-instance coverage for the lay ledger as spec §8 requires, including one test that applies a row with a rewritten
created_atand proves the count does not move (layProgressorders bykey, nevercreated_at, becauseapplyRambleWalletresolves conflicts withcreated_at = MIN(...)).tests/sync-stamp.test.js:174(concurrent first-ever boot returned an empty instance id). The branch touches nothing inservers/, the file passes 10/10 alone, and a re-run of the whole suite was clean. This branch adds 54 tests, which shifts suite timing and may surface it more often. It deserves its own hunt.tests/i18n-global-parity.test.jscovers the translation-key mechanism only.docs/es/guide/ramble.mdwas updated and checked by hand.Process
The plan survived five adversarial review rounds (9 / 13 / 6 / 5 / 4 findings) before any code was written; each round's fixes introduced some of the next round's findings, and the two best outcomes were deletions rather than additions. Nine tasks, each with a fresh implementer and a two-stage review, then a whole-branch review that found two blockers — both in the seams between tasks, where the per-task reviews could not look.
Three findings during implementation were tests the plan specified that could not fail against the bug they guarded — source-string greps standing in for behavioural checks. Each was replaced with a pure extracted helper (
nextEggVisibility,shouldShowIntro) tested directly, and verified red before green.https://claude.ai/code/session_01BpkA6EtBWm2rnr7miS8yAV