diff --git a/.github/workflows/publish-edge.yaml b/.github/workflows/publish-edge.yaml
index aa215f7de..750681607 100644
--- a/.github/workflows/publish-edge.yaml
+++ b/.github/workflows/publish-edge.yaml
@@ -1,6 +1,6 @@
name: publish-edge
-# Continuously publish beta images to GHCR on every push to master, so testers
+# Continuously publish edge images to GHCR on every push to master, so testers
# can track the latest build without waiting for a tagged release. Tagged
# releases (release.yaml, triggered by v* tags) remain the recommended,
# version-pinned install path; this is the rolling "edge" channel.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ffefb94e9..b76c8ed1c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,14 @@ reaches `1.0.0`. Pre-1.0 minor versions may contain breaking changes.
## [Unreleased]
+## [0.3.0] — 2026-10-05
+
+The first Gameplane release without a pre-release suffix, a pre-v1 release. It
+contains every change made since v0.2.0-beta.8, including the changes first
+previewed in v0.3.0-rc.1 and the pre-release audit fixes summarized under
+0.3.0-rc.2 below. It does not claim v1 or production support; see
+[`docs/roadmap.md`](docs/roadmap.md).
+
### Upgrade Notes
- **Network capture feature adds an emptyDir volume to every game pod:** The
@@ -350,11 +358,12 @@ reaches `1.0.0`. Pre-1.0 minor versions may contain breaking changes.
- **gameaction:** hardened console action parameter validation against shell and RCON metacharacters.
- **operator:** hardened tunnel credential handling: a credentials Secret not owned by its GameServer is now refused, the tunnel is scaled to zero, and TunnelReady=False (reason TunnelCredentialRefused) reports why.
-## [0.3.0-rc.2] — Unreleased
+## [0.3.0-rc.2] — not tagged
-The second release candidate for v0.3.0. It adds the changes merged since
+The second release candidate for v0.3.0 was not tagged separately; its changes
+shipped in [0.3.0](#030--2026-10-05). It covers the changes merged since
v0.3.0-rc.1, mostly fixes from the v0.3 pre-release audit. They are listed
-under [Unreleased](#unreleased) above, which also holds the rc.1 changes;
+under [0.3.0](#030--2026-10-05) above, which also holds the rc.1 changes;
the Highlights below summarize what is new since rc.1.
### Highlights
@@ -390,8 +399,8 @@ the Highlights below summarize what is new since rc.1.
The first release candidate for v0.3.0, the first Gameplane release without a
beta suffix. It contains the changes made since v0.2.0-beta.8 up to
-2026-09-23; the entries under Unreleased above that come from later PRs
-(the pre-release audit fixes) are in 0.3.0-rc.2, not in this release.
+2026-09-23; the entries under 0.3.0 above that come from later PRs
+(the pre-release audit fixes) are in 0.3.0, not in this release.
Release candidates are for testing against diverse workloads and deployment
topologies before the v1-ready v0.3.0 GA; pre-releases are
published and listed in the GitHub releases page.
@@ -1077,8 +1086,9 @@ testing. Not yet recommended for unattended production workloads — see
runner (retry + longer readiness window), eliminating a cascade of flaky
API e2e failures.
-[Unreleased]: https://github.com/ValgulNecron/gameplane/compare/v0.2.0-beta.8...HEAD
-[0.3.0-rc.2]: https://github.com/ValgulNecron/gameplane/compare/v0.3.0-rc.1...HEAD
+[Unreleased]: https://github.com/ValgulNecron/gameplane/compare/v0.3.0...HEAD
+[0.3.0]: https://github.com/ValgulNecron/gameplane/compare/v0.3.0-rc.1...v0.3.0
+[0.3.0-rc.2]: https://github.com/ValgulNecron/gameplane/compare/v0.3.0-rc.1...v0.3.0
[0.3.0-rc.1]: https://github.com/ValgulNecron/gameplane/compare/v0.2.0-beta.8...v0.3.0-rc.1
[0.2.0-beta.8]: https://github.com/ValgulNecron/gameplane/compare/v0.2.0-beta.7...v0.2.0-beta.8
[0.2.0-beta.7]: https://github.com/ValgulNecron/gameplane/compare/v0.2.0-beta.6...v0.2.0-beta.7
diff --git a/CLAUDE.md b/CLAUDE.md
index 0f6c2bbdd..7ffff46f8 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -2,7 +2,7 @@
Architecture, commands, and binding rules for AI agents. Humans: [`README.md`](README.md), [`docs/contributing.md`](docs/contributing.md).
-**Gameplane:** Kubernetes-native game server control panel (CubeCoders AMP alternative); identical on single-node k3s and multi-node clusters. **Status:** beta `v0.2.0-beta.8`; v1 scope feature-complete, stabilizing.
+**Gameplane:** Kubernetes-native game server control panel (CubeCoders AMP alternative); identical on single-node k3s and multi-node clusters. **Status:** Pre-v1 release (`v0.3.0`); v1 scope feature-complete, stabilizing.
## ⏳ Session start: blocked dependency upgrades (delete an entry once unblocked)
diff --git a/README.md b/README.md
index dfcdee9fa..5f4a2c139 100644
--- a/README.md
+++ b/README.md
@@ -5,9 +5,9 @@ A Kubernetes-native game server control panel. Open-source alternative to
Docker — scales from a single-node k3s homelab to multi-node production
clusters without changing the operational model.
-> Status: **beta** (`v0.2.0-beta.8`). The operator, API, agent, and dashboard
+> Status: **pre-v1 release** (`v0.3.0`). The operator, API, agent, and dashboard
> are feature-complete for the v1 scope and stabilized for external testing.
-> See [Beta status & known limitations](#beta-status--limitations) before
+> See [Pre-v1 status & known limitations](#pre-v1-status--limitations) before
> running it for anything you can't afford to lose.
**Website:** — features,
@@ -34,9 +34,9 @@ Screenshots are captured against mocked data for consistency and reproducibility
|  |  |
| Console — live output over WebSocket | Admin Settings — Mod registries |
-## Beta Status & Limitations
+## Pre-v1 Status & Limitations
-Gameplane is currently in **beta** (`v0.2.0-beta.8`). Core workflows — server deployment, live consoles, file management, backups/restores, game modules, multi-cluster management, and RBAC — work end-to-end and are verified by automated unit, integration, upgrade, and end-to-end test suites on every commit.
+Gameplane is a **pre-v1 release** (`v0.3.0`). Core workflows — server deployment, live consoles, file management, backups/restores, game modules, multi-cluster management, and RBAC — work end-to-end and are verified by automated unit, integration, upgrade, and end-to-end test suites on every commit.
Here are a few items to keep in mind:
@@ -58,7 +58,7 @@ and Agones (a Kubernetes operator library). While not direct competitors,
Agones is included as a reference point for teams building on Kubernetes
primitives.
-Status: **beta** (`v0.2.0-beta.8`). The operator, API, agent, and dashboard
+Status: **pre-v1 release** (`v0.3.0`). The operator, API, agent, and dashboard
are feature-complete for the v1 scope and stabilized for external testing.
| Dimension | Gameplane | Pterodactyl | CubeCoders AMP | Agones |
@@ -213,7 +213,7 @@ helm upgrade --install gameplane oci://ghcr.io/valgulnecron/charts/gameplane \
```
The chart pins matching `ghcr.io/valgulnecron/gameplane/{operator,api,agent}`
-images by `appVersion`. To track the rolling beta instead of a tagged release,
+images by `appVersion`. To track the rolling edge build instead of a tagged release,
add `--set image.tag=edge`. Then seed an admin user and log in — see
[`docs/install.md`](docs/install.md) for the full flow, OIDC, Postgres, and
values reference. For address pool configuration (pinning servers to specific
diff --git a/agent/specs.md b/agent/specs.md
index 5c806cd24..472cab9b0 100644
--- a/agent/specs.md
+++ b/agent/specs.md
@@ -1,6 +1,6 @@
# agent — Specification
-**Status:** beta (v0.2.0-beta.8)
+**Status:** pre-v1 (v0.3.0)
**Module / package:** `github.com/ValgulNecron/gameplane/agent`
## Purpose
diff --git a/api/specs.md b/api/specs.md
index f810f5408..2b2e3b824 100644
--- a/api/specs.md
+++ b/api/specs.md
@@ -1,6 +1,6 @@
# api — Specification
-**Status:** beta (v0.2.0-beta.8)
+**Status:** pre-v1 (v0.3.0)
**Module / package:** github.com/ValgulNecron/gameplane/api
## Purpose
diff --git a/audit-syslog-bridge/specs.md b/audit-syslog-bridge/specs.md
index 861262340..fb9dcd80c 100644
--- a/audit-syslog-bridge/specs.md
+++ b/audit-syslog-bridge/specs.md
@@ -1,6 +1,6 @@
# audit-syslog-bridge — Specification
-**Status:** beta (v0.2.0-beta.8)
+**Status:** pre-v1 (v0.3.0)
**Module / package:** `github.com/ValgulNecron/gameplane/audit-syslog-bridge`
## Purpose
diff --git a/capture-sidecar/specs.md b/capture-sidecar/specs.md
index ae37916f9..01f164154 100644
--- a/capture-sidecar/specs.md
+++ b/capture-sidecar/specs.md
@@ -1,6 +1,6 @@
# capture-sidecar — Specification
-**Status:** beta (v0.2.0-beta.8), Phase 2 Foundational (implementation complete)
+**Status:** pre-v1 (v0.3.0), Phase 2 Foundational (implementation complete)
**Module / command:** `github.com/ValgulNecron/gameplane/capture-sidecar`
**Dependencies (current):** stdlib + external libraries for packet capture and filtering (github.com/gopacket/gopacket v1.7.2, github.com/packetcap/go-pcap, golang.org/x/net)
diff --git a/charts/gameplane/Chart.yaml b/charts/gameplane/Chart.yaml
index 35d0d95f3..92ac06250 100644
--- a/charts/gameplane/Chart.yaml
+++ b/charts/gameplane/Chart.yaml
@@ -2,8 +2,8 @@ apiVersion: v2
name: gameplane
description: Kubernetes-native game server control panel (open-source alternative to CubeCoders AMP).
type: application
-version: 0.2.0-beta.8
-appVersion: "0.2.0-beta.8"
+version: 0.3.0
+appVersion: "0.3.0"
home: https://github.com/ValgulNecron/gameplane
sources:
- https://github.com/ValgulNecron/gameplane
diff --git a/charts/gameplane/values.yaml b/charts/gameplane/values.yaml
index 17e7bf685..3de37b9fa 100644
--- a/charts/gameplane/values.yaml
+++ b/charts/gameplane/values.yaml
@@ -579,7 +579,7 @@ defaultModuleSource:
# own cluster). Bump this ref only in lockstep with a chart release that
# was actually tested against the matching module-repo tag. Set to
# "main" explicitly if you want the bleeding edge instead.
- ref: v0.2.0-beta.6
+ ref: v0.3.0
subPath: "" # module directories live at the repo root
oci:
url: ghcr.io/valgulnecron/gameplane-modules
diff --git a/docs/comparison-sources.md b/docs/comparison-sources.md
index 92c42af70..9d187dce5 100644
--- a/docs/comparison-sources.md
+++ b/docs/comparison-sources.md
@@ -21,7 +21,7 @@ verified.
**Source ID**: G-a
**Evidence**: README.md:8; operator/api/v1alpha1/gameserver_types.go:1–50
**Checked on**: 2026-09-02
-**What was verified**: README status line confirms project is beta; GameServer CRD types and controller-runtime operator documented in operator module with support for k3s and multi-node clusters.
+**What was verified**: README status line confirms project is a pre-v1 release (`v0.3.0`; status line re-checked 2026-10-05); GameServer CRD types and controller-runtime operator documented in operator module with support for k3s and multi-node clusters.
**Last-known URL**: https://github.com/ValgulNecron/Gameplane
diff --git a/docs/dependencies.md b/docs/dependencies.md
index ce7385fa2..6cb48f058 100644
--- a/docs/dependencies.md
+++ b/docs/dependencies.md
@@ -26,11 +26,11 @@ to find call sites (or `go mod why -m ` from inside the module). For
Toolchain versions come from `Makefile`, `.github/workflows/*.yaml`, and
`.devcontainer/post-create.sh`.
-Accurate as of **2026-09-02**, repo state `v0.2.0-beta.8`; the `gameproto`,
+Accurate as of **2026-09-02**, repo state `v0.3.0`; the `gameproto`,
`svcutil`, `sentinel`, `capture-sidecar`, `tunnel`, and `gp-module` sections
were added and verified on **2026-09-26**.
-> **Note:** The dependency versions listed in the table below reflect the state at v0.2.0-beta.8. For the most current versions, refer to [CHANGELOG.md](../CHANGELOG.md).
+> **Note:** The dependency versions listed in the table below reflect the state at v0.3.0. For the most current versions, refer to [CHANGELOG.md](../CHANGELOG.md).
## At a glance
@@ -317,7 +317,7 @@ package a game module before publishing it. Direct deps from
### web
React 18 + TypeScript strict + Vite dashboard (`web/package.json` version
-`0.2.0-beta.8`, matching the repo version):
+`0.3.0`, matching the repo version):
**Framework / core**
- `react` `^19.2.8`, `react-dom` `^19.2.8` — base UI framework, rendered via `createRoot` in `src/main.tsx`, used throughout every component.
diff --git a/docs/install.md b/docs/install.md
index 68bf30122..115604816 100644
--- a/docs/install.md
+++ b/docs/install.md
@@ -11,7 +11,7 @@
The chart and its images are published to the GitHub Container Registry (GHCR)
as OCI artifacts — no `helm repo add` needed. Install a tagged release straight
-from the registry (replace `` with a release, e.g. `0.2.0-beta.8`):
+from the registry (replace `` with a release, e.g. `0.3.0`):
```sh
helm upgrade --install gameplane oci://ghcr.io/valgulnecron/charts/gameplane \
@@ -31,7 +31,7 @@ belong to is enabled (and, for `sentinel` and `capture-sidecar`, only for
GameServers that opt in). See each component's values block for its enable
flag.
-### Edge channel (latest beta)
+### Edge channel (latest edge build)
Every push to `master` publishes rolling `:edge` images. To track them, install
the chart and point images at the edge tag:
@@ -634,7 +634,7 @@ GameServers intact.
`helm` instead of skipping existing CRDs, so a `helm install` over leftover
CRDs updates them itself (stamp included) and the hook stays pre-upgrade
only. The hook applies under the same `helm` field manager so that apply
-never conflicts with it. Releases up to `0.2.0-beta.8` applied under
+never conflicts with it. Releases up to and including `0.2.0-beta.8` applied under
kubectl's default manager (`kubectl`); if CRDs such a release upgraded were
left behind, a Helm 4 `helm install` stops with `conflict with "kubectl" …
.spec.versions`. Re-run it with `--force-conflicts` to take them over:
diff --git a/docs/roadmap.md b/docs/roadmap.md
index 68b2a4d69..a38ffd59f 100644
--- a/docs/roadmap.md
+++ b/docs/roadmap.md
@@ -1,9 +1,9 @@
# Roadmap to v1
-Gameplane is currently **`v0.2.0-beta.8`**. The CRDs, operator, API, agent, and
+Gameplane is currently **`v0.3.0`**. The CRDs, operator, API, agent, and
dashboard are feature-complete for the v1 scope and stabilized for external
testing, but the project is not yet recommended for unattended production. This
-page tracks what stands between beta and a v1 GA release.
+page tracks what stands between v0.3 and a v1 GA release.
It is a living document: items move out of it as they ship, and anything
discovered along the way gets added. For what already works today, see
@@ -73,7 +73,7 @@ remaining gap and is a candidate future hardening, not yet implemented.
Threat-model context lives in [`security.md`](security.md#audit-log-integrity).
-### Upgrade testing (`e2e upgrade` bucket) (shipped v0.2.0-beta.8)
+### Upgrade testing (`e2e upgrade` bucket) (shipped v0.2.0-beta.8)
`helm upgrade` was the most dangerous operation a user performs and the only
one CI never exercised. It now runs on every PR, on both amd64 and arm64:
@@ -97,7 +97,7 @@ while, but [`install.md`](install.md#helm-crd-caveat) still told users to run
Not yet covered: upgrades skipping several releases at once, and Postgres [experimental].
-### Idle auto-sleep (backend PR #180, dashboard PR #182) (shipped v0.2.0-beta.8)
+### Idle auto-sleep (backend PR #180, dashboard PR #182) (shipped v0.2.0-beta.8)
Opt-in per server (`spec.idle`): the operator scales a GameServer to zero once
it has reported no online players for `afterMinutes`, and brings it back on a
@@ -140,7 +140,7 @@ browser would duplicate scheduling semantics the operator owns (rule 10).
Persisting it on status is the right fix, and is a CRD change rather than a
dashboard one.
-### Wake-on-connect for idle auto-sleep (shipped v0.2.0-beta.8)
+### Wake-on-connect for idle auto-sleep (shipped v0.2.0-beta.8)
A sentinel [optional] component holds advertised ports while a server is asleep and wakes
it on a genuine connection attempt. Opt-in per server via `spec.idle.wakeOnConnect`
@@ -186,7 +186,7 @@ A new optional component [optional] (distroless Docker image, Helm toggle) expos
"Propose a fix" returns suggested YAML or `kubectl` invocations as text — no
create/update/delete/patch tool exists. See [`mcp-server/README.md`](../mcp-server/README.md).
-### Module signing: active for official bundles (ECDSA P-256, Rekor-logged) (shipped v0.2.0-beta.8)
+### Module signing: active for official bundles (ECDSA P-256, Rekor-logged) (shipped v0.2.0-beta.8)
The keyed-cosign signing mechanism is implemented and e2e-proven, and
`ModuleSource.spec.verify` can require a valid signature. It is now **active**
@@ -201,7 +201,7 @@ fail-closed when the key is absent. The operator's verify path remains
offline/keyed, preserving air-gapped functionality. See
[Signing official bundles](module-authoring.md#signing-official-bundles).
-### Hermetic module images (gameplane-module#35, docs in #178) (shipped v0.2.0-beta.8)
+### Hermetic module images (gameplane-module#35, docs in #178) (shipped v0.2.0-beta.8)
Every shipped module's default image is now pinned by digest, so a server
binary can no longer change underneath a user on pod restart with no version
@@ -220,7 +220,7 @@ opt-out), and a monthly workflow refreshes the pins. Authoring rules live in
## Blocking v1
-Nothing hard-blocks v1 anymore. What stands between beta and a v1 GA is the
+Nothing hard-blocks v1 anymore. What stands between v0.3 and a v1 GA is the
production-readiness hardening below — tracked items, not code gaps.
---
diff --git a/gameaction/specs.md b/gameaction/specs.md
index 4387f4cbb..062c10499 100644
--- a/gameaction/specs.md
+++ b/gameaction/specs.md
@@ -1,6 +1,6 @@
# gameaction — Specification
-**Status:** beta (v0.2.0-beta.8)
+**Status:** pre-v1 (v0.3.0)
**Module / package:** `github.com/ValgulNecron/gameplane/gameaction`
**Dependencies:** stdlib only (Go 1.26+)
diff --git a/gameproto/specs.md b/gameproto/specs.md
index 37f61ccde..f148a3bc8 100644
--- a/gameproto/specs.md
+++ b/gameproto/specs.md
@@ -1,6 +1,6 @@
# gameproto — Specification
-**Status:** beta (v0.2.0-beta.8)
+**Status:** pre-v1 (v0.3.0)
**Module / package:** `github.com/ValgulNecron/gameplane/gameproto`
**Dependencies:** stdlib only (Go 1.26+)
diff --git a/hack/check-links.sh b/hack/check-links.sh
index 50cbdc3f3..0c2052512 100755
--- a/hack/check-links.sh
+++ b/hack/check-links.sh
@@ -57,14 +57,14 @@
# (in document order), append -1, -2, ... to disambiguate, matching
# GitHub's own de-duplication behavior.
#
-# Worked example: "## Beta Status & Limitations"
-# -> strip marker: "Beta Status & Limitations"
+# Worked example: "## Pre-v1 Status & Limitations"
+# -> strip marker: "Pre-v1 Status & Limitations"
# -> no markdown link, no backticks
# -> remove '&' (its surrounding spaces are untouched by the removal,
# since only the '&' character itself is deleted):
-# "Beta Status Limitations" (two spaces)
-# -> lowercase: "beta status limitations"
-# -> spaces -> hyphens: "beta-status--limitations" (two hyphens)
+# "Pre-v1 Status Limitations" (two spaces)
+# -> lowercase: "pre-v1 status limitations"
+# -> spaces -> hyphens: "pre-v1-status--limitations" (two hyphens)
#
# Explicit HTML anchors `` / `` (case-insensitive tag
# and attribute name; single or double quoted value) are also valid anchor
@@ -208,7 +208,7 @@ self_test() {
# Regression: existing ASCII behavior (worked example in the header
# comment) must not change.
_assert_slug "ASCII punctuation (regression)" \
- "Beta Status & Limitations" "beta-status--limitations"
+ "Pre-v1 Status & Limitations" "pre-v1-status--limitations"
# Unicode arrow: only the arrow itself is dropped, surrounding spaces
# are untouched (so two spaces -> two hyphens), matching GitHub.
diff --git a/mcp-server/specs.md b/mcp-server/specs.md
index b8e5a21d8..a3a1ce71b 100644
--- a/mcp-server/specs.md
+++ b/mcp-server/specs.md
@@ -1,6 +1,6 @@
# mcp-server — Specification
-**Status:** beta (v0.2.0-beta.8)
+**Status:** pre-v1 (v0.3.0)
**Module / package:** `github.com/ValgulNecron/gameplane/mcp-server`
## Purpose
diff --git a/netguard/specs.md b/netguard/specs.md
index 4f43e8f37..5538e767e 100644
--- a/netguard/specs.md
+++ b/netguard/specs.md
@@ -1,6 +1,6 @@
# netguard — Specification
-**Status:** beta (v0.2.0-beta.8)
+**Status:** pre-v1 (v0.3.0)
**Module / package:** github.com/ValgulNecron/gameplane/netguard
## Purpose
diff --git a/operator/specs.md b/operator/specs.md
index 0024dc1fe..00f7729b3 100644
--- a/operator/specs.md
+++ b/operator/specs.md
@@ -1,6 +1,6 @@
# operator — Specification
-**Status:** beta (v0.2.0-beta.8)
+**Status:** pre-v1 (v0.3.0)
**Module / package:** github.com/ValgulNecron/gameplane/operator
**Go version:** 1.26.0
diff --git a/sentinel/specs.md b/sentinel/specs.md
index f0331dad0..18e7c2b3a 100644
--- a/sentinel/specs.md
+++ b/sentinel/specs.md
@@ -1,6 +1,6 @@
# sentinel — Specification
-**Status:** beta (v0.2.0-beta.8)
+**Status:** pre-v1 (v0.3.0)
**Module / command:** `github.com/ValgulNecron/gameplane/sentinel`
**Dependencies:** Kubernetes `client-go` (dynamic client, in-cluster config), `k8s.io/apimachinery`, gameproto
diff --git a/telemetry-receiver/README.md b/telemetry-receiver/README.md
index 318700122..d0186e260 100644
--- a/telemetry-receiver/README.md
+++ b/telemetry-receiver/README.md
@@ -6,7 +6,7 @@ a day when the admin has enabled **Admin Settings → Telemetry → Send
anonymous usage metrics**:
```json
-{ "version": "0.2.0-beta.8", "servers": 3, "templates": 7 }
+{ "version": "0.3.0", "servers": 3, "templates": 7 }
```
No names, namespaces, hostnames, or identifiers of any kind — the
@@ -25,7 +25,7 @@ are never stored.
Metrics:
```
-gameplane_telemetry_reports_total{version="0.2.0-beta.8"} # reports by reported version
+gameplane_telemetry_reports_total{version="0.3.0"} # reports by reported version
gameplane_telemetry_servers # histogram of GameServer counts
gameplane_telemetry_templates # histogram of GameTemplate counts
```
diff --git a/telemetry-receiver/specs.md b/telemetry-receiver/specs.md
index b246daf69..f692c635e 100644
--- a/telemetry-receiver/specs.md
+++ b/telemetry-receiver/specs.md
@@ -1,6 +1,6 @@
# telemetry-receiver — Specification
-**Status:** beta (v0.2.0-beta.8)
+**Status:** pre-v1 (v0.3.0)
**Module / package:** github.com/ValgulNecron/gameplane/telemetry-receiver
**Go version:** 1.26
@@ -50,7 +50,7 @@ telemetry-receiver/
### Ingest payload
```json
-{ "version": "0.2.0-beta.7", "servers": 3, "templates": 7 }
+{ "version": "0.3.0", "servers": 3, "templates": 7 }
```
The body must be exactly one JSON object with all three required fields and no trailing non-whitespace content. Keys are matched exactly, case-sensitively; duplicate keys are rejected. Missing or null required fields and unknown fields are rejected (16 KiB body cap applies to the entire request).
@@ -62,7 +62,7 @@ The body must be exactly one JSON object with all three required fields and no t
### Prometheus metrics
```
-gameplane_telemetry_reports_total{version="0.2.0-beta.7"} # counter, by version label
+gameplane_telemetry_reports_total{version="0.3.0"} # counter, by version label
gameplane_telemetry_servers_bucket{le="…"} # histogram (buckets: 0,1,2,5,10,25,50,100,250,+Inf)
gameplane_telemetry_servers_sum # histogram sum
gameplane_telemetry_servers_count # histogram count
diff --git a/test/e2e/internal/7-days-to-die/spec.md b/test/e2e/internal/7-days-to-die/spec.md
index 11e0668df..5f817d6c4 100644
--- a/test/e2e/internal/7-days-to-die/spec.md
+++ b/test/e2e/internal/7-days-to-die/spec.md
@@ -20,7 +20,7 @@ GAMEPLANE_E2E_REUSE_CLUSTER=1 GAMEPLANE_E2E_CONTEXT= GAMEPLANE_E2E
A successful run is the only event that licenses updating `Last Verified` to the current date.
-**Status:** beta (v0.2.0-beta.8)
+**Status:** pre-v1 (v0.3.0)
**Module / package:** `github.com/ValgulNecron/gameplane/test/e2e/internal/7-days-to-die`
**Dependencies:** stdlib + shared protocol family `a2s` (Go 1.25+); tested against vinanrra/7dtd-server:v0.9.3 (UNMEASURED against a real server — see "Measured connectivity")
diff --git a/test/e2e/internal/ark-survival-ascended/spec.md b/test/e2e/internal/ark-survival-ascended/spec.md
index f3946b60f..058d9e9ca 100644
--- a/test/e2e/internal/ark-survival-ascended/spec.md
+++ b/test/e2e/internal/ark-survival-ascended/spec.md
@@ -20,7 +20,7 @@ GAMEPLANE_E2E_REUSE_CLUSTER=1 GAMEPLANE_E2E_CONTEXT= GAMEPLANE_E2E
A successful run is the only event that licenses updating `Last Verified` to the current date.
-**Status:** beta (v0.2.0-beta.8)
+**Status:** pre-v1 (v0.3.0)
**Module / package:** `github.com/ValgulNecron/gameplane/test/e2e/internal/ark-survival-ascended`
**Dependencies:** stdlib only (Go 1.25+); tested against mschnitzer/asa-linux-server:1.5.1
diff --git a/test/e2e/internal/ark-survival-evolved/spec.md b/test/e2e/internal/ark-survival-evolved/spec.md
index ea74f17b8..63063e3d0 100644
--- a/test/e2e/internal/ark-survival-evolved/spec.md
+++ b/test/e2e/internal/ark-survival-evolved/spec.md
@@ -18,7 +18,7 @@ This test is part of the `bot-heavy` bucket and does not run by default in CI. T
GAMEPLANE_E2E_REUSE_CLUSTER=1 GAMEPLANE_E2E_CONTEXT= GAMEPLANE_E2E_GAME_BOT=1 GAMEPLANE_E2E_GAMES=ark-survival-evolved make test-e2e-keep
```
-**Status:** beta; probe depth measured: **QUERY** (A2S query response received)
+**Status:** pre-v1; probe depth measured: **QUERY** (A2S query response received)
**Module / package:** `github.com/ValgulNecron/gameplane/test/e2e/internal/ark-survival-evolved`
**Dependencies:** `test/e2e/internal/protocol/{a2sproto,joindepth}`
**Heavy game:** Yes (>30GB SteamCMD download)
diff --git a/test/e2e/internal/arma-reforger/spec.md b/test/e2e/internal/arma-reforger/spec.md
index 30cc70dad..fccb1b3f3 100644
--- a/test/e2e/internal/arma-reforger/spec.md
+++ b/test/e2e/internal/arma-reforger/spec.md
@@ -18,7 +18,7 @@ This test is part of the `bot-heavy` bucket and does not run by default in CI. T
GAMEPLANE_E2E_REUSE_CLUSTER=1 GAMEPLANE_E2E_CONTEXT= GAMEPLANE_E2E_GAME_BOT=1 GAMEPLANE_E2E_GAMES=arma-reforger make test-e2e-keep
```
-**Status:** beta; probe depth measured: **QUERY** (A2S query response received)
+**Status:** pre-v1; probe depth measured: **QUERY** (A2S query response received)
**Module / package:** `github.com/ValgulNecron/gameplane/test/e2e/internal/arma-reforger`
**Dependencies:** `test/e2e/internal/protocol/{a2sproto,joindepth}`
**Heavy game:** Yes (>15GB SteamCMD download)
diff --git a/test/e2e/internal/beammp/spec.md b/test/e2e/internal/beammp/spec.md
index fcb2136e2..a50fbb770 100644
--- a/test/e2e/internal/beammp/spec.md
+++ b/test/e2e/internal/beammp/spec.md
@@ -18,7 +18,7 @@ This test is part of the `bot-fast` bucket and can run in CI against a test clus
GAMEPLANE_E2E_REUSE_CLUSTER=1 GAMEPLANE_E2E_CONTEXT= GAMEPLANE_E2E_GAME_BOT=1 GAMEPLANE_E2E_GAMES=beammp make test-e2e-keep
```
-**Status:** beta; probe depth measured: **QUERY** (BeamMP TCP handshake success)
+**Status:** pre-v1; probe depth measured: **QUERY** (BeamMP TCP handshake success)
**Module / package:** `github.com/ValgulNecron/gameplane/test/e2e/internal/beammp`
**Dependencies:** stdlib only
**Heavy game:** No (<5Gi storage, fast container startup)
diff --git a/test/e2e/internal/cs2/spec.md b/test/e2e/internal/cs2/spec.md
index 629c6b329..3331a3572 100644
--- a/test/e2e/internal/cs2/spec.md
+++ b/test/e2e/internal/cs2/spec.md
@@ -20,7 +20,7 @@ GAMEPLANE_E2E_REUSE_CLUSTER=1 GAMEPLANE_E2E_CONTEXT= GAMEPLANE_E2E
A successful run is the only event that licenses updating `Last Verified` to the current date.
-**Status:** beta (v0.2.0-beta.8); probe depth measured: **QUERY** (A2S query success)
+**Status:** pre-v1 (v0.3.0); probe depth measured: **QUERY** (A2S query success)
**Module / package:** `github.com/ValgulNecron/gameplane/test/e2e/internal/cs2`
**Dependencies:** stdlib only (Go 1.25+); tested against CS2 Image 4.0.1 (joedwards32/cs2); image pin required (floating tag drifts)
**Heavy game (never runs in CI):** See "Why CS2 is heavy and never in CI" section below
diff --git a/test/e2e/internal/dont-starve-together/spec.md b/test/e2e/internal/dont-starve-together/spec.md
index 1057f8f89..109c4c158 100644
--- a/test/e2e/internal/dont-starve-together/spec.md
+++ b/test/e2e/internal/dont-starve-together/spec.md
@@ -20,7 +20,7 @@ GAMEPLANE_E2E_REUSE_CLUSTER=1 GAMEPLANE_E2E_CONTEXT= GAMEPLANE_E2E
A successful run is the only event that licenses updating `Last Verified` to the current date.
-**Status:** beta (v0.2.0-beta.8)
+**Status:** pre-v1 (v0.3.0)
**Module / package:** `github.com/ValgulNecron/gameplane/test/e2e/internal/dont-starve-together`
**Dependencies:** stdlib + shared `protocol/a2s` (Go 1.25+); tested against jamesits/dst-server:vanilla (query-port assertion UNMEASURED against a real server — see "Measured connectivity")
diff --git a/test/e2e/internal/enshrouded/spec.md b/test/e2e/internal/enshrouded/spec.md
index c8753cf89..ed623222c 100644
--- a/test/e2e/internal/enshrouded/spec.md
+++ b/test/e2e/internal/enshrouded/spec.md
@@ -20,7 +20,7 @@ GAMEPLANE_E2E_REUSE_CLUSTER=1 GAMEPLANE_E2E_CONTEXT= GAMEPLANE_E2E
A successful run is the only event that licenses updating `Last Verified` to the current date.
-**Status:** beta (v0.2.0-beta.8)
+**Status:** pre-v1 (v0.3.0)
**Module / package:** `github.com/ValgulNecron/gameplane/test/e2e/internal/enshrouded`
**Dependencies:** stdlib only (Go 1.25+); tested against mornedhels/enshrouded-server:1.7.2
diff --git a/test/e2e/internal/euro-truck-simulator-2/spec.md b/test/e2e/internal/euro-truck-simulator-2/spec.md
index bcf2ca170..ba41acff6 100644
--- a/test/e2e/internal/euro-truck-simulator-2/spec.md
+++ b/test/e2e/internal/euro-truck-simulator-2/spec.md
@@ -18,7 +18,7 @@ This test is part of the `bot-heavy` bucket and does not run by default in CI. T
GAMEPLANE_E2E_REUSE_CLUSTER=1 GAMEPLANE_E2E_CONTEXT= GAMEPLANE_E2E_GAME_BOT=1 GAMEPLANE_E2E_GAMES=euro-truck-simulator-2 make test-e2e-keep
```
-**Status:** beta; probe depth measured: **QUERY** (A2S query response received)
+**Status:** pre-v1; probe depth measured: **QUERY** (A2S query response received)
**Module / package:** `github.com/ValgulNecron/gameplane/test/e2e/internal/euro-truck-simulator-2`
**Dependencies:** `test/e2e/internal/protocol/{a2sproto,joindepth}`
**Heavy game:** Yes (>10GB SteamCMD download)
diff --git a/test/e2e/internal/factorio/spec.md b/test/e2e/internal/factorio/spec.md
index a7dd29098..bc049472a 100644
--- a/test/e2e/internal/factorio/spec.md
+++ b/test/e2e/internal/factorio/spec.md
@@ -10,7 +10,7 @@
- **Blocker**: Wire format undocumented; server and client must match exactly (version-locked)
- **Blocker Class**: documentation
-**Status:** beta (v0.2.0-beta.8)
+**Status:** pre-v1 (v0.3.0)
**Module / package:** `github.com/ValgulNecron/gameplane/test/e2e/internal/factorio`
**Dependencies:** stdlib only (Go 1.25+); tested against factoriotools/factorio:stable (2.0.x); image: `factoriotools/factorio:stable@sha256:7052b3cca8ca7790f99f4058617d5c8089df544de736b1baa23f2c5f58fb7f48`
diff --git a/test/e2e/internal/farming-simulator-25/spec.md b/test/e2e/internal/farming-simulator-25/spec.md
index 26cf41c3d..0a27e3ba0 100644
--- a/test/e2e/internal/farming-simulator-25/spec.md
+++ b/test/e2e/internal/farming-simulator-25/spec.md
@@ -18,7 +18,7 @@ This test is part of the `bot-heavy` bucket and does not run by default in CI. T
GAMEPLANE_E2E_REUSE_CLUSTER=1 GAMEPLANE_E2E_CONTEXT= GAMEPLANE_E2E_GAME_BOT=1 GAMEPLANE_E2E_GAMES=farming-simulator-25 make test-e2e-keep
```
-**Status:** beta; probe depth measured: **QUERY** (GIANTS web portal HTTP response)
+**Status:** pre-v1; probe depth measured: **QUERY** (GIANTS web portal HTTP response)
**Module / package:** `github.com/ValgulNecron/gameplane/test/e2e/internal/farming-simulator-25`
**Dependencies:** stdlib only
**Heavy game:** Yes (>30GB disk download, headless Wine/Proton)
diff --git a/test/e2e/internal/fivem/spec.md b/test/e2e/internal/fivem/spec.md
index 6b8ec73e8..a420e14f1 100644
--- a/test/e2e/internal/fivem/spec.md
+++ b/test/e2e/internal/fivem/spec.md
@@ -18,7 +18,7 @@ This test is part of the `bot-heavy` bucket and does not run by default in CI. T
GAMEPLANE_E2E_REUSE_CLUSTER=1 GAMEPLANE_E2E_CONTEXT= GAMEPLANE_E2E_GAME_BOT=1 GAMEPLANE_E2E_GAMES=fivem make test-e2e-keep
```
-**Status:** beta; probe depth measured: **QUERY** (HTTP info.json query success)
+**Status:** pre-v1; probe depth measured: **QUERY** (HTTP info.json query success)
**Module / package:** `github.com/ValgulNecron/gameplane/test/e2e/internal/fivem`
**Dependencies:** stdlib only
**Heavy game:** Yes (>5Gi storage and embedded database supervision)
diff --git a/test/e2e/internal/garrys-mod/spec.md b/test/e2e/internal/garrys-mod/spec.md
index 0f7c84303..1f9f4b097 100644
--- a/test/e2e/internal/garrys-mod/spec.md
+++ b/test/e2e/internal/garrys-mod/spec.md
@@ -10,7 +10,7 @@
- **Blocker**: C2S_CONNECT field offsets unknown; challenge exchange already decoded, sv_lan 1 removes the Steam gate
- **Blocker Class**: documentation
-**Status:** beta (v0.2.0-beta.8)
+**Status:** pre-v1 (v0.3.0)
**Module / package:** `github.com/ValgulNecron/gameplane/test/e2e/internal/garrys-mod`
**Dependencies:** stdlib only (Go 1.25+); tested against ceifa/garrysmod:debian; shared protocol families `a2s`, `source`
diff --git a/test/e2e/internal/hell-let-loose/spec.md b/test/e2e/internal/hell-let-loose/spec.md
index 614a40aa5..17331d4d0 100644
--- a/test/e2e/internal/hell-let-loose/spec.md
+++ b/test/e2e/internal/hell-let-loose/spec.md
@@ -18,7 +18,7 @@ This test is part of the `bot-heavy` bucket and does not run by default in CI. T
GAMEPLANE_E2E_REUSE_CLUSTER=1 GAMEPLANE_E2E_CONTEXT= GAMEPLANE_E2E_GAME_BOT=1 GAMEPLANE_E2E_GAMES=hell-let-loose make test-e2e-keep
```
-**Status:** beta; probe depth measured: **QUERY** (A2S query response received)
+**Status:** pre-v1; probe depth measured: **QUERY** (A2S query response received)
**Module / package:** `github.com/ValgulNecron/gameplane/test/e2e/internal/hell-let-loose`
**Dependencies:** `test/e2e/internal/protocol/{a2sproto,joindepth}`
**Heavy game:** Yes (>30GB SteamCMD download)
diff --git a/test/e2e/internal/left-4-dead-2/spec.md b/test/e2e/internal/left-4-dead-2/spec.md
index 3013b1cce..8263ea711 100644
--- a/test/e2e/internal/left-4-dead-2/spec.md
+++ b/test/e2e/internal/left-4-dead-2/spec.md
@@ -18,7 +18,7 @@ This test is part of the `bot-heavy` bucket and does not run by default in CI. T
GAMEPLANE_E2E_REUSE_CLUSTER=1 GAMEPLANE_E2E_CONTEXT= GAMEPLANE_E2E_GAME_BOT=1 GAMEPLANE_E2E_GAMES=left-4-dead-2 make test-e2e-keep
```
-**Status:** beta; probe depth measured: **QUERY** (A2S query response received)
+**Status:** pre-v1; probe depth measured: **QUERY** (A2S query response received)
**Module / package:** `github.com/ValgulNecron/gameplane/test/e2e/internal/left-4-dead-2`
**Dependencies:** `test/e2e/internal/protocol/{a2sproto,sourceproto,joindepth}`
**Heavy game:** Yes (>10GB SteamCMD download)
diff --git a/test/e2e/internal/minecraft-java/spec.md b/test/e2e/internal/minecraft-java/spec.md
index 79b10d134..e53a86991 100644
--- a/test/e2e/internal/minecraft-java/spec.md
+++ b/test/e2e/internal/minecraft-java/spec.md
@@ -10,7 +10,7 @@
- **Blocker**: —
- **Blocker Class**: —
-**Status:** beta (v0.2.0-beta.8)
+**Status:** pre-v1 (v0.3.0)
**Module / package:** `github.com/ValgulNecron/gameplane/test/e2e/internal/minecraft-java`
**Dependencies:** stdlib only (Go 1.25+); tested against Minecraft 1.21.4; image: `itzg/minecraft-server:java21`
diff --git a/test/e2e/internal/mount-and-blade-2-bannerlord/spec.md b/test/e2e/internal/mount-and-blade-2-bannerlord/spec.md
index a0d7325af..10769fe9a 100644
--- a/test/e2e/internal/mount-and-blade-2-bannerlord/spec.md
+++ b/test/e2e/internal/mount-and-blade-2-bannerlord/spec.md
@@ -18,7 +18,7 @@ This test is part of the `bot-heavy` bucket and does not run by default in CI. T
GAMEPLANE_E2E_REUSE_CLUSTER=1 GAMEPLANE_E2E_CONTEXT= GAMEPLANE_E2E_GAME_BOT=1 GAMEPLANE_E2E_GAMES=mount-and-blade-2-bannerlord make test-e2e-keep
```
-**Status:** beta; probe depth measured: **QUERY** (A2S query response received)
+**Status:** pre-v1; probe depth measured: **QUERY** (A2S query response received)
**Module / package:** `github.com/ValgulNecron/gameplane/test/e2e/internal/mount-and-blade-2-bannerlord`
**Dependencies:** `test/e2e/internal/protocol/{a2sproto,joindepth}`
**Heavy game:** Yes (>30GB SteamCMD download, headless Wine)
diff --git a/test/e2e/internal/palworld/spec.md b/test/e2e/internal/palworld/spec.md
index 6805d10d0..1494eff71 100644
--- a/test/e2e/internal/palworld/spec.md
+++ b/test/e2e/internal/palworld/spec.md
@@ -20,7 +20,7 @@ GAMEPLANE_E2E_REUSE_CLUSTER=1 GAMEPLANE_E2E_CONTEXT= GAMEPLANE_E2E
A successful run is the only event that licenses updating `Last Verified` to the current date.
-**Status:** beta (v0.2.0-beta.8)
+**Status:** pre-v1 (v0.3.0)
**Module / package:** `github.com/ValgulNecron/gameplane/test/e2e/internal/palworld`
**Dependencies:** stdlib only (Go 1.25+); tested against Palworld via thijsvanloef/palworld-server-docker:latest
diff --git a/test/e2e/internal/project-zomboid/spec.md b/test/e2e/internal/project-zomboid/spec.md
index 55703045a..470f68fe0 100644
--- a/test/e2e/internal/project-zomboid/spec.md
+++ b/test/e2e/internal/project-zomboid/spec.md
@@ -20,7 +20,7 @@ GAMEPLANE_E2E_REUSE_CLUSTER=1 GAMEPLANE_E2E_CONTEXT= GAMEPLANE_E2E
A successful run is the only event that licenses updating `Last Verified` to the current date.
-**Status:** beta (v0.2.0-beta.8)
+**Status:** pre-v1 (v0.3.0)
**Module / package:** `github.com/ValgulNecron/gameplane/test/e2e/internal/project-zomboid`
**Dependencies:** stdlib + shared `protocol/a2s` (Go 1.25+); tested against sknnr/zomboid-dedicated-server:v1.1.1 (UNMEASURED against a real server — see "Measured connectivity")
diff --git a/test/e2e/internal/protocol/a2sproto/spec.md b/test/e2e/internal/protocol/a2sproto/spec.md
index 994eb80d5..45c09690d 100644
--- a/test/e2e/internal/protocol/a2sproto/spec.md
+++ b/test/e2e/internal/protocol/a2sproto/spec.md
@@ -1,6 +1,6 @@
# A2S (Valve Source Query) Protocol
-**Status:** beta (v0.2.0-beta.8)
+**Status:** pre-v1 (v0.3.0)
**Module / package:** `test/e2e/internal/protocol/a2s`
**Dependencies:** stdlib only (Go 1.25+)
diff --git a/test/e2e/internal/protocol/sourceproto/spec.md b/test/e2e/internal/protocol/sourceproto/spec.md
index fbc108715..8ba8f87ea 100644
--- a/test/e2e/internal/protocol/sourceproto/spec.md
+++ b/test/e2e/internal/protocol/sourceproto/spec.md
@@ -1,6 +1,6 @@
# Source Engine Connectionless Protocol
-**Status:** Beta (implemented, not yet CI-verified)
+**Status:** pre-v1 (implemented, not yet CI-verified)
**Module / package:** `test/e2e/internal/protocol/source`
**Dependencies:** stdlib only (Go 1.25+)
diff --git a/test/e2e/internal/satisfactory/spec.md b/test/e2e/internal/satisfactory/spec.md
index 9b2e82637..48923ae7a 100644
--- a/test/e2e/internal/satisfactory/spec.md
+++ b/test/e2e/internal/satisfactory/spec.md
@@ -20,7 +20,7 @@ GAMEPLANE_E2E_REUSE_CLUSTER=1 GAMEPLANE_E2E_CONTEXT= GAMEPLANE_E2E
A successful run is the only event that licenses updating `Last Verified` to the current date.
-**Status:** beta (v0.2.0-beta.8), in-progress (QUERY depth measured; in-game claim gate blocks authentication)
+**Status:** pre-v1 (v0.3.0), in-progress (QUERY depth measured; in-game claim gate blocks authentication)
## Purpose
diff --git a/test/e2e/internal/specs.md b/test/e2e/internal/specs.md
index a474afb8e..664269974 100644
--- a/test/e2e/internal/specs.md
+++ b/test/e2e/internal/specs.md
@@ -1,6 +1,6 @@
# e2e game-bot harness — Specification
-**Status:** beta (v0.2.0-beta.8), in-progress (fast set JOINED, heavy set not yet implemented)
+**Status:** pre-v1 (v0.3.0), in-progress (fast set JOINED, heavy set not yet implemented)
**Module / package:** `test/e2e/internal/{probe,protocol,}` — per-game protocol clients and the shared probe harness (plus `internal/fakeoidc`, an unrelated e2e fixture — see `test/e2e/api_auth_e2e_test.go`)
**Dependencies:** stdlib only (Go 1.26+) — per-game binaries build against `test/e2e/go.mod` with `GOWORK=off`, dragging zero Kubernetes or external modules into the probe image
diff --git a/test/e2e/internal/squad/spec.md b/test/e2e/internal/squad/spec.md
index 40dde3abb..04fc0c12e 100644
--- a/test/e2e/internal/squad/spec.md
+++ b/test/e2e/internal/squad/spec.md
@@ -18,7 +18,7 @@ This test is part of the `bot-heavy` bucket and does not run by default in CI. T
GAMEPLANE_E2E_REUSE_CLUSTER=1 GAMEPLANE_E2E_CONTEXT= GAMEPLANE_E2E_GAME_BOT=1 GAMEPLANE_E2E_GAMES=squad make test-e2e-keep
```
-**Status:** beta; probe depth measured: **QUERY** (A2S query response received)
+**Status:** pre-v1; probe depth measured: **QUERY** (A2S query response received)
**Module / package:** `github.com/ValgulNecron/gameplane/test/e2e/internal/squad`
**Dependencies:** `test/e2e/internal/protocol/{a2sproto,joindepth,sourceproto}`
**Heavy game:** Yes (>30GB SteamCMD download)
diff --git a/test/e2e/internal/team-fortress-2/spec.md b/test/e2e/internal/team-fortress-2/spec.md
index de1f6dd28..2664226b1 100644
--- a/test/e2e/internal/team-fortress-2/spec.md
+++ b/test/e2e/internal/team-fortress-2/spec.md
@@ -18,7 +18,7 @@ This test is part of the `bot-heavy` bucket and does not run by default in CI. T
GAMEPLANE_E2E_REUSE_CLUSTER=1 GAMEPLANE_E2E_CONTEXT= GAMEPLANE_E2E_GAME_BOT=1 GAMEPLANE_E2E_GAMES=team-fortress-2 make test-e2e-keep
```
-**Status:** beta; probe depth measured: **QUERY** (A2S query response received)
+**Status:** pre-v1; probe depth measured: **QUERY** (A2S query response received)
**Module / package:** `github.com/ValgulNecron/gameplane/test/e2e/internal/team-fortress-2`
**Dependencies:** `test/e2e/internal/protocol/{a2sproto,sourceproto,joindepth}`
**Heavy game:** Yes (>15GB disk download)
diff --git a/test/e2e/internal/terraria/spec.md b/test/e2e/internal/terraria/spec.md
index 82308c663..4aaeb7b7a 100644
--- a/test/e2e/internal/terraria/spec.md
+++ b/test/e2e/internal/terraria/spec.md
@@ -10,7 +10,7 @@
- **Blocker**: —
- **Blocker Class**: —
-**Status:** beta (v0.2.0-beta.8)
+**Status:** pre-v1 (v0.3.0)
**Module / package:** `github.com/ValgulNecron/gameplane/test/e2e/internal/terraria`
**Dependencies:** stdlib only (Go 1.25+)
diff --git a/test/e2e/internal/the-isle/spec.md b/test/e2e/internal/the-isle/spec.md
index 5d7b3f616..00a87138c 100644
--- a/test/e2e/internal/the-isle/spec.md
+++ b/test/e2e/internal/the-isle/spec.md
@@ -18,7 +18,7 @@ This test is part of the `bot-heavy` bucket and does not run by default in CI. T
GAMEPLANE_E2E_REUSE_CLUSTER=1 GAMEPLANE_E2E_CONTEXT= GAMEPLANE_E2E_GAME_BOT=1 GAMEPLANE_E2E_GAMES=the-isle make test-e2e-keep
```
-**Status:** beta; probe depth measured: **QUERY** (A2S query response received)
+**Status:** pre-v1; probe depth measured: **QUERY** (A2S query response received)
**Module / package:** `github.com/ValgulNecron/gameplane/test/e2e/internal/the-isle`
**Dependencies:** `test/e2e/internal/protocol/{a2sproto,joindepth}`
**Heavy game:** Yes (>20GB SteamCMD download)
diff --git a/test/e2e/internal/tmodloader/spec.md b/test/e2e/internal/tmodloader/spec.md
index 18b3e0b0a..63a503bc9 100644
--- a/test/e2e/internal/tmodloader/spec.md
+++ b/test/e2e/internal/tmodloader/spec.md
@@ -18,7 +18,7 @@ This test is part of the `bot-fast` bucket and can run in CI against a test clus
GAMEPLANE_E2E_REUSE_CLUSTER=1 GAMEPLANE_E2E_CONTEXT= GAMEPLANE_E2E_GAME_BOT=1 GAMEPLANE_E2E_GAMES=tmodloader make test-e2e-keep
```
-**Status:** beta; probe depth measured: **QUERY** (Terraria TCP handshake response)
+**Status:** pre-v1; probe depth measured: **QUERY** (Terraria TCP handshake response)
**Module / package:** `github.com/ValgulNecron/gameplane/test/e2e/internal/tmodloader`
**Dependencies:** `test/e2e/internal/terraria/terrariaproto`, `test/e2e/internal/protocol/joindepth`
**Heavy game:** No (<5Gi storage, fast container startup)
diff --git a/test/e2e/internal/v-rising/spec.md b/test/e2e/internal/v-rising/spec.md
index b16554211..fdd01efde 100644
--- a/test/e2e/internal/v-rising/spec.md
+++ b/test/e2e/internal/v-rising/spec.md
@@ -20,7 +20,7 @@ GAMEPLANE_E2E_REUSE_CLUSTER=1 GAMEPLANE_E2E_CONTEXT= GAMEPLANE_E2E
A successful run is the only event that licenses updating `Last Verified` to the current date.
-**Status:** beta (v0.2.0-beta.8)
+**Status:** pre-v1 (v0.3.0)
**Module / package:** `github.com/ValgulNecron/gameplane/test/e2e/internal/v-rising`
**Dependencies:** stdlib + shared protocol family `a2s` (Go 1.25+); tested against trueosiris/vrising:2026-04-23-1036 (UNMEASURED against a real server — see "Measured connectivity")
diff --git a/test/e2e/internal/valheim/spec.md b/test/e2e/internal/valheim/spec.md
index c14c5dcd2..ffbf4f1ef 100644
--- a/test/e2e/internal/valheim/spec.md
+++ b/test/e2e/internal/valheim/spec.md
@@ -20,7 +20,7 @@ GAMEPLANE_E2E_REUSE_CLUSTER=1 GAMEPLANE_E2E_CONTEXT= GAMEPLANE_E2E
A successful run is the only event that licenses updating `Last Verified` to the current date.
-**Status:** beta (heavy-set, hand-run only)
+**Status:** pre-v1 (heavy-set, hand-run only)
**Module:** `test/e2e/internal/valheim/`
**Depth:** QUERY
diff --git a/test/e2e/specs.md b/test/e2e/specs.md
index 38a38cca8..865004f2c 100644
--- a/test/e2e/specs.md
+++ b/test/e2e/specs.md
@@ -1,6 +1,6 @@
# test/e2e — Specification
-**Status:** beta (v0.2.0-beta.8)
+**Status:** pre-v1 (v0.3.0)
**Module / package:** `github.com/ValgulNecron/gameplane/test/e2e`
**Go version:** 1.26.0
diff --git a/tunnel/specs.md b/tunnel/specs.md
index 65fc9e3c3..0beb7424d 100644
--- a/tunnel/specs.md
+++ b/tunnel/specs.md
@@ -1,6 +1,6 @@
# tunnel — Specification
-**Status:** beta (v0.2.0-beta.8)
+**Status:** pre-v1 (v0.3.0)
**Module / command:** `github.com/ValgulNecron/gameplane/tunnel`
**Dependencies:** stdlib only
diff --git a/web/package-lock.json b/web/package-lock.json
index 47b1a0ee8..3803fb08a 100644
--- a/web/package-lock.json
+++ b/web/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@gameplane/web",
- "version": "0.2.0-beta.8",
+ "version": "0.3.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@gameplane/web",
- "version": "0.2.0-beta.8",
+ "version": "0.3.0",
"dependencies": {
"@heroui/react": "3.2.6",
"@heroui/styles": "3.2.6",
diff --git a/web/package.json b/web/package.json
index ce686745a..9844e4ca2 100644
--- a/web/package.json
+++ b/web/package.json
@@ -1,7 +1,7 @@
{
"name": "@gameplane/web",
"private": true,
- "version": "0.2.0-beta.8",
+ "version": "0.3.0",
"type": "module",
"scripts": {
"dev": "vite",
diff --git a/web/specs.md b/web/specs.md
index c6ddf034d..ee9589aa3 100644
--- a/web/specs.md
+++ b/web/specs.md
@@ -1,6 +1,6 @@
# web — Specification
-**Status:** beta (v0.2.0-beta.8)
+**Status:** pre-v1 (v0.3.0)
**Module / package:** @gameplane/web
**Build:** Vite 8.3 + React 19.3 + TypeScript 6.0 (strict)
@@ -748,7 +748,7 @@ tsconfig.json # TS strict, noUnusedLocals, noUnusedParameters, noF
vitest.config.ts # Coverage gates (lines 92 / functions 76 / branches 82 / statements 92)
playwright.config.ts # Mock + live test modes, serial execution (login state is shared)
eslint.config.js # Flat config: @typescript-eslint (strict), react-hooks, no-floating-promises
-package.json # @gameplane/web v0.2.0-beta.8; dev: vite, npm scripts for build/test/lint
+package.json # @gameplane/web v0.3.0; dev: vite, npm scripts for build/test/lint
```
## Routing & Pages