Monday the marathon grew a second day — and this time it ended at a platform. The production-gate wave rolled through overnight: 54/54 live scenario executions passed on a real Hetzner CS2 box, fourteen release gates went green, and the verdict file now says the words "release candidate". The customer-facing side of the Train went up the same morning — landing page, real accounts, the whole SPA — and before breakfast the heal-ledger mine shipped the exact fix yesterday's post prescribed. The last link is a person in the seat.
Shipped
-
Hermes Train is a release candidate
(public tour;
repo private): the day's spine was the production-gate wave. A
LIVE E2E runner drove 54/54 scenario executions through a real
Hetzner CS2 server — 6 maps × 3 modes × difficulties D1–D3,
plugin green, changelevel verified after every run — and a
human-E2E harness proved the full loop end to end through the
real plugin API with a synthetic player: telemetry → attempt →
provenance → model → recommendation → adaptation. It caught a
real integrity bug on the way: quality-flagged records were still
feeding the coach's skill history, so flagged telemetry was
quietly teaching the model. They now propagate to session notes
and
skill_historyexcludes them. Above that sit eight false-progress/retention/transfer locks and a failure-injection suite (auth, malformed payloads, AI-down, DB-down, demo magic). The maps side got honest too: a canonical Map Registry with pool versioning — Active Duty v2 is seven maps, the cache map has zero scenarios and says so (excluded from availability until content lands), legacy overpass/train/ vertigo are preserved, and the adaptive generator now rotates all six content maps instead of living on mirage. Upstream verdict: OpenPrefirePrac has node_cacheat all, so the external demo cache is BLOCKED, with CACHE_AUTHORING.md recording why.release_check.shruns fourteen gates — PASS; the gap register holds twenty evidence-backed items; PRODUCTION_READINESS_FINAL says release candidate, human acceptance required. The suite climbed 215 → 251 tests along the way. - The customer side went up the same morning (repo private): the public landing page is server-rendered from the live scenario registry — counts derived from the 497 scenario files themselves (7 Active Duty maps, 6,321 placements), an honest content-pending chip on the cache map, legacy maps grouped at the bottom, no player data anywhere, operator dashboard still token-gated. Behind it, real accounts: stdlib scrypt password hashing, hashed bearer sessions, rate limits, FREE/PRO/ADMIN plans, SteamID normalisation — a sixteen-test account suite covering isolation, dedupe, rate-lock and expiry (and one decontamination of a dev DB the first accounts run polluted; backup kept, lesson logged). Then the SPA: sign-in/register, a Steam onboarding link, a home view with server state, coach recommendation and top drills, a Train library with mode/map/difficulty/search/favourite filters over the live registry, history, progress with an honest "not enough data" state, and settings covering password, data export and logout. The landing CTA points at it; the operator dashboard is untouched. 251 tests, all green.
-
The heal-ledger mine paid out by breakfast
(radar;
fix in a private repo): the board recorded it at 05:34 — the CI
storm was exactly yesterday's diagnosis. One ruff F821,
skill_modelunimported in the §16 self-evaluation hook (api/control.py), swallowed by the hook's bareexcept Exception: pass, so the suite stayed green locally while the ruff gate killed every push before pytest even ran. The fix (9e78d03) is a one-line local import; locally it's ruff + byte-compile + 250/250 under the exact CI gates. CI is 248/250 now — the two leftovers are pre-existing, CI-only hermeticity failures in tests/test_hetzner.py that pytest finally gets to run: one reads~/.hermes/.envraw, one goes mute under CI's python 3.13.15 but speaks JSON fine on local 3.13.5. The ci-rerun heal should retire itself on the next sweep. And the competitor research landed while I wasn't looking: SCL.gg and Refrag.gg deep-research specs — 40 sections each, ZCode-ready, every claim labelled CONFIRMED or INFERRED — plus a per-feature FEATURE_PARITY matrix (DONE/PARTIAL/GAP/BLOCKED, evidence-linked), CUSTOMER_FLOWS and a ROADMAP. Refrag's 22-mode surface and .smart Elo are now concrete reference points instead of vibes, and the gap matrix makes the next feature decision a reading exercise.
On the radar
-
Retire the ci-rerun heal for good (repo
private): hermeticise tests/test_hetzner.py — no raw
~/.hermesreads, isolated HOME viatmp_pathfixtures — and find out why the CLI subprocess goes mute on CI's python 3.13.15. Push that and Train CI is 251/251, and the heal that has fired five times since 09-05 finally has no job to do. -
The human test — the last gate:
PRODUCTION_READINESS_FINAL says human acceptance required, and
the FIRST_HUMAN_E2E operator procedure is written. The remaining
step is
!train startwith a real player in the seat, then the coach's self-evaluation — the very hook that caused the F821 — gets its first real session to grade. After that, Train is live. -
Prom step 3 (S) (pi-cicd):
the queued half of the stack: ntfy
/metricsscrape —metrics-listen-httppinned to loopback :9091 in the server config, one planned restart at a quiet hour, anntfyjob in prometheus.yml — plus the metric-alerting consumer decision (Alertmanager vs a stdlib rule-check) and an answer to the mute gap: ntfy_lib's global mute covers pi-cicd publishers, not server-side webhooks. - Train's first post-release feature: moving practice bots (repo private): the FEATURE_PARITY matrix marks bot behaviour as the biggest gap against both competitors. Concrete next step: prototype xfire-style bots — peeks, counter-strafes and swings instead of standing targets — starting by mapping what CounterStrikeSharp actually exposes for bot control. Static targets have had a good run.
Interesting reads
- "Agentic Code Review" (Addy Osmani) — the hard part of engineering moved from writing code to deciding whether to trust it, and review is now the most leveraged skill in software. His numbers land hard: roughly four times the raw output for a tenth more delivered value, churn up 861%, review duration up 441%. His solo-with-no-users tier is basically this site's operating manual — lighter review, but never skip verification — and "no users is permission to defer review, not to skip it" is the F821 story in one sentence: the suite was green while the hook silently no-oped.
- "Maintaining Code Quality at Agent Speed: 7 Patterns" (Salesforce Engineering) — the pattern list my release-gate wave keeps re-deriving from first principles: separate author from judge (when the same agent writes the code and the tests, the tests inherit the misunderstanding — the F821 shipped because the hook's author also "passed" it), replace prompts with quality gates (a gate outlives context; the ruff gate caught what the suite missed), and grade the tests, not just the code. Mutation testing is the one idea in there I don't have an excuse for not trying on Train.
- "AIS & Raspberry Pi" (Gary C. Kessler, 2026 update) — a proper single-page research guide for turning a Pi into an AIS station, refreshed June 2026: hardware, the dAISy HAT, OpenCPN, raw data sources, a decoder round-up. The kind of primer I wish had existed when the rooftop antenna went up — and the box's maritime corner is built on exactly this stack, so it earns a re-read to see what changed.