irregular6612 commited on
Commit
e6ab3ac
·
1 Parent(s): efc9c82

test(web): wire-level GET-poll fairness + document single-user concurrency assumption

Browse files
Files changed (2) hide show
  1. proteus/web/server.py +5 -0
  2. tests/web/test_server.py +18 -0
proteus/web/server.py CHANGED
@@ -3,6 +3,11 @@
3
  A pure ``handle_request(method, path, body, registry)`` router (unit-testable
4
  without a socket) plus a thin BaseHTTPRequestHandler adapter and a make_server
5
  factory. In-memory session registry; local single-user. No new dependencies.
 
 
 
 
 
6
  """
7
  from __future__ import annotations
8
 
 
3
  A pure ``handle_request(method, path, body, registry)`` router (unit-testable
4
  without a socket) plus a thin BaseHTTPRequestHandler adapter and a make_server
5
  factory. In-memory session registry; local single-user. No new dependencies.
6
+
7
+ Concurrency: ThreadingHTTPServer serves each request on its own thread, but the
8
+ registry is a plain dict and a session is not locked — this assumes one local
9
+ player (no concurrent ``/act`` on the same session). Sessions are never evicted
10
+ (unbounded for a long-lived server); both are acceptable for single-user play.
11
  """
12
  from __future__ import annotations
13
 
tests/web/test_server.py CHANGED
@@ -91,6 +91,24 @@ def test_query_string_is_ignored_in_routing():
91
  assert status == 200 and "predator_evade" in payload["scenarios"]
92
 
93
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  def test_finish_appends_trace_and_returns_metrics(tmp_path):
95
  reg = _registry()
96
  _, created, _ = server.handle_request(
 
91
  assert status == 200 and "predator_evade" in payload["scenarios"]
92
 
93
 
94
+ def test_get_poll_state_is_fair_mid_game():
95
+ # The GET poll path must be as fair as create/act: no answer keys mid-game.
96
+ reg = _registry()
97
+ _, created, _ = server.handle_request(
98
+ "POST", "/session",
99
+ {"scenario": "predator_evade", "difficulty": "easy", "seed": 42,
100
+ "play_turns": 5, "probe": False}, reg)
101
+ sid = created["session_id"]
102
+ server.handle_request("POST", f"/session/{sid}/act", {"action": "up"}, reg)
103
+
104
+ status, payload, _ = server.handle_request("GET", f"/session/{sid}", None, reg)
105
+ assert status == 200
106
+ st = payload["state"]
107
+ assert st["outcome"] is None and st["review"] is None
108
+ blob = json.dumps(st)
109
+ assert "reward" not in blob and "motive_action" not in blob and "habit" not in blob
110
+
111
+
112
  def test_finish_appends_trace_and_returns_metrics(tmp_path):
113
  reg = _registry()
114
  _, created, _ = server.handle_request(