Notifications: a new "thread" type notifies every other commenter on a
post whenever anyone comments on it, disregarding reply hierarchy -
excluding the actor and whoever already got a comment/reply
notification for that same event, so no one is double-notified.
Implemented via a background-deferred fan-out mirroring the existing
mention-notification pattern.
SEO: discussion_forum_posting() now embeds up to 20 of a post's
comments as nested schema.org Comment entities (not just an aggregate
count), and a new /topics hub plus /topics/{topic} pages give the
feed's topic filter real, independently crawlable/indexable URLs -
/feed?topic=X was never indexable since its canonical strips the
query string back to bare /feed. Both are wired end to end (schemas,
Devii actions, docs API, sitemap, locustfile load-test coverage).
Quiz player: the auto-advance to the next question used to hide the
just-answered slide in the same tick as rendering the grade, so on
any multi-question quiz the Correct/Not correct feedback was never
actually visible before the view moved on. Delayed via setTimeout,
with the pending timer cleared on manual navigation and on
disconnect so it can't race or fire on a removed component.
Also includes other local changes already in progress in this
working tree before this session (messaging, push delivery,
deepsearch jobs, game economy, quiz builder) - verified by the full
suite passing (3467 tests) but not authored or individually reviewed
in this session.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VL9Xn57W5UR3HZbbuuzxdK
693 lines
25 KiB
Python
693 lines
25 KiB
Python
# retoor <retoor@molodetz.nl>
|
|
|
|
from devplacepy.services.game import economy
|
|
|
|
|
|
def test_level_thresholds():
|
|
assert economy.level_for_xp(0) == 1
|
|
assert economy.level_for_xp(economy.xp_threshold(2)) == 2
|
|
assert economy.level_for_xp(economy.xp_threshold(5)) == 5
|
|
assert economy.level_for_xp(economy.xp_threshold(economy.MAX_LEVEL) + 9999) == economy.MAX_LEVEL
|
|
|
|
|
|
def test_level_progress_span():
|
|
progress = economy.level_progress(economy.xp_threshold(3))
|
|
assert progress["level"] == 3
|
|
assert progress["into_level"] == 0
|
|
assert progress["is_max"] is False
|
|
|
|
|
|
def test_plot_cost_doubles():
|
|
assert economy.plot_cost(economy.STARTING_PLOTS) == economy.PLOT_BASE_COST
|
|
assert economy.plot_cost(economy.STARTING_PLOTS + 1) == economy.PLOT_BASE_COST * 2
|
|
assert economy.plot_cost(economy.STARTING_PLOTS + 2) == economy.PLOT_BASE_COST * 4
|
|
|
|
|
|
def test_perk_cost_grows():
|
|
perk = economy.perk_for("yield")
|
|
assert economy.perk_cost(perk, 0) == perk.base_cost
|
|
assert economy.perk_cost(perk, 1) == round(perk.base_cost * perk.cost_growth)
|
|
assert economy.perk_cost(perk, 2) > economy.perk_cost(perk, 1)
|
|
|
|
|
|
def test_daily_reward_streak_and_cap():
|
|
assert economy.daily_reward(1) == economy.DAILY_BASE
|
|
assert economy.daily_reward(2) == economy.DAILY_BASE + economy.DAILY_STREAK_STEP
|
|
assert economy.daily_reward(99) == economy.daily_reward(economy.DAILY_STREAK_CAP)
|
|
|
|
|
|
def test_effective_plant_cost_discount():
|
|
crop = economy.crop_for("python")
|
|
assert economy.effective_plant_cost(crop, 0) == crop.cost
|
|
assert economy.effective_plant_cost(crop, 3) < crop.cost
|
|
assert economy.effective_plant_cost(crop, 3) >= 1
|
|
|
|
|
|
def test_effective_reward_coins_yield_and_prestige():
|
|
crop = economy.crop_for("shell")
|
|
assert economy.effective_reward_coins(crop, 0, 0) == crop.reward_coins
|
|
assert economy.effective_reward_coins(crop, 4, 0) > crop.reward_coins
|
|
assert economy.effective_reward_coins(crop, 0, 2) > crop.reward_coins
|
|
|
|
|
|
def test_effective_reward_xp():
|
|
crop = economy.crop_for("shell")
|
|
assert economy.effective_reward_xp(crop, 0) == crop.reward_xp
|
|
assert economy.effective_reward_xp(crop, 10) > crop.reward_xp
|
|
|
|
|
|
def test_growth_perk_speeds_build():
|
|
crop = economy.crop_for("python")
|
|
assert economy.grow_seconds_for(crop, 1, 5) < economy.grow_seconds_for(crop, 1, 0)
|
|
|
|
|
|
def test_ci_tier_speeds_build():
|
|
crop = economy.crop_for("python")
|
|
assert economy.grow_seconds_for(crop, 2, 0) < economy.grow_seconds_for(crop, 1, 0)
|
|
|
|
|
|
def test_prestige_multiplier():
|
|
assert economy.prestige_multiplier(0) == 1.0
|
|
assert economy.prestige_multiplier(2) == 1 + 2 * economy.PRESTIGE_BONUS
|
|
|
|
|
|
def test_fertilize_cost_has_floor():
|
|
assert economy.fertilize_click_cost(1, 1, 1_000_000) == 1
|
|
assert economy.fertilize_click_cost(10_000, 50, 100) > 1
|
|
|
|
|
|
def test_crop_payload_locked_flag():
|
|
rust = economy.crop_for("rust")
|
|
assert economy.crop_payload(rust, 1, 1)["locked"] is True
|
|
assert economy.crop_payload(rust, 1, rust.min_level)["locked"] is False
|
|
|
|
|
|
def test_crop_payload_reflects_perks():
|
|
crop = economy.crop_for("python")
|
|
base = economy.crop_payload(crop, 1, 5)
|
|
boosted = economy.crop_payload(crop, 1, 5, growth_level=5, discount_level=3, yield_level=4, prestige=1)
|
|
assert boosted["cost"] < base["cost"]
|
|
assert boosted["grow_seconds"] < base["grow_seconds"]
|
|
assert boosted["reward_coins"] > base["reward_coins"]
|
|
|
|
|
|
def test_daily_quests_deterministic_count_and_kinds():
|
|
first = economy.daily_quests("user-xyz", "2026-06-22")
|
|
second = economy.daily_quests("user-xyz", "2026-06-22")
|
|
assert first == second
|
|
assert len(first) == economy.DAILY_QUEST_COUNT
|
|
assert all(quest["kind"] in economy.QUEST_DEFS for quest in first)
|
|
assert all(quest["goal"] > 0 for quest in first)
|
|
|
|
|
|
def test_farm_score_empty_is_zero():
|
|
assert economy.farm_score({}) == 0
|
|
|
|
|
|
def test_farm_score_counts_every_factor():
|
|
score = economy.farm_score(
|
|
{
|
|
"xp": 100,
|
|
"prestige": 2,
|
|
"total_harvests": 3,
|
|
"coins": 200,
|
|
"ci_tier": 3,
|
|
"plot_count": economy.STARTING_PLOTS + 2,
|
|
"perk_yield": 1,
|
|
"perk_growth": 1,
|
|
"perk_discount": 1,
|
|
"perk_xp": 1,
|
|
"streak": 4,
|
|
}
|
|
)
|
|
expected = (
|
|
100
|
|
+ 2 * economy.SCORE_PRESTIGE
|
|
+ 3 * economy.SCORE_HARVEST
|
|
+ 200 // economy.SCORE_COIN_DIVISOR
|
|
+ (3 - 1) * economy.SCORE_CI
|
|
+ 2 * economy.SCORE_PLOT
|
|
+ 4 * economy.SCORE_PERK
|
|
+ 4 * economy.SCORE_STREAK
|
|
)
|
|
assert score == expected
|
|
|
|
|
|
def test_farm_score_prestige_is_additive_and_substantial():
|
|
base = {"xp": 800, "total_harvests": 5}
|
|
with_prestige = {**base, "prestige": 1}
|
|
gain = economy.farm_score(with_prestige) - economy.farm_score(base)
|
|
assert gain == economy.SCORE_PRESTIGE
|
|
assert gain >= economy.xp_threshold(economy.PRESTIGE_MIN_LEVEL)
|
|
|
|
|
|
def test_farm_score_prestige_lifts_above_lower_level_player():
|
|
refactorer = {"xp": 200, "prestige": 1}
|
|
higher_level_no_prestige = {"xp": economy.xp_threshold(5)}
|
|
assert economy.farm_score(refactorer) > economy.farm_score(higher_level_no_prestige)
|
|
|
|
|
|
def test_farm_score_streak_is_capped():
|
|
capped = economy.farm_score({"streak": economy.SCORE_STREAK_CAP})
|
|
over = economy.farm_score({"streak": economy.SCORE_STREAK_CAP + 50})
|
|
assert capped == over
|
|
|
|
|
|
def test_farm_score_handles_legacy_null_columns():
|
|
assert economy.farm_score(
|
|
{"xp": 50, "prestige": None, "perk_yield": None, "streak": None}
|
|
) == 50
|
|
|
|
|
|
# --- legacy upgrades ---------------------------------------------------------
|
|
|
|
|
|
def test_legacy_for_known_and_unknown():
|
|
assert economy.legacy_for("multiplier") is not None
|
|
assert economy.legacy_for("does_not_exist") is None
|
|
|
|
|
|
def test_legacy_cost_grows_with_level():
|
|
up = economy.legacy_for("multiplier")
|
|
assert economy.legacy_cost(up, 0) == up.base_cost
|
|
assert economy.legacy_cost(up, 2) > economy.legacy_cost(up, 1)
|
|
|
|
|
|
def test_legacy_multiplier_steps():
|
|
assert economy.legacy_multiplier(0) == 1.0
|
|
assert economy.legacy_multiplier(3) == 1 + economy.LEGACY_MULT_STEP * 3
|
|
|
|
|
|
def test_stars_for_refactor_scales_with_level_and_prestige():
|
|
assert economy.stars_for_refactor(0, 0) == economy.STAR_BASE
|
|
assert economy.stars_for_refactor(10, 0) == economy.STAR_BASE + 2
|
|
assert economy.stars_for_refactor(0, 2) == economy.STAR_BASE + 2
|
|
|
|
|
|
def test_prestige_base_plots_adds_legacy_plots():
|
|
assert economy.prestige_base_plots(0) == economy.STARTING_PLOTS
|
|
assert economy.prestige_base_plots(3) == economy.STARTING_PLOTS + 3
|
|
|
|
|
|
# --- steal economy -----------------------------------------------------------
|
|
|
|
|
|
def test_effective_steal_grace_extends_with_defense():
|
|
assert economy.effective_steal_grace(0) == economy.STEAL_GRACE_SECONDS
|
|
assert economy.effective_steal_grace(2) == (
|
|
economy.STEAL_GRACE_SECONDS + economy.LEGACY_DEFENSE_GRACE * 2
|
|
)
|
|
|
|
|
|
def test_effective_steal_fraction_drops_with_defense_and_has_floor():
|
|
assert economy.effective_steal_fraction(0) == economy.STEAL_FRACTION
|
|
assert economy.effective_steal_fraction(2) < economy.STEAL_FRACTION
|
|
assert economy.effective_steal_fraction(99) >= 0.1
|
|
|
|
|
|
def test_steal_reward_coins_is_a_fraction_of_harvest():
|
|
crop = economy.crop_for("shell")
|
|
full = economy.effective_reward_coins(crop)
|
|
stolen = economy.steal_reward_coins(crop)
|
|
assert 0 < stolen <= full
|
|
|
|
|
|
# --- golden crops ------------------------------------------------------------
|
|
|
|
|
|
def test_is_golden_deterministic_and_bounded():
|
|
first = economy.is_golden("plot-7", "2026-06-20T00:00:00+00:00")
|
|
second = economy.is_golden("plot-7", "2026-06-20T00:00:00+00:00")
|
|
assert first == second
|
|
assert isinstance(first, bool)
|
|
|
|
|
|
def test_is_golden_requires_both_args():
|
|
assert economy.is_golden("", "2026-06-20T00:00:00+00:00") is False
|
|
assert economy.is_golden("plot-7", "") is False
|
|
|
|
|
|
# --- market saturation --------------------------------------------------------
|
|
|
|
|
|
def test_market_saturation_factor_is_full_when_fresh():
|
|
assert economy.market_saturation_factor(0.0) == 1.0
|
|
|
|
|
|
def test_market_saturation_factor_steps_down():
|
|
assert economy.market_saturation_factor(8.0) < 1.0
|
|
assert economy.market_saturation_factor(96.0) == 0.40
|
|
assert economy.market_saturation_factor(8.0) > economy.market_saturation_factor(96.0)
|
|
|
|
|
|
def test_market_saturation_factor_is_monotone_non_increasing():
|
|
previous = 1.0
|
|
step = 0
|
|
while step <= 400:
|
|
supply = step * 0.5
|
|
factor = economy.market_saturation_factor(supply)
|
|
assert factor <= previous
|
|
previous = factor
|
|
step += 1
|
|
|
|
|
|
def test_supply_days_normalizes_by_grow_time():
|
|
shell = economy.crop_for("shell")
|
|
kernel = economy.crop_for("kernel")
|
|
assert economy.supply_days(shell, 0) == 0.0
|
|
assert economy.supply_days(shell, 5760) == economy.supply_days(kernel, 24)
|
|
assert economy.supply_days(shell, 2880) == 1.0
|
|
assert economy.supply_days(kernel, 12) == 1.0
|
|
|
|
|
|
def test_market_buff_factor_only_applies_to_starter_crops():
|
|
assert economy.market_buff_factor("kernel", 0.60) == 1.0
|
|
assert economy.market_buff_factor("shell", 0.0) == 1.0
|
|
assert economy.market_buff_factor("shell", 0.15) == 1.0375
|
|
assert economy.market_buff_factor("shell", 0.60) == economy.MARKET_BUFF_CAP
|
|
assert economy.market_buff_factor("shell", 0.90) == economy.MARKET_BUFF_CAP
|
|
|
|
|
|
def test_market_factor_bounds_across_domain():
|
|
floor = economy.MARKET_SATURATION_TIERS[-1][1]
|
|
for key in economy.MARKET_BUFFED_CROPS + economy.MARKET_PRESSURE_CROPS:
|
|
crop = economy.crop_for(key)
|
|
for harvests in range(0, 300000, 977):
|
|
saturation = economy.market_saturation_factor(economy.supply_days(crop, harvests))
|
|
for pressure in (0.0, 0.15, 0.30, 0.45, 0.60):
|
|
factor = saturation if saturation < 1.0 else economy.market_buff_factor(key, pressure)
|
|
assert floor <= factor <= economy.MARKET_BUFF_CAP
|
|
if saturation < 1.0:
|
|
assert factor == saturation
|
|
else:
|
|
assert factor >= 1.0
|
|
|
|
|
|
def test_effective_reward_coins_applies_market_factor():
|
|
crop = economy.crop_for("shell")
|
|
full = economy.effective_reward_coins(crop, 0, 0, 0, 1.0)
|
|
saturated = economy.effective_reward_coins(crop, 0, 0, 0, 0.5)
|
|
assert saturated < full
|
|
assert saturated == round(crop.reward_coins * 0.5)
|
|
|
|
|
|
def test_effective_reward_coins_underdog_multiplier():
|
|
crop = economy.crop_for("shell")
|
|
plain = economy.effective_reward_coins(crop, 0, 0, 0, 1.0, False)
|
|
boosted = economy.effective_reward_coins(crop, 0, 0, 0, 1.0, True)
|
|
assert boosted == round(crop.reward_coins * economy.UNDERDOG_MULTIPLIER)
|
|
assert boosted > plain
|
|
|
|
|
|
# --- infrastructure and defense ------------------------------------------------
|
|
|
|
|
|
def test_infra_for_known_and_unknown():
|
|
assert economy.infra_for("registry") is not None
|
|
assert economy.infra_for("does_not_exist") is None
|
|
|
|
|
|
def test_registry_boost_speeds_only_named_crops():
|
|
kernel = economy.crop_for("kernel")
|
|
shell = economy.crop_for("shell")
|
|
assert economy.grow_seconds_for(kernel, 1, 0, 0, True) < economy.grow_seconds_for(
|
|
kernel, 1, 0, 0, False
|
|
)
|
|
assert economy.grow_seconds_for(shell, 1, 0, 0, True) == economy.grow_seconds_for(
|
|
shell, 1, 0, 0, False
|
|
)
|
|
|
|
|
|
def test_defense_tier_lookup_and_progression():
|
|
assert economy.defense_tier(0).name == "Undefended"
|
|
assert economy.defense_tier(0).upkeep_daily == 0
|
|
top = economy.defense_tier(economy.MAX_DEFENSE_LEVEL)
|
|
assert economy.next_defense_tier(economy.MAX_DEFENSE_LEVEL) is None
|
|
assert economy.next_defense_tier(0) is not None
|
|
assert top.steal_fraction_floor < economy.defense_tier(0).steal_fraction_floor
|
|
|
|
|
|
def test_daily_upkeep_scales_with_wealth():
|
|
tier = economy.defense_tier(1)
|
|
assert economy.daily_upkeep(tier, 0) == tier.upkeep_daily
|
|
rich = economy.daily_upkeep(tier, 10_000_000)
|
|
assert rich > tier.upkeep_daily
|
|
assert rich == round(10_000_000 * economy.UPKEEP_WEALTH_PCT)
|
|
|
|
|
|
def test_effective_steal_fraction_floor_overridden_by_building():
|
|
assert economy.effective_steal_fraction(99, floor=0.30) == 0.30
|
|
assert economy.effective_steal_fraction(0, floor=0.30) == economy.STEAL_FRACTION
|
|
|
|
|
|
def test_effective_steal_grace_extra_seconds_from_building():
|
|
base = economy.effective_steal_grace(0, 0)
|
|
with_building = economy.effective_steal_grace(0, 30)
|
|
assert with_building == base + 30
|
|
|
|
|
|
# --- cosmetics ------------------------------------------------------------------
|
|
|
|
|
|
def test_cosmetic_for_known_and_unknown():
|
|
assert economy.cosmetic_for("title_architect") is not None
|
|
assert economy.cosmetic_for("does_not_exist") is None
|
|
|
|
|
|
def test_cosmetic_title_name_only_resolves_titles():
|
|
assert economy.cosmetic_title_name("title_architect") == "The Architect"
|
|
assert economy.cosmetic_title_name("skin_neon") == ""
|
|
assert economy.cosmetic_title_name("") == ""
|
|
assert economy.cosmetic_title_name("does_not_exist") == ""
|
|
|
|
|
|
# --- mastery --------------------------------------------------------------------
|
|
|
|
|
|
def test_mastery_points_awarded_first_point_at_unlock():
|
|
step = economy.MASTERY_PRESTIGE_STEP
|
|
unlock = economy.MASTERY_UNLOCK_PRESTIGE
|
|
assert economy.mastery_points_awarded(unlock - 1, unlock) == 1
|
|
assert economy.mastery_points_awarded(0, unlock - 1) == 0
|
|
assert economy.mastery_points_awarded(unlock, unlock + step - 1) == 0
|
|
assert economy.mastery_points_awarded(unlock + step - 1, unlock + step) == 1
|
|
assert economy.mastery_points_awarded(unlock, unlock + step * 2) == 2
|
|
|
|
|
|
def test_mastery_for_known_and_unknown():
|
|
assert economy.mastery_for("autoreplant") is not None
|
|
assert economy.mastery_for("does_not_exist") is None
|
|
|
|
|
|
def test_mastery_cost_grows_with_level():
|
|
m = economy.mastery_for("contracts")
|
|
assert economy.mastery_cost(m, 0) == m.base_cost
|
|
|
|
|
|
def test_unlocked_crops_gates_on_mastery_and_level():
|
|
base = economy.unlocked_crops(economy.MAX_LEVEL, mastery_earned=0)
|
|
with_mastery = economy.unlocked_crops(economy.MAX_LEVEL, mastery_earned=1)
|
|
assert "distsys" not in {c.key for c in base}
|
|
assert "distsys" in {c.key for c in with_mastery}
|
|
|
|
|
|
def test_crop_payload_locked_by_mastery():
|
|
distsys = economy.crop_for("distsys")
|
|
locked = economy.crop_payload(distsys, 1, economy.MAX_LEVEL, mastery_earned=0)
|
|
assert locked["locked"] is True
|
|
assert locked["locked_reason"] == "mastery"
|
|
assert "Mastery" in locked["locked_text"]
|
|
unlocked = economy.crop_payload(distsys, 1, economy.MAX_LEVEL, mastery_earned=1)
|
|
assert unlocked["locked"] is False
|
|
assert unlocked["locked_reason"] == ""
|
|
|
|
|
|
def test_crop_payload_locked_by_level_reason():
|
|
rust = economy.crop_for("rust")
|
|
locked = economy.crop_payload(rust, 1, 1)
|
|
assert locked["locked_reason"] == "level"
|
|
assert str(rust.min_level) in locked["locked_text"]
|
|
|
|
|
|
def test_crop_lock_reason_matches_plant_enforcement():
|
|
distsys = economy.crop_for("distsys")
|
|
assert economy.crop_lock_reason(distsys, economy.MAX_LEVEL, 0) == ("mastery", "unlocks after reaching Mastery (Refactor to prestige 50)")
|
|
assert economy.crop_lock_reason(distsys, economy.MAX_LEVEL, 1) is None
|
|
assert economy.crop_lock_reason(distsys, 1, 1)[0] == "level"
|
|
|
|
|
|
def test_secfort_crop_is_steal_immune():
|
|
secfort = economy.crop_for("secfort")
|
|
assert secfort.steal_immune is True
|
|
assert economy.crop_for("shell").steal_immune is False
|
|
|
|
|
|
# --- secondary leaderboard scoring -----------------------------------------------
|
|
|
|
|
|
def test_fair_play_score_rewards_activity_and_penalizes_hoarding():
|
|
active = economy.fair_play_score(harvests_week=20, coins=0)
|
|
hoarder = economy.fair_play_score(harvests_week=0, coins=10_000_000)
|
|
assert active > hoarder
|
|
|
|
|
|
# --- era --------------------------------------------------------------------------
|
|
|
|
|
|
def test_era_score_gives_prestige_partial_weight():
|
|
veteran = economy.era_score(era_coins=0, era_harvests=0, prestige=10)
|
|
rookie = economy.era_score(era_coins=0, era_harvests=0, prestige=0)
|
|
assert veteran > rookie
|
|
assert veteran == round(10 * economy.SCORE_PRESTIGE * economy.ERA_PRESTIGE_CARRYOVER_PCT)
|
|
|
|
|
|
def test_era_reward_stars_by_rank():
|
|
assert economy.era_reward_stars(1) == economy.ERA_REWARD_STARS_BY_RANK[0]
|
|
assert economy.era_reward_stars(len(economy.ERA_REWARD_STARS_BY_RANK) + 1) == 0
|
|
assert economy.era_reward_stars(0) == 0
|
|
|
|
|
|
# --- weekly contracts ---------------------------------------------------------------
|
|
|
|
|
|
def test_weekly_contract_deterministic():
|
|
first = economy.weekly_contract("user-xyz", "2026-W10")
|
|
second = economy.weekly_contract("user-xyz", "2026-W10")
|
|
assert first == second
|
|
assert first["kind"] in economy.QUEST_DEFS
|
|
assert first["reward_stars"] > 0
|
|
|
|
|
|
# --- refactor fee, carry-over, and grants -------------------------------------------
|
|
|
|
|
|
def test_refactor_cost_monotonic_in_prestige():
|
|
previous = 0
|
|
for prestige in range(0, 200):
|
|
cost = economy.refactor_cost(prestige, 0)
|
|
assert cost > previous
|
|
previous = cost
|
|
|
|
|
|
def test_refactor_cost_monotonic_in_wealth():
|
|
previous = -1
|
|
for coins in range(0, 2_000_000, 10_000):
|
|
cost = economy.refactor_cost(0, coins)
|
|
assert cost >= previous
|
|
previous = cost
|
|
|
|
|
|
def test_refactor_cost_floor_is_base():
|
|
assert economy.refactor_cost(0, 0) == economy.REFACTOR_BASE_COST
|
|
assert economy.refactor_cost(-5, -100) == economy.REFACTOR_BASE_COST
|
|
|
|
|
|
def test_refactor_cost_includes_wealth_tax():
|
|
coins = 100_000
|
|
expected = round(
|
|
economy.REFACTOR_BASE_COST + economy.REFACTOR_WEALTH_PCT * coins
|
|
)
|
|
assert economy.refactor_cost(0, coins) == expected
|
|
|
|
|
|
def test_refactor_carryover_fraction_bounds():
|
|
for level in range(0, 50):
|
|
fraction = economy.refactor_carryover_fraction(level)
|
|
assert economy.REFACTOR_CARRYOVER_BASE <= fraction <= economy.REFACTOR_CARRYOVER_MAX
|
|
|
|
|
|
def test_refactor_carryover_never_exceeds_remainder():
|
|
for coins in range(0, 500_000, 7_777):
|
|
for level in (0, 3, 5):
|
|
fee = economy.refactor_cost(0, coins)
|
|
carried = economy.refactor_carryover(coins, fee, level)
|
|
assert 0 <= carried <= max(0, coins - fee)
|
|
|
|
|
|
def test_refactor_carryover_zero_when_unaffordable():
|
|
assert economy.refactor_carryover(100, 20_000, 5) == 0
|
|
|
|
|
|
def test_grant_amount_capped_and_bounded():
|
|
assert economy.grant_amount(0) == 0
|
|
assert economy.grant_amount(-10) == 0
|
|
assert economy.grant_amount(100) == 0
|
|
assert economy.grant_amount(economy.GRANT_MIN_AMOUNT) == economy.GRANT_MIN_AMOUNT
|
|
assert economy.grant_amount(10**9) == economy.GRANT_CAP
|
|
|
|
|
|
def test_grant_amount_shares_between_eligible_farms():
|
|
assert economy.grant_amount(10_000, 5) == 2_000
|
|
assert economy.grant_amount(10**9, 4) == economy.GRANT_CAP
|
|
assert economy.grant_amount(1_000, 10) == 0
|
|
for eligible in range(1, 50):
|
|
share = economy.grant_amount(10**6, eligible)
|
|
assert 0 <= share <= economy.GRANT_CAP
|
|
assert share * eligible <= 10**6 or share == economy.GRANT_CAP
|
|
|
|
|
|
def test_legacy_carryover_upgrade_registered():
|
|
upgrade = economy.legacy_for("carryover")
|
|
assert upgrade is not None
|
|
assert upgrade.max_level == 10
|
|
assert "carry-over" in economy.legacy_value_text(upgrade, 2)
|
|
assert economy.refactor_carryover_fraction(upgrade.max_level) < 1.0
|
|
|
|
|
|
def test_fertilize_is_never_profitable_across_the_input_domain():
|
|
import itertools
|
|
|
|
for crop in economy.CROPS:
|
|
for prestige in range(0, 201, 23):
|
|
for yield_level in (0, 5, 10):
|
|
for legacy in (0, 5, 10):
|
|
for market in (0.40, 0.70, 1.0, 1.15):
|
|
for golden, contract, underdog in itertools.product(
|
|
(False, True), repeat=3
|
|
):
|
|
value = economy.realizable_harvest_coins(
|
|
crop,
|
|
yield_level,
|
|
prestige,
|
|
legacy,
|
|
market,
|
|
golden,
|
|
contract,
|
|
underdog,
|
|
)
|
|
cost = economy.fertilize_click_cost(
|
|
value, crop.grow_seconds, crop.grow_seconds
|
|
)
|
|
assert cost >= value, (
|
|
crop.key,
|
|
prestige,
|
|
golden,
|
|
contract,
|
|
underdog,
|
|
cost,
|
|
value,
|
|
)
|
|
|
|
|
|
def test_fertilize_priced_above_the_expected_canary_payout():
|
|
for crop in economy.CROPS:
|
|
for prestige in (0, 25, 100):
|
|
plain = economy.realizable_harvest_coins(crop, 10, prestige, 10, 1.0)
|
|
priced = economy.realizable_harvest_coins(
|
|
crop, 10, prestige, 10, 1.0, canary=True
|
|
)
|
|
cost = economy.fertilize_click_cost(
|
|
priced, crop.grow_seconds, crop.grow_seconds
|
|
)
|
|
expected = plain * (
|
|
economy.CANARY_DOUBLE_CHANCE * 2
|
|
+ (1 - economy.CANARY_DOUBLE_CHANCE - economy.CANARY_FAIL_CHANCE)
|
|
) + economy.CANARY_FAIL_CHANCE * min(plain, crop.cost)
|
|
assert cost >= expected
|
|
|
|
|
|
def test_staged_fertilize_never_undercuts_the_payout():
|
|
for key in ("shell", "api", "kernel", "secfort"):
|
|
crop = economy.crop_for(key)
|
|
value = economy.realizable_harvest_coins(crop, 10, 50, 10, 1.0, True, True, True)
|
|
remaining, total = crop.grow_seconds, 0
|
|
while True:
|
|
reduce_by = int(remaining * economy.FERTILIZE_FRACTION)
|
|
if reduce_by < 1:
|
|
break
|
|
total += economy.fertilize_click_cost(value, reduce_by, crop.grow_seconds)
|
|
remaining -= reduce_by
|
|
assert total >= value
|
|
|
|
|
|
def test_every_defense_tier_reduces_the_raider_share():
|
|
shares = []
|
|
for tier in economy.DEFENSE_TIERS:
|
|
share = economy.effective_steal_fraction(
|
|
0, tier.steal_fraction_floor, tier.steal_reduction
|
|
)
|
|
shares.append(round(share, 4))
|
|
assert len(set(shares)) == len(economy.DEFENSE_TIERS)
|
|
assert shares == sorted(shares, reverse=True)
|
|
|
|
|
|
def test_more_defense_never_increases_the_raider_share():
|
|
previous = 1.0
|
|
for tier in economy.DEFENSE_TIERS:
|
|
for legacy in range(0, 6):
|
|
share = economy.effective_steal_fraction(
|
|
legacy, tier.steal_fraction_floor, tier.steal_reduction
|
|
)
|
|
assert 0.0 <= share <= 1.0
|
|
top = economy.effective_steal_fraction(
|
|
0, tier.steal_fraction_floor, tier.steal_reduction
|
|
)
|
|
assert top <= previous + 1e-9
|
|
previous = top
|
|
|
|
|
|
def test_observability_only_ever_lowers_the_raider_share():
|
|
for tier in economy.DEFENSE_TIERS:
|
|
for legacy in range(0, 6):
|
|
without = economy.effective_steal_fraction(
|
|
legacy, tier.steal_fraction_floor, tier.steal_reduction
|
|
)
|
|
with_suite = economy.effective_steal_fraction(
|
|
legacy,
|
|
tier.steal_fraction_floor,
|
|
tier.steal_reduction,
|
|
economy.OBSERVABILITY_STEAL_CAP,
|
|
)
|
|
assert with_suite <= without + 1e-9
|
|
assert with_suite <= economy.OBSERVABILITY_STEAL_CAP + 1e-9
|
|
|
|
|
|
def test_raid_share_plus_owner_remainder_never_exceeds_the_build():
|
|
for crop in economy.CROPS:
|
|
for prestige in range(0, 101, 17):
|
|
for golden in (False, True):
|
|
value = economy.realizable_harvest_coins(
|
|
crop, 10, prestige, 10, 1.0, golden
|
|
)
|
|
for tier in economy.DEFENSE_TIERS:
|
|
for legacy in range(0, 6):
|
|
share = economy.effective_steal_fraction(
|
|
legacy, tier.steal_fraction_floor, tier.steal_reduction
|
|
)
|
|
thief = min(max(1, round(value * share)), int(value * (1.0 - 0.0)))
|
|
owner = int(value * (1.0 - share))
|
|
assert thief + owner <= value
|
|
|
|
|
|
def test_weekly_contract_stars_are_per_kind_not_per_goal():
|
|
for kind in economy.QUEST_KINDS:
|
|
for scale in (1.0, 13.5, 40.0):
|
|
contract = economy.weekly_contract("user-a", "2026-W30", scale)
|
|
if contract["kind"] != kind:
|
|
continue
|
|
assert contract["reward_stars"] == economy.QUEST_DEFS[kind].contract_stars
|
|
assert contract["reward_stars"] <= 5
|
|
|
|
|
|
def test_social_rewards_scale_with_the_earner_and_never_regress():
|
|
assert economy.water_reward_coins(0, 0) == economy.WATER_REWARD_COINS
|
|
assert economy.daily_reward(1) == economy.DAILY_BASE
|
|
previous = 0
|
|
for prestige in range(0, 101):
|
|
reward = economy.water_reward_coins(prestige, 0)
|
|
assert reward >= previous
|
|
previous = reward
|
|
|
|
|
|
def test_leaderboard_coin_contribution_is_capped():
|
|
base = {"xp": 18050, "prestige": 50, "total_harvests": 5000, "ci_tier": 5}
|
|
poor = economy.farm_score({**base, "coins": 0})
|
|
rich = economy.farm_score({**base, "coins": 10**9})
|
|
assert rich - poor <= economy.SCORE_COIN_CAP
|
|
|
|
|
|
def test_market_saturation_is_per_capita():
|
|
crop = economy.crop_for("kernel")
|
|
assert economy.supply_days(crop, 288, 1) == economy.supply_days(crop, 2880, 10)
|
|
assert economy.supply_days(crop, 288, 4) < economy.supply_days(crop, 288, 1)
|