`game/` package (routers, mounted at `/game`) is the **Code Farm** idle game (`index.py` + `farm.py`): `GET /game` (page), `GET /game/state`, `GET /game/leaderboard`, `POST /game/{plant,harvest,buy-plot,upgrade,fertilize,daily,grant,perk,prestige,legacy,quests/claim}`, plus social `GET /game/farm/{username}` and `POST /game/farm/{username}/{water,steal}`.
A cooperative-and-competitive idle game (Farmville-style) mounted at `/game`, member-only to play, public to view another farm. Cooperative loop = watering a neighbour's growing build; competitive loop = stealing a neighbour's ready build.
## Data layer
**Data layer is pure + timestamp-driven (no background tick).**`services/game/economy.py` holds every constant and formula as frozen dataclasses/functions: the `CROPS` tuple (key/name/icon/cost/grow_seconds/reward_coins/reward_xp/min_level), `CI_TIERS` (speed multiplier + upgrade cost), level thresholds (`xp_threshold`/`level_for_xp`/`level_progress`), `plot_cost` (doubles per extra plot), and watering bonus. `services/game/store.py` is the only DB access (`game_farms`, `game_plots`). **A plot's state is derived from `ready_at` vs now, never stored** - growing crops finish purely by the clock, so there is no reconciler/service. `serialize_farm(farm, viewer=, owner=)` computes plot states, remaining seconds, `can_water` (viewer is not owner, build growing, viewer not already in the per-cycle `watered_by` JSON list, under `MAX_WATERS_PER_PLOT`), `can_steal`/`steal_coins` (viewer is not owner, build ready, and `now >= ready_at + STEAL_GRACE_SECONDS` so the owner gets a protection window), level progress, and the plantable crop list. `serialize_plot` takes the owner farm's `yield_level`/`prestige` (threaded from `serialize_farm`) only to compute the steal payout. Mutations (`plant`/`harvest`/`buy_plot`/`upgrade_ci`/`water`/`steal`) raise `GameError` on any invalid op (insufficient coins, locked crop, wrong state, still-protected harvest); the routers translate that to a `400` JSON error or a redirect.
`game_farms` (one per user, `coins`/`xp`/`level`/`ci_tier`/`plot_count`/`total_harvests`, plus `prestige`/`streak`/`last_daily_at`/`last_grant_week`, the four `perk_*` columns, and the endgame `stars` + six `legacy_*` columns including `legacy_carryover`), `game_plots` (`farm_uid`/`slot_index`/`crop_key`/`planted_at`/`ready_at`/`watered_by`), `game_steals` (`thief_uid`/`owner_uid`/`slot_index`/`crop_key`/`coins`/`stolen_at`, the per-pair steal-cooldown ledger), and `game_treasury` (a single row `uid="treasury-main"` holding `balance`/`collected_total`/`granted_total`, the refactor-fee redistribution ledger) are **not** soft-deletable - they are mutable game state consumed by state transitions, not user content. Columns + indexes are ensured in `database.init_db` (unique `idx_game_farms_user`, `idx_game_farms_rank`, `idx_game_plots_farm`, `idx_game_steals_pair` on `(thief_uid, owner_uid, stolen_at)`); the `_uid_index` loop adds the uid index. `ensure_farm(user_uid)` lazily creates a farm + starting plots on first access (idempotent), so there is no signup hook.
`index.py` is the base router - `GET /game` (own farm page), `GET /game/state` (own farm JSON), `GET /game/leaderboard`, and the action POSTs `plant`/`harvest`/`buy-plot`/`upgrade`. `farm.py` adds `GET /game/farm/{username}` (view), `POST /game/farm/{username}/water`, and `POST /game/farm/{username}/steal`. Every action returns the **full updated farm** as JSON (so the client refreshes in one round trip) or redirects for no-JS, via the shared `_respond_action` choke (the `farm.py` water/steal handlers inline the same shape). Harvest awards site XP (`award_rewards`) and the `harvest`/`water` achievements (`track_action`). All action handlers are `require_user`; reads of other farms/the leaderboard are public.
**Leaderboard ranking is a composite `economy.farm_score(farm)`** (one integer per row, computed in memory over the already-loaded `_farms().find()` set, so it stays fast): it sums weighted contributions from every tracked factor - `xp`, `prestige`* `SCORE_PRESTIGE` (5000, dominant since a refactor is a full completed cycle), `total_harvests` *`SCORE_HARVEST`, `coins` // `SCORE_COIN_DIVISOR`, `(ci_tier-1)`* `SCORE_CI`, `(plot_count-STARTING_PLOTS)` *`SCORE_PLOT`, the summed perk levels * `SCORE_PERK`, and `min(streak, SCORE_STREAK_CAP)` *`SCORE_STREAK` - so a player who refactored (which resets xp/level/coins/ci/plots/perks) is no longer buried below a never-refactored higher-level player. The weights are module-level constants in `economy.py` for tuning; the leaderboard entry carries `score` and `prestige` (surfaced on `GameLeaderboardEntryOut`) and `GameFarm.js` renders the score next to `Lv X`.
## Live + frontend
After any mutation the handler `await`s `_shared.notify_farm(username)` which publishes a nudge to the `public.game.farm.{username}` pub/sub topic; subscribed clients re-fetch their viewer-specific state (keeps `can_water` correct without broadcasting per-viewer payloads). `static/js/GameFarm.js` (`app.gameFarm`, auto-detects `[data-game-root]`) renders the grid/HUD/leaderboard, ticks plot countdowns client-side every second, delegates the `data-game-action` forms through `Http.send`, subscribes to the farm topic, and keeps a 20s `Poller` fallback. The server renders a full no-JS fallback grid (`templates/_game_grid.html`, shared by `game.html` and `game_farm.html` with progressive-enhancement POST forms).
## Fan-out
Devii plays via the `game_*``http` actions in `actions/catalog.py` (state/leaderboard/view public, the rest `requires_auth`); the API reference has a **Code Farm** group in `docs_api.py`; pages are `noindex,follow` (interactive, user-specific) so they are intentionally not in the sitemap; badges live in `utils.BADGE_CATALOG` under the **Code Farm** group with `harvest`/`water`/`harvest_stolen`/`got_stolen_from``ACHIEVEMENTS` (the steal pair awards **Cat Burglar** to the thief and **Robbed** to the victim, both threshold 1).
`store.steal(thief, owner, slot)` mirrors `water`: it requires the owner plot to be `ready` AND past the protection window `economy.effective_steal_grace(owner_defense_level)` (base `STEAL_GRACE_SECONDS` 60s, +30s per owner Branch Protection level) measured from `ready_at`, AND that the thief is **off cooldown for this victim** (`steal_cooldown_remaining(thief, owner, now) == 0`, i.e. no row in `game_steals` for the pair within `STEAL_COOLDOWN_SECONDS` = 3600 - you can raid a given neighbour only once per hour); it clears the plot exactly like a harvest (owner gets nothing), credits the **thief's** farm `economy.steal_reward_coins` (the owner's yield/prestige/legacy-multiplier realized value times `effective_steal_fraction(owner_defense_level)`, base `STEAL_FRACTION` 0.5, -5% per defense level, floored at 0.1) and **coins only** - no XP, no `total_harvests`, so the leaderboard stays earned by real farming - then inserts a `game_steals` row stamping the cooldown. The route `POST /game/farm/{username}/steal` (reusing `GameSlotForm`) then `track_action`s both sides, fires `create_notification(owner, "harvest_stolen", "Someone raided your Code Farm...", thief_uid, "/game")` (the message never names the thief; `related_uid` is internal), and `await notify_farm`s **both** the owner and the thief usernames so both farms refresh live. The new `harvest_stolen` notification type rides the existing in-app relay (live toast, no new wiring). No DB migration: grace + payout are computed from existing `ready_at`/perk/legacy columns, the `game_steals` table is created by the ensure-block (absent rows -> cooldown 0 -> first steal always allowed), and the new `GamePlotOut.can_steal`/`steal_coins`/`steal_cooldown_seconds`/`steal_reason` + `GameFarmOut.steal_cooldown_seconds` + `GameFarmViewOut.stole_coins` schema fields default safe. The per-pair cooldown is computed **once per farm** in `serialize_farm` (when the viewer is not the owner) and threaded into every `serialize_plot` as `steal_locked_until`, so `can_steal` is false and `steal_reason` is `"cooldown"`/`"protected"` accordingly. Frontend: the ready/not-owner branch of `_game_grid.html` and `GameFarm.js._plotHtml` render a `btn-danger` Steal button (`data-game-action="steal"`, `data-confirm` gated like prestige) carrying `steal_coins`, or a disabled "Raid again in <countdown>" label when on cooldown; on success `GameFarm.js._submit` toasts the payout from `data.stole_coins`.
## Extended mechanics (all backwards compatible)
Five further systems layer onto the base loop, every one defaulting gracefully for pre-existing `game_farms`/`game_plots` rows: new `game_farms` columns (`prestige`, `streak`, `last_daily_at`, `perk_yield`/`perk_growth`/`perk_discount`/`perk_xp`) are added in the `init_db` ensure-block, and `store._lvl(farm, key)` reads every one as `int(farm.get(key) or 0)` so a legacy NULL row behaves as level 0 / no streak / no perks.
1.**Daily bonus** (`POST /game/daily`, `store.claim_daily`): once per UTC day, consecutive days grow `streak` (reward `economy.daily_reward`, capped at `DAILY_STREAK_CAP`).
2.**Daily quests** (`game_quests` table, `POST /game/quests/claim`): `economy.daily_quests(user_uid, day)` deterministically (sha256 of `user:day`) picks 3 of {plant, harvest, water, earn} with goals/rewards; `store.ensure_quests` lazily materializes the day's rows, `store.advance_quests(user_uid, kind, amount)` is called inside `plant`/`harvest`/`water` (wrapped in try/except so a quest write never breaks the action), `claim_quest` pays out when `progress >= goal`.
3.**Perks** (`POST /game/perk`, `store.upgrade_perk`): four permanent upgrades (`economy.PERKS`) with escalating `perk_cost`; applied in the economy formulas - `effective_plant_cost` (discount), `grow_seconds_for(crop, ci_tier, growth_level)` via `farm_speed` (growth), `effective_reward_coins` (yield + prestige), `effective_reward_xp` (xp).
4.**Fertilizer** (`POST /game/fertilize`, `store.fertilize`): cut a growing plot's `ready_at` by `FERTILIZE_FRACTION` for `economy.fertilize_click_cost(eff_reward, reduce_seconds, full_grow_seconds)` = `ceil(eff_reward * reduce/full_grow * FERTILIZE_TAX)` (TAX 1.05). **The cost is priced against the build's realized harvest value (`effective_reward_coins`, which already carries yield/prestige/legacy multipliers), not raw grow-seconds, so the prestige dependence cancels and fully fertilizing a crop always costs >= its harvest - fertilize is a pure time-skip and can NEVER be a profit at any prestige.** (This replaced the old grow-seconds-based `fertilize_cost`, which was an unbounded money pump at high prestige.)
5.**Prestige/Refactor** (`POST /game/prestige`, `store.prestige`): at `PRESTIGE_MIN_LEVEL` resets coins/xp/level/ci/perks, sets `plot_count = economy.prestige_base_plots(legacy_plots_level)` (keeps/recreates plot rows up to that base, deletes the rest), increments `prestige` for a permanent `prestige_multiplier` (+25% coins each), and awards `economy.stars_for_refactor(level, prestige)` Stars (the `legacy_*`/`stars` columns are **omitted from the reset dict** so they survive every refactor, the established pattern). **Refactoring costs a dynamic coin fee** - see "Refactor fee, carry-over, treasury, and community grant" below.
`serialize_farm` exposes all of this (`perks`, `quests`, `streak`, `daily_available`/`daily_reward`, `prestige*`, `stars`, `legacy`, `steal_cooldown_seconds`) only to the owner; the existing `crop_payload`/`serialize_plot` now carry perk- and legacy-adjusted costs/rewards and per-plot value-based `fertilize_cost`. Frontend hosts (`[data-shop-host]`/`[data-perk-host]`/`[data-legacy-host]`/`[data-daily-host]`/`[data-quest-host]`) are server-rendered from partials (`_game_shop.html`/`_game_perks.html`/`_game_legacy.html`/`_game_daily.html`/`_game_quests.html`) and fully re-rendered by `GameFarm.js` builders; the generic `data-game-action` form delegation handles the new actions, with `data-confirm` gating the prestige reset.
The infinite progression for maxed farms. Six new default-0 `game_farms` columns (`stars`, `legacy_autoharvest`, `legacy_multiplier`, `legacy_speed`, `legacy_plots`, `legacy_defense`), all read via `_lvl`.
**Stars** are a meta-currency earned only on Refactor (`stars_for_refactor`), spent via `POST /game/legacy` (`store.upgrade_legacy`, `GameLegacyForm`, Devii `game_upgrade_legacy`) on `economy.LEGACY_UPGRADES` (escalating `legacy_cost` in Stars) that **survive prestige** unlike perks: `autoharvest` (CI Bot), `multiplier` (+10% coins/lvl via `legacy_multiplier`, folded into `effective_reward_coins`), `speed` (+5% base build speed/lvl via `farm_speed`/`grow_seconds_for`/`water_bonus_seconds`), `plots` (+1 base plot after refactor via `prestige_base_plots`), `defense` (steal grace/fraction via `effective_steal_grace`/`effective_steal_fraction`).
**Auto-harvest** is lazy and tick-free: `store._auto_harvest(farm, owner_uid, now)` runs at the top of `serialize_farm` ONLY when the viewer is the owner AND `legacy_autoharvest > 0`; it **clears each ready plot first then credits** the pre-clear crop's coins/xp/`total_harvests` in one `_update_farm`, advances quests, and re-reads the farm - clear-then-credit is idempotent (a second read sees empty plots), and it never fires on a visitor's `GET /game/farm/{username}` view or the leaderboard, honouring the no-background-service invariant (both `GET /game` and `GET /game/state` go through `state_payload` with viewer=owner, so both auto-collect).
**Golden builds** are deterministic and storage-free: `economy.is_golden(plot_uid, planted_at)` (sha256, ~`GOLDEN_CHANCE`) marks a planting golden for its life; `harvest`/`_auto_harvest` multiply **coins only** by `GOLDEN_MULTIPLIER` (XP unscaled to keep level pacing), and `serialize_plot.is_golden` surfaces a sparkle badge (`.game-plot-golden`). New schema fields (`GameLegacyOut`, `GameFarmOut.stars`/`legacy`, `GamePlotOut.is_golden`) all default safe; no DB migration.
## The economy rebalance (Market Saturation, Infrastructure, Defense, Cosmetics, Mastery, secondary leaderboards, Eras, Underdog, weekly Contracts - all backwards compatible)
A second large layer added on top of everything above, aimed at flattening runaway whale inequality (unbounded multiplicative prestige against finite content) and giving the game long-term excitement beyond "hit the Kernel + high-prestige wall." Every mechanic below defaults to a no-op for a farm that has never touched it - new `game_farms` columns are `0`/`""`, new tables start empty, and the Era system in particular is fully dormant (byte-identical to pre-rebalance behavior) until an admin starts the first Era.
**One shared choke point underlies all the new counters.**`store/common.py::credit_farm(farm, *, coins=0, xp=0, harvests=0, era_active=False, extra=None)` is the single place that updates `coins`/`xp`/`level`/`total_harvests`**and** the new shadow counters (`lifetime_coins_earned`, `lifetime_harvests`, and - only when `era_active` - `era_coins`/`era_harvests`) together, so no future coin-crediting feature has to remember to touch five counters at five call sites. `harvest`, `_auto_harvest`, `steal` (thief side), `claim_daily`, and `claim_quest` all route through it instead of their old inline `_update_farm` math. `credit_farm` floors both `coins` and `lifetime_coins_earned` at zero (`max(0, ...)`) as a defense-in-depth guard - no current caller passes a negative `coins` delta, but this is the shared choke every future coin-crediting feature is meant to route through, so the floor costs nothing and forecloses a whole class of future bug.
### Every purchase/upgrade is atomic against concurrent requests (`store/common.py::conditional_update_farm`)
`uvicorn --workers N` means two nearly-simultaneous requests for the same user (a double-click, or two requests hashed to different workers) can run truly in parallel across separate processes - a plain "read the farm, check a precondition in Python, then write" is a classic TOCTOU race under that model. Every mutation that spends a resource against a precondition - `buy_plot`, `upgrade_ci` (`store/farm.py`), `upgrade_perk`, `upgrade_legacy`, `prestige` (`store/actions.py`), `buy_infrastructure`, `upgrade_defense`, `charge_upkeep` (lazy, runs on every `serialize_farm`), `buy_cosmetic`, and `upgrade_mastery` - goes through `conditional_update_farm(farm_uid, set_clause, where_clause, params)`: one raw SQL `UPDATE game_farms SET ... WHERE uid = :farm_uid AND (<precondition>)`, returning the affected row count via `db.executable.execute(...).rowcount` (not `dataset`'s wrapped `db.query()`, which does not expose `rowcount`). The precondition and the write happen as a single atomic statement, so two concurrent attempts against the same stale precondition can never both succeed - the loser's `rowcount` is `0`, and the function re-reads the farm to produce the correct, specific `GameError` (already owned / maxed out / insufficient funds / state changed - refresh and retry).
**Load-bearing gotcha: every precondition column must be `COALESCE`d.** None of `prestige`, `perk_*`, `legacy_*`, `stars`, `mastery_*`, `infra_*`, or `defense_level` are set in `ensure_farm`'s insert - a real, never-yet-touched farm has them as SQL `NULL`, not `0`, and `NULL = 0` evaluates to `NULL` (false) in a `WHERE` clause. A first version of this fix compared bare `column = :current_level` and was verified "safe" only because the verification script had incorrectly pre-seeded those columns to `0` - against a genuinely fresh farm it silently rejected every legitimate first purchase. Every precondition and every arithmetic `SET` on a column that is not set at farm creation must read `COALESCE(column, 0)`; `coins`, `plot_count`, and `ci_tier` are the only farm columns set in `ensure_farm` and are the only ones safe to compare bare.
`buy_plot` additionally reserves the plot slot atomically (`WHERE plot_count = :current_count AND coins >= :cost`) **before** inserting the `game_plots` row - `idx_game_plots_farm (farm_uid, slot_index)` is not a unique index, so without the reservation two concurrent buys could insert two rows at the same `slot_index` (silent data corruption, not just a rejected purchase). `prestige` reserves the whole refactor transition atomically first (`WHERE COALESCE(prestige, 0) = :old_prestige`, in the same statement as every other reset field) and only mutates `game_plots` after that reservation wins, so a losing concurrent `prestige` call touches no plot data at all. Verified by forcing real concurrent OS processes (not threads - `dataset` gives each thread its own pooled connection, and enough of them exhausts the pool and produces `database is locked` noise that has nothing to do with the game logic) against genuinely fresh, un-seeded farm state; every purchase's final coins/stars/level exactly matches hand-computed expected totals under contention, never a partial or double charge.
A new, genuinely new table `game_market_ticks` (`crop_key`, `hour_bucket` = UTC `"YYYY-MM-DDTHH"`, `harvests` count, unique on `(crop_key, hour_bucket)`) tracks the last `MARKET_WINDOW_HOURS` (48h) of production **per crop, globally** - recorded only for owner harvests/auto-harvests (`store/actions.py` calls `market.record_harvest_tick` after a successful clear), deliberately **not** for steals (a raid moves already-produced value, it does not print new supply, so counting it would double-count). `market.recent_harvests(crop_key, window_hours)` sums the trailing buckets via a raw `SELECT SUM` (cached 30s in a plain `TTLCache`, cosmetic/economic staleness only, no `cache_state` wiring needed). `economy.market_saturation_factor(recent_harvests)` steps the payout down through `MARKET_SATURATION_TIERS` (100% -> 40% past 600 recent harvests); `economy.market_buff_factor(crop_key, saturation_factor)` gives the four starter crops (`MARKET_BUFFED_CROPS`) up to `MARKET_BUFF_CAP` (+15%) relief while the market is saturated. `market.market_factor_for(crop_key)` composes both into one multiplier, threaded as the new `market_factor` parameter on `economy.effective_reward_coins`/`steal_reward_coins`/`crop_payload` (default `1.0`, so any caller that omits it is unaffected). `GameCropOut.market_state` (`"normal"`/`"saturated"`/`"boosted"`) surfaces the live signal in the shop list before planting - both the server-rendered `_game_grid.html` plant `<option>` and its `GameFarm.js` JS mirror append a `" (saturated)"`/`" (boosted)"` text suffix to the crop label (an `<option>` cannot hold markup, so this is plain text, not a styled badge). `market.prune_ticks(older_than_hours=96)` keeps the table small; CLI `devplace game market prune`.
- **Infrastructure** (`POST /game/infrastructure/buy`, `store.buy_infrastructure`): three one-time, boolean-owned, prestige-gated buildings (`economy.INFRASTRUCTURE`, new `game_farms` columns `infra_registry`/`infra_canary`/`infra_observability`). `registry` (+15% grow speed for Rust/Compiler/Kernel, `economy.REGISTRY_BOOST_FACTOR`, wired into `grow_seconds_for`'s new `registry_boost` bool param and into water's bonus-seconds calc). `canary` (`store/infrastructure.py::roll_canary`, a plain `random.random()` roll per harvest - deliberately NOT the deterministic `is_golden` hash, since canary is a fresh roll every harvest, not a per-planting property - `CANARY_DOUBLE_CHANCE` 12% to double, `CANARY_FAIL_CHANCE` 6% to only refund the planting cost). `observability` (raises the steal-fraction floor from 0.10 to `OBSERVABILITY_STEAL_FLOOR` 0.30 for this owner; the original critique's "see raid attempts in real time" was dropped - no scouting/detection mechanic exists anywhere in the game, and this achieves the same "raids feel less brutal" goal without inventing one).
- **Defense** (`POST /game/defense/upgrade`, `store.upgrade_defense`/`charge_upkeep`): a leveled building (`economy.DEFENSE_TIERS`, new columns `defense_level`/`defense_last_upkeep_at`) that lowers the steal-fraction floor and raises steal grace per tier (`effective_steal_fraction`/`effective_steal_grace` both gained a `floor`/`extra_seconds` parameter, defaulting to today's values, combined additively with the pre-existing Legacy `defense_level`). Upkeep is the deliberate whale sink: `economy.daily_upkeep(tier, coins) = max(tier.upkeep_daily, coins * UPKEEP_WEALTH_PCT)` (0.2%/day) so a large balance pays real money, not a trivial flat fee. `charge_upkeep` runs **lazily inside `serialize_farm`**, in the exact same spot and spirit as `_auto_harvest` (no new tick, no background service): unpaid upkeep (past `UPKEEP_GRACE_DAYS`) decays the tier by one level instead of going negative.
- **Cosmetics** (`POST /game/cosmetics/{buy,equip}`, `store/cosmetics.py`, new table `game_cosmetics` since this catalog is meant to grow - unlike the fixed Infrastructure/Defense tiers): pure-status titles and plot skins (`economy.COSMETICS`), zero gameplay effect. `game_farms.active_title` holds the equipped title key; `economy.cosmetic_title_name(key)` resolves it to a display name everywhere a leaderboard entry surfaces `title` (never render the raw key). Title display is scoped to the Code Farm leaderboard/farm view only - it does not touch `_avatar_link.html` or any sitewide identity surface.
### 3. Mastery track and new crop families (`economy.py` prestige/mastery/crops sections + `store/mastery.py`)
Orthogonal to prestige, modeled directly on the existing Legacy shape (leveled, its own currency, survives prestige). **Two-counter design, load-bearing:**`mastery_points` (spendable, decreases on spend) vs `mastery_points_earned_total` (never decreases) - crop unlocks gate on the earned total so spending points can never re-lock content. `economy.mastery_points_awarded(old_prestige, new_prestige)` awards the FIRST Mastery point the moment prestige crosses `MASTERY_UNLOCK_PRESTIGE` (50) and one more every `MASTERY_PRESTIGE_STEP` (10) thereafter (`_mastery_total_for(p) = 1 + (p-50)//10` for `p>=50`, difference of the before/after totals - correct even if prestige ever jumps by more than 1). `store/actions.py::prestige()` adds the award into the same reset dict, alongside `stars`, as a field that is **not** zeroed. `POST /game/mastery` (`store.upgrade_mastery`) spends `mastery_points` on `economy.MASTERY_UPGRADES`: `autoreplant` (Continuous Delivery - wired via a shared `_try_autoreplant` helper called from both `harvest()` and `_auto_harvest()` after crediting, replants the same crop immediately if still affordable/unlocked), `analytics` (Farm Analytics - `GameFarmOut.mastery_analytics_unlocked` gates the `lifetime_coins_earned`/`lifetime_harvests` stats panel, rendered by `_game_analytics.html`/`data-analytics-host` inside the Mastery section - both counters are accumulated by `credit_farm`, so they are exact from the moment the upgrade is bought, not backfilled for prior activity), `contracts` (Legacy Contracts - unlocks the weekly contract slot, see section 6; this deliberately consolidates the critique's "Legacy Contracts" and "weekly contracts" into ONE mechanism rather than two redundant long-goal systems).
Three new high-tier crops (`distsys`/`mlpipe`/`secfort` in `economy.CROPS`) extend the `Crop` dataclass with three new **trailing, defaulted** fields (`min_mastery: int = 0`, `steal_immune: bool = False`, `era_key: str | None = None`) - safe because every existing `Crop(...)` construction is positional over the original 8 non-defaulted fields. They set `min_level=MAX_LEVEL` (so, like every other crop, they re-lock after each refactor until the player re-levels to 20 - consistent with how Kernel etc. already behave post-prestige) and `min_mastery=1` (gated on `mastery_points_earned_total`, checked both in `store/actions.py::plant()` - real enforcement - and in `economy.crop_payload`'s `locked` flag - display). `secfort` (Security Fortress) is `steal_immune=True`: `serialize_plot` forces `can_steal=False`/`steal_reason="immune"` and `store/actions.py::steal()` raises immediately, before any grace/cooldown check, when the target crop is immune.
`GET /game/leaderboard` gained an optional `board` query param (default `"score"`, so every existing caller/Devii/docs entry that omits it sees byte-identical output to before this shipped). `store/farm.py::leaderboard_for(board, limit)` dispatches through `LEADERBOARD_BOARDS` (`score` = the original `farm_score` board, `prestige`, `harvests` = this week's `harvests_week` counter, `raids` = average coins per **successful** raid with a minimum of `MIN_RAIDS_FOR_EFFICIENCY_BOARD` (3) qualifying raids - deliberately not "attempts," since failed steals are never persisted today and adding that write would be a spam vector for no real value, `time_to_kernel` = seconds between a farm's last `prestiged_at` and its next Kernel harvest, `fair_play` = `economy.fair_play_score(harvests_week, coins)` which rewards recent activity and penalizes hoarding) plus `era` (dispatches to `store/era.py::leaderboard_era`, always empty when no Era is running). `GameFarm.js._loadLeaderboard` renders a board-appropriate value per row instead of always showing the raw composite score - `raid_avg` (formatted `"Nc/raid"`) for the `raids` board and a formatted duration for `time_to_kernel`, falling back to `score` for every other board. New `game_farms` columns backing these: `harvests_week`/`harvests_week_start` (reset lazily in `serialize_farm` via `_reset_harvests_week` whenever the current ISO week - `common._iso_week` - differs from the stored one, same lazy-no-tick idiom as everything else), `prestiged_at` (stamped every `prestige()`), `last_kernel_harvest_prestige`/`time_to_kernel_seconds` (updated in `harvest`/`_auto_harvest` the first time a Kernel is harvested since the last refactor).
**Admin-triggered, not automatic** - a deliberate deviation from "reset every 4-6 weeks": an unattended live-leaderboard reset in production is exactly the kind of surprising action this project treats with caution, so `POST /admin/game/era/start` and `/era/end` (`/admin/game` page, `require_admin`) are the only way an Era starts or ends. Two new tables: `game_eras` (at most one row `active=1` at a time - **zero active rows is the permanent no-op state**, everything below is dormant until the first Era is started) and `game_era_results` (the permanent per-user historical record written once at era-end, before counters reset). Three new `game_farms` columns, `era_coins`/`era_harvests`/`era_joined_at`, are a **shadow, resettable counter** completely separate from the real, permanent `coins`/`total_harvests` - `start_era` bulk-resets only these three to zero/now for every farm; `end_era` resets `era_coins`/`era_harvests` back to zero for every participant it ranks (in the same `_update_farm` call that awards Stars, so a farm never carries a stale Era total into the next dormant period) while never touching real balances, prestige, stars, Legacy, or Mastery. While an Era is active, `game.html`'s Era banner shows the owner's own live `era_coins`/`era_harvests` (via `data-era-coins`/`data-era-harvests`, kept current by `GameFarm.js._renderHud` on every action), not just the fact that a season is running. `economy.era_score(era_coins, era_harvests, prestige)` is a DISTINCT scoring function from `economy.farm_score` - it gives prestige only `ERA_PRESTIGE_CARRYOVER_PCT` (40%) weight so veterans keep an edge on the Era board specifically without it being insurmountable, while the permanent leaderboards (section 4) keep ranking by full lifetime stats untouched. `end_era` ranks every farm with any Era activity, awards `economy.ERA_REWARD_STARS_BY_RANK` Stars to the top 10 (added to the permanent `stars`, exactly like a refactor's `stars_for_refactor`) and, when the active Era name matches a `Cosmetic.era_key`, grants an Era-exclusive cosmetic. Era-exclusive crops reuse the `Crop.era_key` field from section 3 (`unlocked_crops`/`crop_payload` hide them unless the active Era's name matches - a no-op for every crop shipped so far, all of which have `era_key=None`).
**Underdog** (`economy.UNDERDOG_COIN_RATIO`=10, `UNDERDOG_DURATION_HOURS`=24, `UNDERDOG_MULTIPLIER`=1.25): in `store/actions.py::steal()`, if the owner's coins exceed 10x the thief's, the thief's `underdog_boost_until` is stamped; `_harvest_crop` applies the +25% multiplier while that timestamp is in the future. `GameFarmOut.underdog_boost_seconds_remaining` drives a HUD banner; `steal()`'s result carries `underdog_triggered` so `routers/game/farm.py::steal_farm` can fire the **David vs Goliath** badge.
**Weekly Contracts** extend the existing daily-quest engine (`game_quests` table) rather than building a second system: a new `scope` column (`"daily"`/`"weekly"`, existing/new daily rows always `"daily"` - backfilled on migration via `UPDATE game_quests SET scope='daily' WHERE scope IS NULL OR scope=''` so in-flight quests from before this shipped are never duplicated) and `reward_stars`. `store/quests.py::ensure_weekly_contract` materializes one `economy.weekly_contract(user_uid, iso_week)` row per ISO week (deterministic sha256 pick, same idiom as `daily_quests`), gated on owning the `mastery_contracts` upgrade; `advance_quests` advances both the day's rows and the current week's row in one pass. `claim_quest(user, kind, scope="daily")` claims either; a weekly claim pays Stars plus a `contract_boost_until` timestamp that grants `WEEKLY_CONTRACT_BOOST_MULTIPLIER` (1.2x) coins for `WEEKLY_CONTRACT_BOOST_HOURS` (48h), applied in `_harvest_crop` the same way as the Underdog boost.
**"Crops ready" notifications are client-side only** (`GameFarm.js`'s existing 1-second ticker fires a toast/desktop `Notification` when a countdown hits zero while the tab is open) - this respects the hard "no background tick" architectural invariant, since nothing server-side needs to detect the transition. **"Someone is scouting you" was not built** - like Observability's real-time alert, it would require inventing a scouting/detection mechanic that does not exist. **Alliance/Farm Coop was deliberately deferred** to its own follow-up plan - it is a new multiplayer social feature (group membership, shared resource pooling, its own invite/leave/kick UX), qualitatively different from every economy-tuning change here, and was judged to deserve its own design pass rather than being folded into this rebalance.
### Refactor fee, carry-over, treasury, and community grant (`store/treasury.py`)
Refactoring is no longer free at level 10 - it is the economy's progressive wealth sink, and the sink funds a redistribution loop. All backwards compatible: new `game_farms` columns (`legacy_carryover`, `last_grant_week`) default NULL and are `COALESCE`d, and the `game_treasury` table starts empty (lazily seeded by `ensure_treasury`).
- **Dynamic fee** (`economy.refactor_cost(prestige, coins)` = `REFACTOR_BASE_COST` (20k) `* (1 + prestige) * prestige_multiplier(prestige) + REFACTOR_WEALTH_PCT` (15%) `* coins`): the polynomial prestige term makes time-to-afford grow linearly with prestige (a soft cap on prestige cycling - income grows only linearly, so an exponential fee would wall off Mastery), and the wealth term is a progressive tax a hoarder cannot dodge. At prestige 0 the fee means a level-10 farm must keep farming (~23.5k coins minimum) before its first refactor - instant level-10 cycling is dead.
- **Carry-over** (`economy.refactor_carryover(coins, fee, carryover_level)`): after the fee, `REFACTOR_CARRYOVER_BASE` (10%) of the remainder survives the reset, raised +5%/level by the new **Golden Parachute** Legacy upgrade (`legacy_carryover`, max 5 -> 35%). Always strictly below 100% so a refactor can never be net-profitable (same invariant class as the fertilize fix). `prestige()` pins the balance in the atomic WHERE (`AND coins = :coins_now`) so a concurrent harvest yields a "balance just changed - refresh" `GameError` instead of a wrong charge, then credits the fee to the treasury.
- **Treasury** (`game_treasury`, single row `uid="treasury-main"`, `balance`/`collected_total`/`granted_total`): every refactor fee is credited atomically (`credit_treasury`, raw conditional SQL like `conditional_update_farm`). The ledger invariant `balance == collected_total - granted_total` is fuzz-verified.
- **Community grant** (`POST /game/grant`, `store.claim_grant`): once per ISO week (`last_grant_week`), an **active low-wealth, low-prestige** farm (coins < `GRANT_WEALTH_CEILING` 10k, `harvests_week >= GRANT_MIN_WEEK_HARVESTS` 5 - the activity gate blocks idle alts, prestige <= `GRANT_MAX_PRESTIGE` 5 - so post-refactor whales with a briefly low balance never draw welfare) claims `economy.grant_amount(balance)` (capped `GRANT_CAP` 2,500). Order of operations: atomic treasury debit first (`WHERE balance >= :amount`), then the atomic farm credit+week-stamp; a losing farm update refunds the treasury. Race-verified with real OS processes: concurrent claims by one farm pay exactly once, and two farms racing an underfunded treasury never overdraw it.
- **Fan-out:** `serialize_farm` exposes `refactor_cost`/`refactor_affordable`/`refactor_carryover_pct`/`refactor_carryover_preview` plus the owner-only `grant_*`/`treasury_balance`; the shop row and `GameFarm.js._shopHtml` show the fee and hide the button until affordable; the sidebar **Community grant** section is `_game_grant.html`/`data-grant-host`/`_grantHtml`. Devii: `game_prestige` is now in `CONFIRM_REQUIRED` (large irreversible spend) with a declared `confirm` param; `game_claim_grant` is a plain auth tool. Docs: `game-prestige` updated + `game-grant` added.
`/admin/game` (`routers/admin/game.py`, `admin_game.html`, sidebar entry between Bot Monitor and AI usage) shows the current Era status and the start/end forms; `AdminGameOut` is the response schema. `devplace game market prune` and `devplace game era {status,start,end}` mirror the same actions from the CLI (`cli/game.py`).