OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-tps / scenes / test / gate_admin_cmd_ttl.gd

133 lines · gd ref:
extends SceneTree
## Gate: an admin command that already ran does not run again on a fresh join.
##
## THE BUG THIS EXISTS FOR. admin:cmd: is a DURABLE route, so the room replicates
## every command ever issued. _seen_seqs — AdminFacade's guard against
## re-dispatch — is an in-memory Dictionary, empty in a fresh process. So
## whoever became authority on join re-executed the room's entire history.
## hyper-games #77 item 5, confirmed there: ashatron replayed stortron's walker
## and probe commands on a fresh join, against files that only exist on stortron.
##
## The marker is admin:result:<seq>, which already existed — _dispatch_command
## publishes it and only the RUNNER does, so its presence means exactly "someone
## ran this".
##
## ⛔ THE SEQ FIXTURES BELOW ARE THE REAL ONES, and that is the point of this
## gate. A TTL was implemented first, reading age off the seq because lib/tui.js
## mints Date.now().toString(36) + '-' + noise. The live room's nine commands are
## nothing like that — they are hand-written, and every one is valid base36, so
## the parser read them as far-future timestamps and called them fresh. The TTL
## covered 0 of 9. It passed a gate written with synthetic TUI-shaped seqs, which
## is precisely the hyper-games #68 failure: a gate supplying the condition that
## hides the bug. These fixtures are copied from the room.

var ok := true
var _ran := false

## Verbatim from the AI Testing Town room, 2026-09-15.
const REAL_SEQS := [
	"walk1789177841", "walk1789177884", "walk1789180016", "walk1789180061",
	"walk1789180112", "probe1789180148", "probe1789180176", "p1789180961",
	"perfprobe1",
]


class StubState extends Node:
	signal state_changed(key: String, value: Variant, channel: int)
	var store: Dictionary = {}

	func has_state(key: String) -> bool:
		return store.has(key)

	func set_state(key: String, value: Variant) -> void:
		store[key] = value

	func get_state(key: String, default: Variant = null) -> Variant:
		return store.get(key, default)

	# Presence's deferred _wire_up reaches the stub after the verdict and calls
	# this. Harmless where it lands, but an unhandled call in a gate is noise
	# that the next person has to rule out.
	func keys_with_prefix(prefix: String) -> Array[String]:
		var out: Array[String] = []
		for k: String in store.keys():
			if k.begins_with(prefix):
				out.append(k)
		return out


func _p(c: bool, m: String) -> void:
	print(("ok   " if c else "FAIL: ") + m)
	if not c:
		ok = false


func _process(_delta: float) -> bool:
	if _ran:
		return true
	_ran = true
	_run()
	print("GATE admin_cmd_ttl: %s" % ("PASS" if ok else "FAIL"))
	if not ok:
		quit(1)
	return true


func _run() -> void:
	var af: Node = root.get_node_or_null("AdminFacade")
	_p(af != null, "AdminFacade autoload present")
	if af == null:
		return
	_p(af.has_method("_command_already_applied"),
		"AdminFacade exposes _command_already_applied()")
	if not af.has_method("_command_already_applied"):
		return

	# The real GameState autoload owns /root/GameState, and a second child of
	# that name is silently renamed on collision — which would leave the stub
	# inert and every check below passing for the wrong reason.
	var real_gs: Node = root.get_node_or_null("GameState")
	if real_gs != null:
		real_gs.name = "GameStateAutoload"
	var stub := StubState.new()
	stub.name = "GameState"
	root.add_child(stub)
	_p(root.get_node_or_null("GameState") == stub, "the stub owns /root/GameState")

	# ---- nothing applied yet: every real seq must be dispatchable ----
	for seq: String in REAL_SEQS:
		if af._command_already_applied(seq):
			_p(false, "%s is wrongly considered applied with no marker" % seq)
			break
	_p(true, "with no markers, none of the %d real seqs is considered applied" % REAL_SEQS.size())

	# ---- the room's actual state: all nine have results ----
	for seq: String in REAL_SEQS:
		stub.set_state("admin:result:" + seq, {"ok": true})
	var covered := 0
	for seq: String in REAL_SEQS:
		if af._command_already_applied(seq):
			covered += 1
	_p(covered == REAL_SEQS.size(),
		"all %d real backlog seqs are recognised as applied (%d)" % [REAL_SEQS.size(), covered])

	# ---- discrimination: a command with no result still runs ----
	_p(not af._command_already_applied("walk1789177841-never-ran"),
		"a seq with no result marker is NOT considered applied")
	_p(not af._command_already_applied(""), "an empty seq does not throw")

	# SELF-CHECK: the two assertions above only mean something together. A
	# function returning a constant true would pass the backlog check and fail
	# this one; returning constant false fails the backlog check.
	stub.set_state("admin:result:selfcheck", {"ok": true})
	_p(af._command_already_applied("selfcheck") and not af._command_already_applied("selfcheck-absent"),
		"self-check: the same call answers both ways, so it is reading state")

	# ---- the marker is written by the runner, so the wiring must still exist --
	var src: String = FileAccess.get_file_as_string("res://autoloads/admin_facade.gd")
	_p(src.contains("admin:result:"), "admin_facade still publishes admin:result:")
	var idx: int = src.find("func _on_state_changed")
	var body: String = src.substr(idx, 1400) if idx >= 0 else ""
	_p(body.contains("_command_already_applied"),
		"the dispatch path consults the marker before running a command")