diff --git a/CHANGELOG.md b/CHANGELOG.md index 970c478..9b24fcb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,16 @@ Notable changes to kubestronaut-sim, newest first. A version is the `VERSION` st (year.month.day.n); `./ksim help` and the top bar of the web page show the one you are running. Every entry names the commit it came in. +## Unreleased + +### Fixed + +- Choosing *Teach a domain* could start a full exam. `./ksim web` reads `web/index.html` afresh on + every request but keeps running the code it started with, so a server from before the update + read the new request as its default, a full exam. The server now reports when its code has + changed on disk since it started (a server from before this check counts as changed). The + lobby then asks you to restart it and starts nothing until you do. + ## 2026.10.26.2 — 2026-10-26 Everything below came in `e852419`. diff --git a/ksim b/ksim index 6699c91..2bfbc88 100755 --- a/ksim +++ b/ksim @@ -2165,9 +2165,17 @@ def cmd_reset(args): print(("rebuilt " if not problem else "problem rebuilding ") + f"Q{q['id']:02d}: {q['title']}") # --------------------------------------------------------------- web ---- +def code_stamp(): + """When the simulator's own code (ksim, sim/*.py) last changed on disk.""" + sim_dir = os.path.join(ROOT, "sim") + return max(os.path.getmtime(f) for f in [os.path.join(ROOT, "ksim")] + + [os.path.join(sim_dir, n) for n in os.listdir(sim_dir) if n.endswith(".py")]) + + class Api(http.server.BaseHTTPRequestHandler): """Serves web/index.html plus a small JSON API. State lives in the same files the CLI uses.""" lock = threading.Lock() + started_code = None # code_stamp() when ./ksim web started log_lines = [] seeding = False seed_error = None @@ -2345,6 +2353,10 @@ class Api(http.server.BaseHTTPRequestHandler): "k8s": k8s_version(), "pending": len(PENDING), "drilled": drilled_domains(), "sets": {k: {"name": v, "count": len(set_questions(k))} for k, v in SETS.items()}, "seen": sorted(last_seen()), "seeding": Api.seeding, "seed_error": Api.seed_error, + # index.html is read from disk on every request, the server's code only when it started: + # after an update the page may ask for what this server does not know (an old one read + # "teach a domain" as a full exam), so the page starts nothing until it is restarted + "stale": Api.started_code is not None and code_stamp() > Api.started_code, "session": None, } payload.update(self.path_payload()) @@ -2444,6 +2456,7 @@ def cmd_web(args): except envs.EnvError as e: Api.desktop_error = str(e) print(yellow(f" no desktop: {e}")) + Api.started_code = code_stamp() http.server.ThreadingHTTPServer.allow_reuse_address = True srv = http.server.ThreadingHTTPServer(("127.0.0.1", port), Api) # type: ignore[arg-type] print(bold(f"\n {TRACK_ID.upper()} exam UI: http://127.0.0.1:{port} (ksim {VERSION})\n") diff --git a/web/index.html b/web/index.html index 86b6414..7bf5bc7 100644 --- a/web/index.html +++ b/web/index.html @@ -397,6 +397,7 @@ try { const t = localStorage.getItem('ksim.theme'); if (t === 'light' || t === '