# F007 Pre-Launch Checklist (temp, 2026-04-12) Scope: verify the HF Space deployment is real and usable **before** the blog post goes live today. Delete this file after launch. --- ## TL;DR — what to do in the next ~60 min | # | Action | Time | Value | Do it? | |---|---|---|---|---| | 1 | Open Space in browser, confirm it loads | 2 min | **Critical** — judges will click the link first | **YES** | | 2 | Hit `/health` and `/docs` | 1 min | **Critical** — proves server is up | **YES** | | 3 | Run one full episode via `/web` UI | 5 min | **Critical** — proves action space works end-to-end | **YES** | | 4 | Fix stale `docs/competition-deliverables.md` status | 3 min | **High** — doc claims "Not started", Space is live | **YES** | | 5 | Python client smoke test against live Space | 10 min | **High** — proves programmatic access (the thing the blog promises) | **YES** | | 6 | Pull `registry.hf.space/...` Docker image and run locally | 10 min | Medium — nice to have, judges rarely do this | If time | | 7 | `pip install` from Space URL | 5 min | Medium — validates `pyproject.toml` inside Space | If time | | 8 | Concurrency audit (`SUPPORTS_CONCURRENT_SESSIONS`) | 15 min | **Low for launch, High for anyone retraining** | Skip today, file issue | | 9 | TRL `environment_factory` wrapper | — | — | **Already done** (see below) | **Recommendation:** Do 1–5 before publishing. Skip 6–8. Item 9 is already in the repo. --- ## About TRL (already integrated — do not re-research) **TRL** = Hugging Face's `transformers`-based RL library. Its `GRPOTrainer` accepts an `environment_factory=MyEnvClass` argument and runs the multi-turn tool-calling loop automatically: generate → parse tool call → call your env → feed result back → repeat. No custom `rollout_func` needed. **We already implement this.** `training/trl_adapter.py::SQLEnvTRL` is a TRL-native environment class with: - `reset(**kwargs)` — reads `question_text` from the dataset column to route to the correct database - Named tool methods with docstrings: `describe(table_name)`, `sample(table_name)`, `query(sql)`, `answer(value)` — not a generic `step()` - `sql_env_reward_func` as the reward function `notebooks/train_grpo.ipynb` cell 16 passes it directly: ```python trainer = build_trainer( ... reward_funcs=[sql_env_reward_func], environment_factory=SQLEnvTRL, ... ) ``` The Setup cell pins `trl>=0.29.0` and `transformers` from `main` specifically because `environment_factory` requires transformers ≥5.2. Our v1/v2 runs used this path. **One nuance (intentional design):** `SQLEnvTRL.__init__` instantiates a **local in-process `SQLEnvironment`**, not a WebSocket client to `https://hjerpe-sql-env.hf.space`. Reasons: - Training opens N parallel sessions (one per generation). The hosted Space defaults to 1 concurrent session — see `SUPPORTS_CONCURRENT_SESSIONS` in the TRL↔OpenEnv docs. - Local is faster, no network hops, no rate limits. - The hosted Space is for judges (clicking `/web`) and external users consuming the env via pip/Docker. Training correctly bypasses it. **Implication for the blog:** you can claim "TRL-native integration via `environment_factory`" factually. It's already true and the notebook proves it. **What's still on the post-launch list** is the Space-side concurrency config (item 8), not the adapter. Without `SUPPORTS_CONCURRENT_SESSIONS=True` on the server, an external user trying to retrain against the hosted Space would hit the 1-session cap. This does not affect our own training (we use local). --- ## 1. Browser smoke test (2 min) — CRITICAL **How:** ```bash open https://huggingface.co/spaces/hjerpe/sql_env ``` (or paste the URL into a browser manually) **What to check:** - [ ] Space status is **Running** (green), not Building / Sleeping / Error - [ ] README renders with a clear one-liner of what the env does - [ ] No red error banner at the top **What you're validating:** that HF Spaces successfully built our image and the container is alive. If it's sleeping, the first visit wakes it (~30s cold start). Warm it up now and leave the tab open so blog readers don't hit a cold Space. **If it's broken:** open the "Logs" tab on the Space page → look for the Docker build error → fix locally → re-push with `uv run openenv push`. --- ## 2. Health + API docs (1 min) — CRITICAL **How:** ```bash curl -sS https://hjerpe-sql-env.hf.space/health curl -sS https://hjerpe-sql-env.hf.space/docs | head -20 # should be HTML open https://hjerpe-sql-env.hf.space/docs # visual check ``` **What to check:** - [ ] `/health` returns HTTP 200 and a JSON body (e.g. `{"status":"ok"}`) - [ ] `/docs` Swagger page lists `/reset`, `/step`, `/ws` endpoints - [ ] `/step` request schema mentions our `SQLAction` fields (`action_type`, `argument`) with values `DESCRIBE`, `SAMPLE`, `QUERY`, `ANSWER` **What you're validating:** the FastAPI server inside the container is up and the OpenAPI schema published to the Space matches our local `SQLAction` model. If schemas drift, clients break. **If it's broken:** usually means the Dockerfile picked up a stale version of `sql_env/models.py`. Rebuild and push: `uv run openenv build -t …` then `uv run openenv push`. --- ## 3. One full episode via the built-in web UI (5 min) — CRITICAL **How:** ```bash open https://hjerpe-sql-env.hf.space/web ``` OpenEnv ships a `/web` interactive UI on every env. Walk through one full episode: 1. Click **Reset** — a schema hint + question prompt should appear 2. Enter action `DESCRIBE` with argument = a table name from the reset output 3. Enter action `SAMPLE` with a table name (confirm 5 sample rows come back) 4. Enter action `QUERY` with a valid `SELECT ...` (confirm rows return) 5. Enter action `ANSWER` with your final answer (confirm reward + `done=true`) **What to check:** - [ ] Each step returns a new observation without error - [ ] Terminal `ANSWER` produces a reward (even 0.0 is fine — we're testing plumbing, not correctness) - [ ] Screenshot the final screen — free blog content **What you're validating:** the end-to-end action space a judge will exercise. This is our judges' happiest path. **If any step errors, do not publish the blog until it's fixed.** --- ## 4. Fix stale deliverables doc (3 min) — HIGH `docs/competition-deliverables.md` line 30 says: > **Status:** Not started (no Dockerfile yet) This is wrong. F007 demo (`specs/F007-DEMO.md`) shows a successful authenticated push to `https://huggingface.co/spaces/hjerpe/sql_env` on 2026-03-29. Update to: > **Status:** Live at https://huggingface.co/spaces/hjerpe/sql_env — manual > episode flow verified 2026-04-12. Also update the open items list at the bottom — "Deploy HuggingFace Space" should be checked off. --- ## 5. Python client smoke test (10 min) — HIGH **How:** First find the actual client class name and action constructor args — our client module may not match the generic OpenEnv template: ```bash rg -n "class SQLEnv\b|base_url" -g '!**/tests/**' -g '!**/docs/**' . rg -n "class SQLAction|action_type|argument" sql_env/models.py ``` Then create a throwaway script `scratch_hf_smoke.py` in the repo root: ```python from sql_env.client import SQLEnv # adjust after grep above from sql_env.models import SQLAction URL = "https://hjerpe-sql-env.hf.space" with SQLEnv(base_url=URL).sync() as env: r = env.reset() print("RESET:", r.observation) # Pick any table name from the schema hint in r.observation r = env.step(SQLAction(action_type="DESCRIBE", argument="")) print("DESCRIBE:", r.observation) r = env.step(SQLAction(action_type="QUERY", argument="SELECT 1")) print("QUERY:", r.observation) r = env.step(SQLAction(action_type="ANSWER", argument="")) print("ANSWER reward=", r.reward, "done=", r.done) ``` Run: ```bash uv run python scratch_hf_smoke.py ``` **What to check:** - [ ] No connection / WebSocket handshake errors - [ ] `r.observation` is a populated dict/string at each step - [ ] Final step: `r.reward` is a float and `r.done == True` - [ ] Delete `scratch_hf_smoke.py` after — do not commit it **What you're validating:** that a blog reader copy-pasting our snippet against the live Space actually gets a working client. If this fails and the `/web` UI (step 3) works, the problem is likely a client-side model drift — check that our shipped `sql_env/models.py` matches what the server inside the Space expects. --- ## 6. Docker image pull (10 min) — IF TIME This is the pattern every OpenEnv env on the hub ships. It's how external users run our env locally for training (no rate limits, full concurrency). **How — option A: pull the pre-built image from HF registry** ```bash docker pull --platform linux/amd64 registry.hf.space/hjerpe-sql_env:latest docker run -d --name sqlenv-smoke -p 8001:8000 --platform linux/amd64 \ registry.hf.space/hjerpe-sql_env:latest # Wait ~5s for uvicorn to boot sleep 5 curl -sS http://0.0.0.0:8001/health open http://0.0.0.0:8001/docs # Clean up docker stop sqlenv-smoke && docker rm sqlenv-smoke ``` **How — option B: rebuild locally from our repo (same image the Space runs)** ```bash uv run openenv validate --verbose # dry-run config check uv run openenv build -t openenv-sql-env:local docker run -d --name sqlenv-local -p 8001:8000 openenv-sql-env:local curl -sS http://0.0.0.0:8001/health docker stop sqlenv-local && docker rm sqlenv-local ``` **What to check:** - [ ] Image pulls without auth (Space is public) - [ ] Container starts, `/health` returns 200 - [ ] `/docs` renders Swagger on localhost - [ ] No `--platform` warnings on Apple Silicon (the Space is `linux/amd64`, which runs under Rosetta on M-series Macs — slow but functional) **What you're validating:** the reproducibility story. A broken image here means the blog's "clone and train" path is dead. Judges rarely click this, but any serious user will. --- ## 7. pip install from Space (5 min) — IF TIME **How:** First check the package name declared inside the pushed Space: ```bash curl -sS https://huggingface.co/spaces/hjerpe/sql_env/raw/main/pyproject.toml \ | grep -E '^name' ``` Then install it into a throwaway venv: ```bash uv venv /tmp/sqlenv-pip-test source /tmp/sqlenv-pip-test/bin/activate # Replace "openenv-sql-env" with whatever name the pyproject.toml above shows pip install "openenv-sql-env @ git+https://huggingface.co/spaces/hjerpe/sql_env" python -c "from sql_env.client import SQLEnv; print('OK:', SQLEnv)" deactivate && rm -rf /tmp/sqlenv-pip-test ``` **What to check:** - [ ] `pip install` resolves without dependency errors - [ ] The client class imports from the installed wheel **What you're validating:** the `pyproject.toml` we pushed into the Space actually declares the package correctly. This is the install method TRL documents: `pip install " @ git+https://huggingface.co/spaces/"`. --- ## 8. Concurrency audit — POST-LAUNCH **How:** ```bash rg -n "SUPPORTS_CONCURRENT_SESSIONS|max_concurrent_envs|create_app\(" sql_env/server/ ``` Expected result **today:** no matches (the flag is not set), which means the Space defaults to **1 concurrent WebSocket session**. Per the OpenEnv↔TRL docs, any training run with `num_generations > 1` against the hosted Space will hit capacity errors. **Fix (post-launch):** in `sql_env/server/app.py` (or wherever `create_app(...)` is called): ```python SUPPORTS_CONCURRENT_SESSIONS = True app = create_app( create_sql_environment, SQLAction, SQLObservation, max_concurrent_envs=64, # ≥ TRL's generation_batch_size ) ``` Then `uv run openenv build -t ...` and `uv run openenv push` again. **Why it's not a launch blocker:** the blog does not ask readers to train against the hosted Space. Our own training uses the in-process `SQLEnvironment` via `SQLEnvTRL` (not the WebSocket client), so we never hit this limit. Only matters if an external user wants to run `GRPOTrainer` against `https://hjerpe-sql-env.hf.space` directly. File as a GitHub issue after the blog ships. --- ## 9. TRL `environment_factory` wrapper — DONE Already implemented in `training/trl_adapter.py::SQLEnvTRL` and wired into `notebooks/train_grpo.ipynb` cell 16. See the TRL section at the top of this document for details. No action. --- --- ## Appendix A: Republish the Space from scratch (reference) Only run these if step 1–3 show the Space is broken and a rebuild+push is needed. Otherwise skip — the current Space is already live. **Prereqs (one-time):** ```bash uv sync # project deps hf auth login # HuggingFace CLI auth # (token with write access to hjerpe/sql_env) ``` **Validate + build + push:** ```bash # 1. Dry-run config check — confirms the openenv manifest, Dockerfile # and server entrypoint agree uv run openenv validate --verbose # 2. Build the Docker image locally (same image HF Spaces will run) uv run openenv build -t openenv-sql-env:local # 3. Optional: smoke-test the local image before pushing docker run -d --name sqlenv-local -p 8001:8000 openenv-sql-env:local curl -sS http://0.0.0.0:8001/health docker stop sqlenv-local && docker rm sqlenv-local # 4. Push to the Space — creates hjerpe/sql_env if it doesn't exist, # uploads files, and triggers the Space's own Docker build uv run openenv push # expected tail: # ✓ Authenticated as: hjerpe # ✓ Space hjerpe/sql_env is ready # ✓ Upload completed successfully # Space URL: https://huggingface.co/spaces/hjerpe/sql_env ``` **After push:** the Space rebuilds its own Docker image on HF's infra (takes 2–5 min). Watch the build logs in the browser at `https://huggingface.co/spaces/hjerpe/sql_env` → "Logs" tab. When it turns green, re-run steps 1–5 at the top of this doc to verify. **Files that must exist for `openenv push` to work** (already in the repo): - `openenv.yaml` — manifest with name, version, description - `sql_env/server/Dockerfile` — FastAPI + uvicorn container - `sql_env/server/app.py` — `create_app(...)` entrypoint - `sql_env/models.py` — `SQLAction` / `SQLObservation` Pydantic models - `pyproject.toml` — pip-installable package metadata - `README.md` — Space landing page (HF renders it on the Space page) If any of these drifts out of sync, `openenv validate --verbose` will flag it before you push. --- ## Appendix B: Research finding — dangling legacy reward module **Finding:** `training/rewards.py` (151 lines) is legacy dead code from the pre-F010 rollout-based architecture. It is not used by the production training path and can be deleted post-launch. **Evidence:** - Module docstring (line 1–5): *"Reward callables for TRL GRPO training. These helpers consume **rollout metadata**..."* — this is the OLD pattern where reward functions parsed `kwargs['metadata']` from TRL rollouts instead of reading `env.reward` from environment instances. - Internal helper `_extract_metadata_rows()` (line 41): *"TRL can pass rollout metadata in different shapes depending on wrapper code."* — explicit confirmation this is replay-based reward parsing. - Functions exposed: `reward_correctness`, `reward_progress`, `reward_operational`. - **Zero production imports.** `rg 'from.*training\.rewards|training\.rewards\.reward_'` returns exactly **one** hit: `tests/unit/test_rewards.py`. No script, notebook, or other module in `training/` imports it. - The real training path uses `sql_env_reward_func` in `training/trl_adapter.py`, which reads `env.reward` directly from `SQLEnvTRL` instances. This is the `environment_factory` pattern mandated by F010 and documented as the correct choice (see `specs/F010-IMPLEMENTATION_SPEC.md:173` and the user's own memory note: *"Use environment_factory or rollout_func, not replay-based reward parsing"*). - Notebook `train_grpo.ipynb` cell 16: `reward_funcs=[sql_env_reward_func]` — pulls from `trl_adapter`, not `rewards.py`. **The only `rollout` matches in `training/`** are harmless: - `training/prompts.py:1` — docstring mentions "GRPO training rollouts" - `training/rewards.py` — the legacy module itself - `notebooks/train_grpo.ipynb` cell 16 — a local variable `before_rollouts = sample_random_baseline(...)` that has nothing to do with TRL's `rollout_func` **Recommendation (post-launch, low priority):** 1. Delete `training/rewards.py` 2. Delete `tests/unit/test_rewards.py` 3. Confirm `uv run pytest tests/ -v` still passes 4. Commit with message: `refactor: remove legacy rollout-metadata reward module superseded by F010 environment_factory` **Why not today:** zero risk on launch (nothing imports it in production), and deleting files during blog-publish day is the wrong kind of churn. File as a post-launch cleanup. --- ## Post-launch cleanup - [ ] Delete this file - [ ] File issue for item 8 (Space concurrency) - [ ] Delete `training/rewards.py` + `tests/unit/test_rewards.py` (see Appendix B) - [ ] Update `docs/competition-deliverables.md` open-items list