File size: 6,499 Bytes
a625b1a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | """The 20261003 move to normal terrain must not destroy anything.
Locks down: a fresh world directory (old maps preserved, auth untouched, no
automatic playerdata import on flat->normal), a fresh EMPTY Naldo checkpoint
(no seeding: upstream asserts an empty vectordb matches the skills file), and
normal-terrain server properties without flat layers.
"""
from __future__ import annotations
import json
from pathlib import Path
import minecraft_stack as mc
import voyager_stack as vs
def test_new_world_is_fresh_and_old_maps_are_kept():
assert mc.WORLD_DIR.name == "world-20261003-normal-v1"
assert mc.WORLD_DIR.parent == mc.PERSIST_ROOT
assert mc.PREVIOUS_WORLD_DIR.name == "world-20260928-ores-y64-v1"
assert mc.WORLD_DIR != mc.PREVIOUS_WORLD_DIR
# The flat constants stay for the old maps and the map-contract tests;
# the new map simply does not use them.
assert mc.WORLD_PROFILE == "minecraft:normal"
def test_normal_server_properties_have_no_flat_layers():
props = mc._server_properties()
assert props["level-type"] == "minecraft:normal"
assert props["generate-structures"] == "true"
assert "generator-settings" not in props
assert props["server-ip"] == "127.0.0.1"
assert props["max-players"] == str(mc.MAX_PLAYERS)
def test_flat_profile_still_selects_the_flat_generator(monkeypatch):
# Profile selection works both ways; the historic flat contract itself is
# left untouched (its own test keeps the HEAD baseline).
monkeypatch.setattr(mc, "WORLD_PROFILE", "minecraft:flat")
props = mc._server_properties()
assert props["level-type"] == "minecraft:flat"
assert props["generator-settings"] == mc.FLAT_GENERATOR_SETTINGS
assert props["generate-structures"] == "false"
def test_flat_to_normal_imports_no_player_saves(tmp_path, monkeypatch):
previous = tmp_path / "world-20260928-ores-y64-v1"
current = tmp_path / "world-20261003-normal-v1"
(previous / "playerdata").mkdir(parents=True)
human = previous / "playerdata" / "human.dat"
human.write_bytes(b"human-save")
(current).mkdir(parents=True)
# Flat->normal: everyone spawns fresh at the natural spawn; importing an
# old position buries the player inside a mountain, far from Naldo.
assert mc.WORLD_PROFILE == "minecraft:normal"
assert mc._should_carry_player_saves(current, previous) is False
# The legacy helper still exists for flat->flat replacements.
monkeypatch.setattr(mc, "WORLD_PROFILE", "minecraft:flat")
assert mc._should_carry_player_saves(current, previous) is True
assert mc._should_carry_player_saves(current, tmp_path / "missing") is False
(current / "level.dat").write_bytes(b"generated")
assert mc._should_carry_player_saves(current, previous) is False
# Nothing is ever deleted from the old world by asking the question.
assert human.read_bytes() == b"human-save"
def test_relay_auth_is_untouched_by_the_map_move():
# The Xbox OAuth cache lives here; a map change must never cost the login.
assert mc.RELAY_DIR == mc.PERSIST_ROOT / "relay"
assert "token.json" not in str(mc.WORLD_DIR)
def test_new_checkpoint_starts_empty_and_seeding_is_gone():
# Upstream SkillManager asserts vectordb count == len(skills): seeding a
# non-empty skills.json without its vectordb fails the boot, and the
# repaired defaults then flip resume=True. The new map must start empty.
assert vs.CKPT_DIR.name == "ckpt-20261003-normal-v1"
assert "gemini-voyager" not in str(vs.CKPT_DIR)
assert not hasattr(vs, "_seed_skill_library"), "automatic skill seeding must be removed"
assert not hasattr(vs, "PREV_CKPT_DIR"), "no previous-checkpoint wiring may remain"
def test_fresh_checkpoint_inherits_nothing_from_the_old_map(tmp_path):
old = tmp_path / "ckpt-old"
(old / "skill").mkdir(parents=True)
(old / "skill" / "skills.json").write_text(
json.dumps({"mineWood": {"code": "x"}}), encoding="utf-8"
)
(old / "curriculum").mkdir(parents=True)
(old / "curriculum" / "completed_tasks.json").write_text('["Mine 1 wood"]', encoding="utf-8")
(old / "curriculum" / "failed_tasks.json").write_text("[]", encoding="utf-8")
new = tmp_path / "ckpt-20261003-normal-v1"
new.mkdir(parents=True)
# The boot creates the directory and nothing else: no skills, no tasks,
# no positions are ever copied across maps.
assert vs._is_fresh_checkpoint(new) is True
assert vs._is_fresh_checkpoint(old) is False
assert not (new / "skill" / "skills.json").exists()
assert not (new / "curriculum" / "completed_tasks.json").exists()
# The old checkpoint is preserved untouched for history.
assert json.loads((old / "skill" / "skills.json").read_text(encoding="utf-8")) == {
"mineWood": {"code": "x"}
}
def test_supervisor_stops_before_shutdown_without_endpoints():
# app needs the Space runtime (spaces/gradio) to import, so verify the
# shutdown ordering statically: the supervisor loop must wait on an Event
# and _shutdown must set it before any save/stop. No command endpoint.
import ast
tree = ast.parse((Path(__file__).resolve().parents[1] / "app.py").read_text(encoding="utf-8"))
module = {node.name: node for node in tree.body if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef))}
supervisor = module["_service_supervisor"]
shutdown = module["_shutdown"]
supervisor_src = ast.get_source_segment(
(Path(__file__).resolve().parents[1] / "app.py").read_text(encoding="utf-8"), supervisor
)
assert "_supervisor_stop.wait(30)" in supervisor_src
shutdown_src = ast.get_source_segment(
(Path(__file__).resolve().parents[1] / "app.py").read_text(encoding="utf-8"), shutdown
)
assert shutdown_src.index("_supervisor_stop.set()") < shutdown_src.index("STACK.stop()")
assert "_supervisor_stop.set()" in shutdown_src
routes_src = (Path(__file__).resolve().parents[1] / "app.py").read_text(encoding="utf-8")
assert "/minecraft/save" not in routes_src and "/minecraft/stop" not in routes_src
def test_presence_diagnostic_counts_without_commands_or_names():
presence = mc._recent_players([
"[2026-10-03 10:00:00] minecraft> Player1 joined the game",
"[2026-10-03 10:01:00] minecraft> Player1 left the game",
"[2026-10-03 10:02:00] minecraft> Player2 joined the game",
])
assert presence["estimated_online"] == 1
assert presence["joins_this_boot"] == 2
|