extends SceneTree
## GATE — the History panel's admin-only buttons follow the ROLE, not the journal.
##
## 2026-10-12 (hyper-games #109): "in HOME room, flatten map and flatten room are greyed
## out". The daemon answers `members` with role "admin" for self at Home (measured on a
## scratch daemon). KeetGameState fetches that role in its own RPC, racing the map load
## (game_state.gd says so for the starter seed). editor_history re-checked the role only
## on LevelPersistence.folded, so a role that lands after the last fold — at Home nothing
## else writes — left Flatten disabled for the whole session.
##
## 1. role "peer": both Flatten buttons are disabled
## 2. the role arrives as "admin" (KeetService._on_role_loaded, the real path), with
## NO fold after it: both are enabled
## 3. a later downgrade to "peer" disables them again
##
## RUN: HYPERTPS_DAEMON_TCP=127.0.0.1:1 "$GODOT" --headless --path . --script res://scenes/test/gate_history_role.gd
var _frame := 0
var _map: Node = null
var fails := 0
var checks := 0
func _p(c: bool, m: String, got: Variant = "") -> void:
checks += 1
if not c:
fails += 1
print(" %-66s %s %s" % [m, "OK" if c else "**FAIL**", str(got)])
func _process(_d: float) -> bool:
_frame += 1
if _frame == 1:
_map = (load("res://scenes/maps/map_flat.tscn") as PackedScene).instantiate()
root.add_child(_map)
return false
if _frame < 30:
return false
_run()
if checks < 6:
print(" **FAIL** only %d checks ran -- setup died before the assertions" % checks)
fails += 1
print("\nGATE history_role: %s (%d checks, %d failed)" % ["PASS" if fails == 0 else "FAIL", checks, fails])
quit(0 if fails == 0 else 1)
return true
func _run() -> void:
var keet: Node = root.get_node_or_null("/root/KeetService")
var hist: Node = _map.get("_history")
_p(keet != null and hist != null, "setup: KeetService and the History panel exist")
if keet == null or hist == null:
return
var fm: Button = hist.get("_flatten_map_btn")
var fr: Button = hist.get("_flatten_room_btn")
_p(fm != null and fr != null, "setup: both Flatten buttons were built")
if fm == null or fr == null:
return
var room := "gate-room"
keet.current_role = "peer"
hist.call("refresh") # a fold while still "peer"
_p(fm.disabled and fr.disabled, "1. role peer: Flatten map/room disabled", "%s/%s" % [fm.disabled, fr.disabled])
keet.call("_on_role_loaded", room, "admin") # the role RPC answers, no fold after it
_p(not fm.disabled, "2. role admin arrives after the fold: Flatten map enabled", fm.disabled)
_p(not fr.disabled, "2. role admin arrives after the fold: Flatten room enabled", fr.disabled)
keet.call("_on_role_loaded", room, "peer")
_p(fm.disabled and fr.disabled, "3. downgraded to peer: disabled again", "%s/%s" % [fm.disabled, fr.disabled])