From b62a5fdd366b4b63b06db0837a80c555000dd2fc Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 22:51:14 +0000 Subject: [PATCH 1/4] docs(specs): 018 audit report, v0.3.0 release notes draft, cold-read check T066 audit/report.md (counts re-derived from inventory/findings/coverage), T067 status-wording change set copied in, T068 release-notes draft, T069 cold read (no-go: 1 of 8 release criteria met). Decision left for the maintainer (T070). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01UshpSigdLccuYZi7oFJX9y Signed-off-by: Claude --- .../audit/evidence/cold-read.md | 26 ++ .../audit/evidence/release-notes-v0.3.0.md | 126 +++++++ .../audit/report.md | 314 ++++++++++++++++++ 3 files changed, 466 insertions(+) create mode 100644 specs/018-v0-3-release-readiness/audit/evidence/cold-read.md create mode 100644 specs/018-v0-3-release-readiness/audit/evidence/release-notes-v0.3.0.md diff --git a/specs/018-v0-3-release-readiness/audit/evidence/cold-read.md b/specs/018-v0-3-release-readiness/audit/evidence/cold-read.md new file mode 100644 index 000000000..c392b5473 --- /dev/null +++ b/specs/018-v0-3-release-readiness/audit/evidence/cold-read.md @@ -0,0 +1,26 @@ +# Cold-read check (T069) + +Date: 2026-10-05 +Model tier: sonnet + +## (1) Go or no-go + +**No-go.** v0.3.0 should not be released now. + +## (2) Reasons + +- **Release criteria (Release criteria table):** only 1 of 8 is Met (RC-02, component coverage). RC-07 is Partially met. The other 6 are Not met. +- **Open findings (Totals, Open findings):** 291 of 293 findings are in a blocking status: 25 `imported`, 37 `open`, 229 `fixed-unverified`. None is `verified`. This fails RC-03. The open set includes S1 and S2 items, for example F-115 (S1: new file truncates existing file), F-118 and F-119 (S2: tunnel create and enable flows fail), and F-014, F-015 and F-018 (S1 security items, still `imported`). +- **Inventory (Totals, Not live-verified):** 467 of 486 rows are `untested` and 0 are `pass`. 19 rows are `blocked`. The formal live round did not run (OD-029). This fails RC-01. +- **Security boundaries (RC-04):** all 16 `INV-SEC-*` rows are `untested`, so no violation attempt is recorded for any FR-008 boundary. +- **Upgrade (RC-05, Rounds):** the beta.8 to RC upgrade round and the node round have not run. Zero data loss is unproven. +- **Cleanup (RC-06):** no post-cleanup snapshot comparison exists, and the `audit018-admin` account is still pending removal. +- **Tag and CI (RC-08, header, Rounds):** `v0.3.0-rc.2` is not tagged or pushed (RC-TAG-2 is PENDING). `v0.3.0-rc.1` was never installable because its release run was cancelled. No tagged commit has a green CI run. +- **Re-verification (Rounds):** T058, which re-verifies the 229 `fixed-unverified` findings, has not run. +- **Decision section:** the maintainer's decision is still pending. The report itself says it is "not a go case". + +What would change this: a tagged and installable RC with green CI, the re-verification, upgrade and security rounds run, and the blocking findings closed or triaged. + +## (3) Time taken + +About 6 minutes. This is an estimate: roughly 4 to 5 minutes reading, most of it skimming the long tables and the status-wording change set, and 1 to 2 minutes deciding. The no-go was clear from the header and the criteria table. diff --git a/specs/018-v0-3-release-readiness/audit/evidence/release-notes-v0.3.0.md b/specs/018-v0-3-release-readiness/audit/evidence/release-notes-v0.3.0.md new file mode 100644 index 000000000..e1a0b2041 --- /dev/null +++ b/specs/018-v0-3-release-readiness/audit/evidence/release-notes-v0.3.0.md @@ -0,0 +1,126 @@ +# Gameplane v0.3.0 release notes (draft) + +Draft for the maintainer (T068). Not published and not final: v0.3.0 has no go decision yet (see [../report.md](../report.md)). The highlights are copied from the Highlights of the `0.3.0-rc.1` and `0.3.0-rc.2` sections of `CHANGELOG.md`; the "Not live-verified" section is copied word for word from the report (FR-002, SC-001); the pre-v1 caveats are copied from `docs/roadmap.md`, "Wanted for v1, not blocking". Two highlights pointed at other `CHANGELOG.md` sections ("above"); they now name `CHANGELOG.md`. The rc.2 section of the changelog is marked Unreleased and `v0.3.0-rc.2` has not been tagged (RC-TAG-2 is PENDING). The release notes must be re-checked against the report when the audit finishes. + +## Highlights + +### Since v0.3.0-rc.1 (from the 0.3.0-rc.2 changelog section) + +- **Agent Prometheus metrics move to a dedicated listener (port 9090):** the + agent now serves `/metrics` on its own unauthenticated `:9090` listener + instead of the mTLS control port, where every agent scrape target was + reported "down"; the chart's `PodMonitor` scrapes it by name (#476). +- **Owner-only server operations now need the owner or an admin:** see + Upgrade Notes in `CHANGELOG.md`. +- **Helm chart fixes:** `helm upgrade` works for releases not named + `gameplane` and with `--reuse-values` from v0.2.0-beta.8, a reinstall over + leftover CRDs updates them (#443), and `helm uninstall` keeps the games + Namespace and the GameServers in it (#425). +- **Playit tunnels:** the tunnel NetworkPolicy now lets playit reach its + relay (#488), and the playit-assigned address shows up in the + GameServer's status (#447). +- **API fixes:** validation errors return 400/409 instead of 500 (#477), a + required console-action parameter sent empty is rejected instead of taking + its default (#491), and large file, log and capture transfers are no longer + cut off by the 60 s timeout and 1 MiB body cap (#444). +- **Backup, restore and wipe:** a failed data wipe is reported instead of + acknowledged (#436), and backup/restore quiesce-lifecycle fixes stop a + server being left quiesced; a restore now also removes files created + after the snapshot (#454). +- **Uploads and backups:** dashboard file and mod uploads over 1 MiB are no + longer rejected (#426), and backup and restore Jobs can reach their + repository when NetworkPolicies are enabled (#432). +- Further security hardening across the API, operator, agent and release + pipeline (see Security hardening in `CHANGELOG.md`). + +### In v0.3.0-rc.1 (from the 0.3.0-rc.1 changelog section) + +- **Every existing GameServer pod restarts once on upgrade** due to the network + capture feature adding an emptyDir volume; plan your upgrade window accordingly. +- **User theme customization:** presets (Modern Pink, Legacy Orange) + custom + accent/surface colors with WCAG AA contrast guarantee, custom CSS overlay, and + safe-mode suspension on demand. Accessed via Settings → Theme & Appearance. +- **13 new top-steam-game modules** (FiveM, Farming Simulator 25, Euro Truck + Simulator 2, Mount & Blade Bannerlord, tModLoader, Team Fortress 2, BeamMP, + Left 4 Dead 2, The Isle, ARK, Arma Reforger, Hell Let Loose, Squad) with + Gameplane-owned container images (`fivem`, `farming-simulator-25`, + `euro-truck-simulator-2`, `beammp`). +- **Network capture for protocol reverse-engineering:** admin-only, on-demand + packet capture from running game pods as ephemeral sidecar containers, + downloaded as PCAPNG files (Wireshark-compatible). +- **Easy module building toolkit:** `gp-module` CLI (`init`, `validate`, `preview`, + `package`) for scaffolding, authoring, and publishing custom game modules; + web dashboard UI with live validation and cluster installation. +- **Install-time configuration:** Helm-seeded OIDC role mappings (no + `bootstrap-admin` needed for OIDC-only installs) and default StorageClass for + game-data PVCs. +- **Share link expiry options:** no-expiry, 15/30/60/90-day presets, or custom + date; lifts the old 90-day cap that outlived long-running survival servers. +- **Console fixes:** non-default port handling (port-forward scenarios) and + guarded `send()` before socket open. +- **Existing PVC support:** Helm `api.storage.existingClaim` lets installs + point SQLite to a pre-existing PersistentVolumeClaim. + +## Not live-verified + +Rows are not live-verified if they are `blocked` (listed below, with the prerequisite and the alternative tested) or still `untested` (counted after the table). Counts come from `awk` over the Outcome column of `audit/inventory.md` (see Totals). + +### Blocked rows (19) + +| ID | Capability | Prerequisite and alternative | +|---|---|---| +| INV-CRD-029 | Cluster register and health check | OD-021 item 19: blocked, no second live cluster available to the audit; anchor renamed to match. Verified live instead: an unregistered `?cluster=` selector gets HTTP 400 `cluster not permitted` from the RBAC allow-list (`scope.ResolveCluster`) before dispatch. The `rejectRemoteCluster` guard (`resources.go:104-110`) itself only fires for a *registered* remote cluster, which the audit lacks; it returns 501 with body `httperr.RemoteClusterNotImplemented` (`resources.go:106`, `httperr.go:33-34`), per OD-021 item 19 (#430) — see procedures/crd.md step 4 | +| INV-CRD-030 | Cluster health check failure (Unhealthy) | OD-021 item 19: blocked, cascades from INV-CRD-029 (no second live cluster to register first) | +| INV-AUX-009 | Supervise frp (forward proxy) relay client | blocked candidate: needs external frp server; alternative: test operator tunnel injection via envtest (api-agent bucket) | +| INV-AUX-010 | Supervise Tailscale relay client | blocked candidate: needs Tailscale account and auth key; alternative: test operator injection | +| INV-AUX-011 | Supervise playit relay client | blocked candidate: needs playit.gg account and secret key; alternative: test operator injection | +| INV-AUX-012 | Accept HTTP audit events and relay to syslog collector | blocked candidate: needs external RFC 5424 syslog receiver; alternative: test with local netcat listener (api-auth bucket) | +| INV-AUX-013 | Format and send RFC 5424 syslog records | blocked candidate: needs external syslog collector | +| INV-MOD-033 | Create and start DayZ server from template | blocked candidate: needs node memory ≥6Gi per pod; no lighter alternative available in rcon/battleye category (DayZ is the only module) | +| INV-MOD-034 | Join DayZ server via A2S query | blocked candidate: needs node memory ≥6Gi per pod; no lighter alternative available in rcon/battleye category (DayZ is the only module) | +| INV-MOD-035 | DayZ server BattlEye RCON console | blocked candidate: needs node memory ≥6Gi per pod; no lighter alternative available in rcon/battleye category (DayZ is the only module) | +| INV-MOD-036 | Backup and restore DayZ server | blocked candidate: needs node memory ≥6Gi per pod; no lighter alternative available in rcon/battleye category (DayZ is the only module) | +| INV-MOD-049 | Create and start Satisfactory server from template | blocked candidate: needs node memory ≥6Gi per pod; alternative: FiveM (rcon/rest + HTTP REST probe, 4Gi) | +| INV-MOD-050 | Join Satisfactory server via HTTP REST | blocked candidate: needs node memory ≥6Gi per pod; alternative: FiveM (rcon/rest + HTTP REST probe, 4Gi) | +| INV-MOD-051 | Satisfactory server satisfactory RCON console | blocked candidate: needs node memory ≥6Gi per pod; alternative: FiveM (rcon/rest + HTTP REST probe, 4Gi) | +| INV-MOD-052 | Backup and restore Satisfactory server | blocked candidate: needs node memory ≥6Gi per pod; alternative: FiveM (rcon/rest + HTTP REST probe, 4Gi) | +| INV-MOD-053 | Create and start Ark Survival Ascended server from template | blocked candidate: needs node memory ≥10Gi per pod; alternative: CS2 (rcon/source + Steam A2S probe, 2Gi) | +| INV-MOD-054 | Join Ark Survival Ascended server via TCP RCON probe | blocked candidate: needs node memory ≥10Gi per pod; alternative: CS2 (rcon/source + Steam A2S probe, 2Gi) | +| INV-MOD-055 | Ark Survival Ascended server Source RCON console | blocked candidate: needs node memory ≥10Gi per pod; alternative: CS2 (rcon/source + Steam A2S probe, 2Gi) | +| INV-MOD-056 | Backup and restore Ark Survival Ascended server | blocked candidate: needs node memory ≥10Gi per pod; alternative: CS2 (rcon/source + Steam A2S probe, 2Gi) | + +### Untested rows + +- **467 of 486 inventory rows in `audit/inventory.md` are still `untested`** (WEB 145, API 146, CRD 35, AGT 36, AUX 13, HELM 28, MOD 56, UPG 5, NODE 3). The formal per-row live round did not run (OD-029): the 2026-10-04 informal live sweep on `master` stands in for it, and it did not record per-row outcomes, so no row is marked `pass`. +- The 16 security-control rows (`INV-SEC-001` to `INV-SEC-016`) are kept in `audit/held/inventory-SEC.md`, not in `audit/inventory.md` (OD-019; that file has been in git since 8249db80) and are all `untested` there, so no active violation attempt is recorded for them. +- No upgrade or node round has run (T061, T062, T065): the beta.8 to RC upgrade (`UPG`, 5 rows) and the node behaviour rows (`NODE`, 3 rows) are `untested`. +- 229 findings are `fixed-unverified`: their fixes merged but have not been re-verified on a release candidate (T058 has not run). + +## Pre-v1 caveats + +This is a pre-v1 release. These items are wanted for v1 and are not blocking v0.3.0: + +#### Production-readiness hardening (planned) + +- A documented backup/restore **drill** — a runbook an operator can follow. + The *coverage* half of this item is already done and was stale here: + `TestRestore_RoundTrip` (`test/e2e/restore_e2e_test.go`) writes a marker into + a server's PVC, backs it up, wipes it, restores, and asserts the bytes came + back — against the real in-cluster restic-server that `ensureResticRepo` + provisions. What is missing is the human-facing runbook, not the test. +- Resource-limit guidance sized from real workloads rather than defaults. + +#### Postgres driver: production readiness (experimental) + +SQLite is the only production-tested driver. The Postgres driver (build tag +`-tags postgres`) now works end to end (#518): migrations 001–012 have +hand-written Postgres equivalents (`api/internal/db/migrations/postgres/`), +every later migration is one portable file both drivers run +(`migrations/common/`), the Postgres connection rewrites `?` placeholders to +`$n`, and runtime timestamps are generated in Go. The `api (postgres)` CI job +builds the api with the tag and runs `api/internal/db`'s tests against a real +PostgreSQL server. It stays **experimental** until the rest lands: running the +handler/auth/audit test suites and the kind e2e and upgrade suites against +Postgres, a published image built with `-tags postgres`, and multi-replica +safety (the user-management lock and the audit hash chain assume a single API +process). diff --git a/specs/018-v0-3-release-readiness/audit/report.md b/specs/018-v0-3-release-readiness/audit/report.md index 3c2807eff..4457dafdc 100644 --- a/specs/018-v0-3-release-readiness/audit/report.md +++ b/specs/018-v0-3-release-readiness/audit/report.md @@ -2,20 +2,334 @@ Built from the audit records at the end of the audit (T066). Readable cold in under 15 minutes (SC-008). +**State of this report (2026-10-05, master `c79715a6`): the audit is not finished.** It is a snapshot of what the records say, not a go case. 1 of 8 release criteria is Met. The formal live round did not run (OD-029), the upgrade and node rounds have not run, and no finding is `verified` (T058 has not run). `v0.3.0-rc.2` **has not been tagged or pushed**: RC-TAG-2 in [OPEN-DECISIONS.md](../OPEN-DECISIONS.md#rc-tag-2-publish-v030-rc2--pending) still reads PENDING, and its tag target is the #496 merge commit `6750ba87`: `gh api repos/ValgulNecron/Gameplane/git/refs/tags/v0.3.0-rc.2` returns 404 on 2026-10-05, and only `v0.3.0-rc.1` exists (never installable, see [rounds.md](rounds.md#rc1)). + ## Decision +Not decided. This section is the maintainer's (T070): name, date and go/no-go go here. + +- Go/no-go: _pending_ +- Maintainer: _pending_ +- Date: _pending_ + ## Release criteria +Evidence as of 2026-10-05. `Met` here is filled only from the records; the maintainer's decision (T070) will set the `Met` column in `audit/release-criteria.md`, which stays `pending` until then. + +| ID | Criterion | Source | Met | Reason | +|---|---|---|---|---| +| RC-01 | Every inventory row has an outcome, zero rows `fail`, and every `blocked` row names its prerequisite and is listed as not live-verified | SC-001 | **Not met** | 467 of 486 rows are `untested` and no row is `pass`; no row is `fail`. 19 rows are `blocked`, each names its prerequisite, and they are listed under Not live-verified. The criterion needs an outcome on every row. | +| RC-02 | Every component has a `complete` review record | SC-002 | **Met** | `audit/coverage.md` has 27 component rows, all `complete`. The 15 `go.work` entries, `web/`, `charts/gameplane/`, `deploy/`, `hack/`, `.github/workflows/`, `.github/actions/`, `images/`, `docs/`, root docs, `design-export/`, `modules/` and `website/` are all there. The records say a review happened; findings from them are counted under RC-03. | +| RC-03 | Zero findings in `imported`, `open`, `fixing` or `fixed-unverified` | SC-003, SC-004 | **Not met** | 291 findings are in a blocking status: 25 `imported`, 37 `open`, 0 `fixing`, 229 `fixed-unverified`. None is `verified`. | +| RC-04 | Each FR-008 boundary has at least one active violation attempt recorded | SC-007 | **Not met** | The 16 `INV-SEC-*` rows (in `audit/held/inventory-SEC.md`, OD-019) are all `untested`, so no violation attempt is recorded for any FR-008 boundary. | +| RC-05 | Live beta.8 → RC upgrade with zero data loss and zero lost accounts | SC-005, OD-005 | **Not met** | The upgrade round has not run (T061, T065). The 5 `UPG` rows are `untested`. CI `e2e-upgrade` from beta.8 exists but is not the live upgrade this criterion asks for. | +| RC-06 | The baseline snapshot matches the post-cleanup snapshot, with zero `audit018-` resources remaining | SC-006 | **Not met** | No post-cleanup snapshot comparison is recorded. The `audit018-admin` test account is still `pending` removal in [rounds.md](rounds.md), the live sweep's test resources are `not recorded`, and T034 (cleanup) is open. | +| RC-07 | Every `not-a-defect` and `out-of-scope` closure is justified, and each out-of-scope one cites a roadmap line | SC-009 | **Partially** | Both closures that exist are accounted for: F-276 (`not-a-defect`) carries a Justification citing `web/src/lib/servers.ts:15-16`, and F-181 (`closed-already-fixed`) cites #467. No finding is `out-of-scope`, so no roadmap line is needed yet. Not complete: the open findings have not been triaged, so more closures are expected. | +| RC-08 | CI is green on the tagged commit | FR-017 | **Not met** | No `v0.3.0` tag exists. `v0.3.0-rc.2` is not tagged (RC-TAG-2 is PENDING), so there is no tagged commit with a green CI run. `v0.3.0-rc.1` was tagged but its release run was cancelled. | + ## Totals +How each number was produced: findings from the `| F-NNN |` rows of `audit/findings.md` (awk, split on `|`, Severity and Status columns); inventory from the `| INV-` rows of `audit/inventory.md` and `audit/held/inventory-SEC.md` (awk, Outcome column); coverage from `audit/coverage.md`. The T059 loop command `grep -cE '\| (imported|open|fixing|fixed-unverified) \|' audit/findings.md` returns **291**. + +### Findings: 293 total (F-001 to F-293, no gaps) + +| Severity | imported | open | fixing | fixed-unverified | verified | closed-already-fixed | not-a-defect | out-of-scope | Total | +|---|---|---|---|---|---|---|---|---|---| +| S1 | 6 | 1 | 0 | 5 | 0 | 0 | 0 | 0 | 12 | +| S2 | 1 | 2 | 0 | 10 | 0 | 0 | 0 | 0 | 13 | +| S3 | 13 | 15 | 0 | 91 | 0 | 0 | 0 | 0 | 119 | +| S4 | 5 | 19 | 0 | 123 | 0 | 1 | 1 | 0 | 149 | +| Total | 25 | 37 | 0 | 229 | 0 | 1 | 1 | 0 | 293 | + +### Inventory: 486 rows in `inventory.md` plus 16 `INV-SEC-*` rows in `held/inventory-SEC.md` = 502 + +| Outcome | `inventory.md` (486) | With `INV-SEC-*` (502) | +|---|---|---| +| pass | 0 | 0 | +| fail | 0 | 0 | +| blocked | 19 | 19 | +| n/a | 0 | 0 | +| untested | 467 | 483 | + +No row is `pass`. The formal per-row round did not run (OD-029), so most rows stay `untested`; they are reported as such. + +### Coverage + +27 of 27 required component rows in `audit/coverage.md` are `complete` (100%): 15 `go.work` modules, plus `web/`, `charts/gameplane/`, `deploy/`, `hack/`, `.github/workflows/`, `.github/actions/`, `images/`, `docs/`, root docs, `design-export/`, `modules/`, `website/` (OD-022 added the actions and images rows). Complete means reviewed, not that its findings are fixed. + +### Rounds + +| Round | State | +|---|---| +| rc.0 | pre-RC review and inventory enumeration; 0 rows run | +| rc.1 | `v0.3.0-rc.1` tagged 2026-09-24, release run cancelled (F-257), never installable; 0 rows run | +| live-sweep 2026-10-04 | informal sweep of `master` on kubelab; F-273 to F-293; per-row outcomes not recorded (OD-029) | +| rc.2 | RC-TAG-2 PENDING; tag target `6750ba87` (#496 merge commit), **not tagged or pushed** | +| upgrade, node (T061, T062, T065) | not run | +| re-verification of fixed-unverified findings (T058) | not run | + ## Open findings +Must be empty for a go. It is not: 291 findings are in a blocking status. + +- **229 `fixed-unverified`** (fix merged, not re-verified on an RC): S1 5, S2 10, S3 91, S4 123. Listed in [findings.md](findings.md); re-verification (T058) has not run. +- **25 `imported`** and **37 `open`** are listed below (62 rows). Several `imported` rows say their fix is merged or that they are believed not-a-defect; none has been re-checked and closed. + +| ID | Severity | Status | Component | Title | +|---|---|---|---|---| +| F-001 | S3 | imported | web/ | Dependency bump (#406) broke upload-dialog unit tests and keyboard-focus e2e | +| F-002 | S4 | imported | web/ | Visual-diff residuals after feature 014 conformance (7 screens) | +| F-003 | S4 | imported | web/ | Design exports mismatched shipped UI: DMnEi mislabel, J5pjJ3 composite frame, oversized chips/badges | +| F-004 | S3 | imported | web/ | e2e `page.route()` overrides silently no-op under mock-target MSW service worker | +| F-005 | S3 | imported | web/ | Live share-links e2e failure traced to missing `/shares` rule in Vite dev proxy | +| F-006 | S1 | imported | .github/ | CI `dump-cluster-state` redaction misses quoted/JSON-embedded secret values | +| F-007 | S2 | imported | web/ | Console WebSocket rejected (403) on non-default ports; `send()` before open threw | +| F-008 | S3 | imported | web/ | Module catalog tag filters unioned instead of intersected | +| F-009 | S4 | imported | web/ | Vertical tab list rendered as an oval | +| F-010 | S3 | imported | web/ | Console terminal grew without bound | +| F-011 | S3 | imported | web/ | Preset share links didn't expire at end of day like custom dates | +| F-012 | S1 | imported | api/, operator/, charts/gameplane/, images/ | Security-audit hardening: RBAC, share/tunnel credential handling, GameServer reconciler validation (bundled fix) | +| F-013 | S1 | imported | .github/ | CI `dump-cluster-state`: redact quoted/JSON-embedded secret values (fix for F-006) | +| F-014 | S1 | imported | api/ | Share links not scoped to their originating cluster in multi-cluster installs | +| F-015 | S1 | imported | api/, operator/ | GameServer env-var Secret/ConfigMap references not restricted to server-owned objects | +| F-016 | S3 | imported | charts/gameplane/ | Audit syslog bridge had no ingress NetworkPolicy restricting senders to the API | +| F-017 | S3 | imported | images/ | steamcmd base image referenced by a mutable `:latest` tag instead of a pinned digest | +| F-018 | S1 | imported | api/, operator/ | Tunnel credential Secret delete/update/mount lacked ownership checks | +| F-019 | S3 | imported | charts/gameplane/ | Telemetry receiver had no ingress NetworkPolicy restricting senders to the API | +| F-020 | S4 | imported | modules/, docs/ | Nuclear Option's assumed UDP 7777 game-join port is not bound on the live server | +| F-021 | S4 | imported | docs/ | Helm-seeded OIDC role mappings documented while the feature sits under CHANGELOG Unreleased | +| F-022 | S3 | imported | operator/, agent/, web/ | `cli` rcon.protocol semantics: confirm the implementation matches the recorded Option A ruling | +| F-023 | S3 | imported | modules/ | Open question: Factorio template's `rcon.protocol: source` vs. an earlier contract claim of `none` | +| F-024 | S3 | imported | modules/ | Open question: Project Zomboid template's `rcon.protocol: source` vs. an earlier contract claim of `none` | +| F-025 | S3 | imported | agent/ | Open question: generic `rest` rcon wire contract (FiveM txAdmin / Farming Simulator 25) not yet given a final ruling | +| F-027 | S3 | open | docs/ | `docs/install.md` has no rollback procedure | +| F-028 | S3 | open | charts/gameplane/ | `charts/gameplane/values.yaml` git module source still pinned to `ref: v0.2.0-beta.6` | +| F-037 | S4 | open | website/ | website games page lists 16 games but 30 now shipped | +| F-038 | S4 | open | website/ | website comparison.mdx says "16 official modules" but 30 now shipped | +| F-039 | S4 | open | website/ | website VERSION constant still beta.7; beta.8 published 2026-08-22 | +| F-115 | S1 | open | web | New file truncates existing file | +| F-117 | S3 | open | web | Settings save merges entire spec, losing concurrent changes | +| F-118 | S2 | open | web | Tunnel create blocked by missing Secret | +| F-119 | S2 | open | web | Tunnel enable flows fail validation | +| F-120 | S3 | open | web | Share links resolve hangs on extended wake | +| F-122 | S3 | open | web | Settings dirty state persists on tab switch | +| F-123 | S3 | open | web | Revoked share links show as active | +| F-124 | S3 | open | web | Node selector never applied to running server | +| F-127 | S3 | open | web | Default namespace not used on server create | +| F-128 | S4 | open | web | Modules hash navigation fails | +| F-129 | S4 | open | web | Add cluster links to unusable page | +| F-131 | S4 | open | web | Invalid sections don't block save | +| F-132 | S4 | open | web | Reset text editor preserves old content | +| F-133 | S4 | open | web | Invite dialog retains previous entry | +| F-134 | S4 | open | web | Identity provider tab contradicts code | +| F-139 | S4 | open | web | specs.md contradicts implemented features | +| F-140 | S4 | open | web | specs.md lists unimplemented UI | +| F-219 | S3 | open | charts/gameplane/ | Default module catalog omits 14 spec-015 modules | +| F-222 | S4 | open | charts/gameplane/ | Module source git.ref doc says main, but values pins v0.2.0-beta.6 | +| F-260 | S4 | open | operator | GameServer.Stopped and Restore.Resuming phases declared but never assigned | +| F-264 | S3 | open | .github/actions/ | Dependabot never bumps the action pins inside `.github/actions/`, and they already trail the workflows | +| F-265 | S4 | open | .github/actions/ | docker-bake.hcl header names `e2e-images` as its caller; bake runs in `build-e2e-images` | +| F-266 | S3 | open | images/ | steam-install.sh reports a failed update as success once the game is installed, and never retries it | +| F-267 | S3 | open | images/ | images/README.md Dockerfile template runs `chmod` as the non-root user and fails to build | +| F-268 | S4 | open | images/ | Documented local `docker run -v game-data:/data` gives a root-owned volume the game user can't write | +| F-269 | S4 | open | images/ | images/README.md promises exponential backoff; steam-install.sh uses a fixed delay | +| F-270 | S4 | open | images/ | images/README.md trigger list omits `pull_request`, and its manual `docker build -f Dockerfile` commands fail from the repo root | +| F-289 | S3 | open | modules/ | Terraria and tModLoader servers lack a TCP readiness probe | +| F-290 | S4 | open | web | Public share page: "starting up" vs "waking up" copy (item 21c) | +| F-291 | S4 | open | web | AdminSettings `instanceName` hint text | +| F-292 | S3 | open | web | Files tab: folder selection and delete (item 18c) | +| F-293 | S3 | open | web | Console history (item 21h) | + ## Not live-verified +Rows are not live-verified if they are `blocked` (listed below, with the prerequisite and the alternative tested) or still `untested` (counted after the table). Counts come from `awk` over the Outcome column of `audit/inventory.md` (see Totals). + +### Blocked rows (19) + +| ID | Capability | Prerequisite and alternative | +|---|---|---| +| INV-CRD-029 | Cluster register and health check | OD-021 item 19: blocked, no second live cluster available to the audit; anchor renamed to match. Verified live instead: an unregistered `?cluster=` selector gets HTTP 400 `cluster not permitted` from the RBAC allow-list (`scope.ResolveCluster`) before dispatch. The `rejectRemoteCluster` guard (`resources.go:104-110`) itself only fires for a *registered* remote cluster, which the audit lacks; it returns 501 with body `httperr.RemoteClusterNotImplemented` (`resources.go:106`, `httperr.go:33-34`), per OD-021 item 19 (#430) — see procedures/crd.md step 4 | +| INV-CRD-030 | Cluster health check failure (Unhealthy) | OD-021 item 19: blocked, cascades from INV-CRD-029 (no second live cluster to register first) | +| INV-AUX-009 | Supervise frp (forward proxy) relay client | blocked candidate: needs external frp server; alternative: test operator tunnel injection via envtest (api-agent bucket) | +| INV-AUX-010 | Supervise Tailscale relay client | blocked candidate: needs Tailscale account and auth key; alternative: test operator injection | +| INV-AUX-011 | Supervise playit relay client | blocked candidate: needs playit.gg account and secret key; alternative: test operator injection | +| INV-AUX-012 | Accept HTTP audit events and relay to syslog collector | blocked candidate: needs external RFC 5424 syslog receiver; alternative: test with local netcat listener (api-auth bucket) | +| INV-AUX-013 | Format and send RFC 5424 syslog records | blocked candidate: needs external syslog collector | +| INV-MOD-033 | Create and start DayZ server from template | blocked candidate: needs node memory ≥6Gi per pod; no lighter alternative available in rcon/battleye category (DayZ is the only module) | +| INV-MOD-034 | Join DayZ server via A2S query | blocked candidate: needs node memory ≥6Gi per pod; no lighter alternative available in rcon/battleye category (DayZ is the only module) | +| INV-MOD-035 | DayZ server BattlEye RCON console | blocked candidate: needs node memory ≥6Gi per pod; no lighter alternative available in rcon/battleye category (DayZ is the only module) | +| INV-MOD-036 | Backup and restore DayZ server | blocked candidate: needs node memory ≥6Gi per pod; no lighter alternative available in rcon/battleye category (DayZ is the only module) | +| INV-MOD-049 | Create and start Satisfactory server from template | blocked candidate: needs node memory ≥6Gi per pod; alternative: FiveM (rcon/rest + HTTP REST probe, 4Gi) | +| INV-MOD-050 | Join Satisfactory server via HTTP REST | blocked candidate: needs node memory ≥6Gi per pod; alternative: FiveM (rcon/rest + HTTP REST probe, 4Gi) | +| INV-MOD-051 | Satisfactory server satisfactory RCON console | blocked candidate: needs node memory ≥6Gi per pod; alternative: FiveM (rcon/rest + HTTP REST probe, 4Gi) | +| INV-MOD-052 | Backup and restore Satisfactory server | blocked candidate: needs node memory ≥6Gi per pod; alternative: FiveM (rcon/rest + HTTP REST probe, 4Gi) | +| INV-MOD-053 | Create and start Ark Survival Ascended server from template | blocked candidate: needs node memory ≥10Gi per pod; alternative: CS2 (rcon/source + Steam A2S probe, 2Gi) | +| INV-MOD-054 | Join Ark Survival Ascended server via TCP RCON probe | blocked candidate: needs node memory ≥10Gi per pod; alternative: CS2 (rcon/source + Steam A2S probe, 2Gi) | +| INV-MOD-055 | Ark Survival Ascended server Source RCON console | blocked candidate: needs node memory ≥10Gi per pod; alternative: CS2 (rcon/source + Steam A2S probe, 2Gi) | +| INV-MOD-056 | Backup and restore Ark Survival Ascended server | blocked candidate: needs node memory ≥10Gi per pod; alternative: CS2 (rcon/source + Steam A2S probe, 2Gi) | + +### Untested rows + +- **467 of 486 inventory rows in `audit/inventory.md` are still `untested`** (WEB 145, API 146, CRD 35, AGT 36, AUX 13, HELM 28, MOD 56, UPG 5, NODE 3). The formal per-row live round did not run (OD-029): the 2026-10-04 informal live sweep on `master` stands in for it, and it did not record per-row outcomes, so no row is marked `pass`. +- The 16 security-control rows (`INV-SEC-001` to `INV-SEC-016`) are kept in `audit/held/inventory-SEC.md`, not in `audit/inventory.md` (OD-019; that file has been in git since 8249db80) and are all `untested` there, so no active violation attempt is recorded for them. +- No upgrade or node round has run (T061, T062, T065): the beta.8 to RC upgrade (`UPG`, 5 rows) and the node behaviour rows (`NODE`, 3 rows) are `untested`. +- 229 findings are `fixed-unverified`: their fixes merged but have not been re-verified on a release candidate (T058 has not run). + ## By component +Counts are from the Component column of `audit/findings.md`; a finding naming several components counts under each. Review record, method, tier and date are from `audit/coverage.md`. + +| Component | Review record | Method | Reviewer tier | Review date | imported | open | fixed-unverified | closed / not-a-defect | +|---|---|---|---|---|---|---|---|---| +| agent/ | complete | code-review | opus → opus (independent, OD-020) | 2026-09-24 | 2 | 0 | 15 | 0 | +| api/ | complete | code-review | opus → opus (independent, OD-020) | 2026-09-24 | 4 | 0 | 40 | 0 | +| audit-syslog-bridge/ | complete | code-review | opus → opus (independent, OD-020) | 2026-09-24 | 0 | 0 | 6 | 0 | +| capture-sidecar/ | complete | code-review | opus → opus (independent, OD-020) | 2026-09-24 | 0 | 0 | 8 | 0 | +| gameaction/ | complete | code-review | opus → opus (independent, OD-020) | 2026-09-24 | 0 | 0 | 4 | 0 | +| gameproto/ | complete | code-review | opus → opus (independent, OD-020) | 2026-09-24 | 0 | 0 | 6 | 0 | +| gp-module/ | complete | code-review | opus → opus (independent, OD-020) | 2026-09-24 | 0 | 0 | 11 | 0 | +| mcp-server/ | complete | code-review | opus → opus (independent, OD-020) | 2026-09-24 | 0 | 0 | 8 | 0 | +| netguard/ | complete | code-review | opus → opus (independent, OD-020) | 2026-09-24 | 0 | 0 | 3 | 0 | +| operator/ | complete | code-review | opus → opus (independent, OD-020) | 2026-09-24 | 4 | 1 | 37 | 0 | +| sentinel/ | complete | code-review | opus → opus (independent, OD-020) | 2026-09-24 | 0 | 0 | 8 | 1 | +| svcutil/ | complete | code-review | opus → opus (independent, OD-020) | 2026-09-24 | 0 | 0 | 2 | 0 | +| telemetry-receiver/ | complete | code-review | opus → opus (independent, OD-020) | 2026-09-24 | 0 | 0 | 4 | 0 | +| test/e2e/ | complete | code-review | sonnet → opus | 2026-09-23 | 0 | 0 | 3 | 0 | +| tunnel/ | complete | code-review | opus → opus (independent, OD-020) | 2026-09-24 | 0 | 0 | 7 | 0 | +| web/ | complete | code-review | opus → opus (independent, OD-020) | 2026-09-24 | 11 | 21 | 24 | 1 | +| charts/gameplane/ | complete | code-review | opus → opus (independent, OD-020) | 2026-09-24 | 3 | 3 | 20 | 0 | +| deploy/ | complete | code-review | opus → opus (independent, OD-020) | 2026-09-24 | 0 | 0 | 6 | 0 | +| hack/ | complete | code-review | opus → opus (independent, OD-020) | 2026-09-24 | 0 | 0 | 3 | 0 | +| .github/workflows/ | complete | code-review | opus → opus (independent, OD-020) | 2026-09-24 | 0 | 0 | 11 | 0 | +| .github/actions/ | complete | code-review | sonnet → opus | 2026-10-04 | 0 | 2 | 0 | 0 | +| images/ | complete | code-review | sonnet → opus | 2026-10-04 | 2 | 5 | 0 | 0 | +| docs/ | complete | code-review | sonnet → opus | 2026-09-23 | 2 | 1 | 7 | 0 | +| root docs | complete | code-review | sonnet → opus | 2026-09-23 | 0 | 0 | 3 | 0 | +| design-export/ | complete | code-review | sonnet → opus | 2026-09-23 | 0 | 0 | 0 | 0 | +| modules/ | complete | consistency-only | sonnet → opus | 2026-09-23 | 3 | 1 | 0 | 0 | +| website/ | complete | consistency-only | sonnet → opus | 2026-09-23 | 0 | 3 | 0 | 0 | + +Findings on components without their own coverage row (not shown above): `.github/` (2 `imported`: F-006, F-013; 2 `fixed-unverified`). + ## By area +Inventory outcomes by area code, from `audit/inventory.md` (awk on the ID prefix and Outcome column). + +| Area | Rows | untested | blocked | pass | fail | n/a | +|---|---|---|---|---|---|---| +| WEB | 145 | 145 | 0 | 0 | 0 | 0 | +| API | 146 | 146 | 0 | 0 | 0 | 0 | +| CRD | 37 | 35 | 2 | 0 | 0 | 0 | +| AGT | 36 | 36 | 0 | 0 | 0 | 0 | +| AUX | 18 | 13 | 5 | 0 | 0 | 0 | +| HELM | 28 | 28 | 0 | 0 | 0 | 0 | +| MOD | 68 | 56 | 12 | 0 | 0 | 0 | +| UPG | 5 | 5 | 0 | 0 | 0 | 0 | +| NODE | 3 | 3 | 0 | 0 | 0 | 0 | +| SEC (`held/inventory-SEC.md`) | 16 | 16 | 0 | 0 | 0 | 0 | +| **Total** | 502 | 483 | 19 | 0 | 0 | 0 | + ## Proposed E2E additions +Counted from the `**Automatable?**` field of each `### ` procedure under `audit/procedures/*.md` (python script, same files): 356 procedures carry the field, 300 say `yes`, 56 say `no`, deferred or n/a. The bucket is the first bucket name written in the field; where a procedure names two (for example "api-auth or api-mods"), the full wording is in the procedure. `web-api` is a new bucket proposed in OD-021 item 12 that does not exist yet in `test/e2e/buckets.sh`. + +| Proposed bucket | Procedures | +|---|---| +| api-agent | 77 | +| web-api | 74 | +| api-auth | 53 | +| api-mods | 35 | +| operator | 28 | +| api-rbac | 23 | +| api-roles | 6 | +| upgrade | 3 | +| bot-heavy | 1 | + +Procedures by bucket (area file and slug; the link goes to the procedure): + +**api-agent** (77): [agent:console-source](procedures/agent.md#console-source), [agent:console-telnet](procedures/agent.md#console-telnet), [agent:console-websocket](procedures/agent.md#console-websocket), [agent:console-battleye](procedures/agent.md#console-battleye), [agent:console-satisfactory](procedures/agent.md#console-satisfactory), [agent:console-palworld](procedures/agent.md#console-palworld), [agent:console-nuclearoption](procedures/agent.md#console-nuclearoption), [agent:console-rest](procedures/agent.md#console-rest), [agent:console-pty](procedures/agent.md#console-pty), [agent:files-list](procedures/agent.md#files-list), [agent:files-read](procedures/agent.md#files-read), [agent:files-write](procedures/agent.md#files-write), [agent:files-upload](procedures/agent.md#files-upload), [agent:files-download](procedures/agent.md#files-download), [agent:files-mkdir](procedures/agent.md#files-mkdir), [agent:files-delete](procedures/agent.md#files-delete), [agent:logs-tail](procedures/agent.md#logs-tail), [agent:logs-download](procedures/agent.md#logs-download), [agent:players-list](procedures/agent.md#players-list), [agent:players-banned](procedures/agent.md#players-banned), [agent:players-kick](procedures/agent.md#players-kick), [agent:players-ban](procedures/agent.md#players-ban), [agent:players-unban](procedures/agent.md#players-unban), [agent:players-whitelist](procedures/agent.md#players-whitelist), [agent:players-whitelist-add](procedures/agent.md#players-whitelist-add), [agent:players-whitelist-remove](procedures/agent.md#players-whitelist-remove), [agent:quiesce-pause](procedures/agent.md#quiesce-pause), [agent:quiesce-resume](procedures/agent.md#quiesce-resume), [agent:lifecycle-stop](procedures/agent.md#lifecycle-stop), [agent:actions-run](procedures/agent.md#actions-run), [agent:status-metrics](procedures/agent.md#status-metrics), [agent:mods-list](procedures/agent.md#mods-list), [agent:mods-install](procedures/agent.md#mods-install), [agent:mods-upload](procedures/agent.md#mods-upload), [agent:mods-remove](procedures/agent.md#mods-remove), [agent:heartbeat-metrics](procedures/agent.md#heartbeat-metrics), [aux:sentinel-minecraft-status-ping](procedures/aux.md#sentinel-minecraft-status-ping), [aux:sentinel-minecraft-join-wake](procedures/aux.md#sentinel-minecraft-join-wake), [aux:sentinel-terraria-generic-udp](procedures/aux.md#sentinel-terraria-generic-udp), [aux:capture-sidecar-start-stop](procedures/aux.md#capture-sidecar-start-stop), [aux:mcp-server-read-only-check](procedures/aux.md#mcp-server-read-only-check), [crd:gameserver-create-from-template](procedures/crd.md#gameserver-create-from-template), [crd:gameserver-restart](procedures/crd.md#gameserver-restart), [crd:gameserver-wipe-data-volume](procedures/crd.md#gameserver-wipe-data-volume), [web:servers-start-server](procedures/web.md#servers-start-server), [web:servers-stop-server](procedures/web.md#servers-stop-server), [web:servers-restart-server](procedures/web.md#servers-restart-server), [web:servers-wake-sleeping-server](procedures/web.md#servers-wake-sleeping-server), [web:server-detail-lifecycle-start](procedures/web.md#server-detail-lifecycle-start), [web:server-detail-lifecycle-stop](procedures/web.md#server-detail-lifecycle-stop), [web:server-detail-lifecycle-restart](procedures/web.md#server-detail-lifecycle-restart), [web:server-detail-lifecycle-wake](procedures/web.md#server-detail-lifecycle-wake), [web:server-detail-console-send-command](procedures/web.md#server-detail-console-send-command), [web:server-detail-logs-view-game-logs](procedures/web.md#server-detail-logs-view-game-logs), [web:server-detail-files-browse](procedures/web.md#server-detail-files-browse), [web:server-detail-files-view-file](procedures/web.md#server-detail-files-view-file), [web:server-detail-files-edit-file](procedures/web.md#server-detail-files-edit-file), [web:server-detail-files-upload-file](procedures/web.md#server-detail-files-upload-file), [web:server-detail-files-create-file](procedures/web.md#server-detail-files-create-file), [web:server-detail-files-create-directory](procedures/web.md#server-detail-files-create-directory), [web:server-detail-files-delete-file](procedures/web.md#server-detail-files-delete-file), [web:server-detail-mods-list](procedures/web.md#server-detail-mods-list), [web:server-detail-mods-install-url](procedures/web.md#server-detail-mods-install-url), [web:server-detail-mods-install-registry](procedures/web.md#server-detail-mods-install-registry), [web:server-detail-mods-upload](procedures/web.md#server-detail-mods-upload), [web:server-detail-mods-remove](procedures/web.md#server-detail-mods-remove), [web:server-detail-modpacks-install](procedures/web.md#server-detail-modpacks-install), [web:server-detail-players-view](procedures/web.md#server-detail-players-view), [web:server-detail-players-kick](procedures/web.md#server-detail-players-kick), [web:server-detail-players-ban](procedures/web.md#server-detail-players-ban), [web:server-detail-players-unban](procedures/web.md#server-detail-players-unban), [web:server-detail-players-whitelist-add](procedures/web.md#server-detail-players-whitelist-add), [web:server-detail-players-whitelist-remove](procedures/web.md#server-detail-players-whitelist-remove), [web:create-server-wizard-pick-template](procedures/web.md#create-server-wizard-pick-template), [web:create-server-wizard-configure](procedures/web.md#create-server-wizard-configure), [web:create-server-wizard-network](procedures/web.md#create-server-wizard-network), [web:create-server-wizard-review-create](procedures/web.md#create-server-wizard-review-create) + +**web-api** (74): [web:dashboard-view-recent-activity](procedures/web.md#dashboard-view-recent-activity), [web:dashboard-view-recent-backups](procedures/web.md#dashboard-view-recent-backups), [web:servers-filter-by-namespace](procedures/web.md#servers-filter-by-namespace), [web:server-detail-logs-view-pod-logs](procedures/web.md#server-detail-logs-view-pod-logs), [web:server-detail-mods-browse-registry](procedures/web.md#server-detail-mods-browse-registry), [web:server-detail-mods-check-updates](procedures/web.md#server-detail-mods-check-updates), [web:server-detail-modpacks-browse](procedures/web.md#server-detail-modpacks-browse), [web:server-detail-backups-create-now](procedures/web.md#server-detail-backups-create-now), [web:server-detail-backups-view-list](procedures/web.md#server-detail-backups-view-list), [web:server-detail-backups-restore](procedures/web.md#server-detail-backups-restore), [web:server-detail-backups-schedule-create](procedures/web.md#server-detail-backups-schedule-create), [web:server-detail-backups-schedule-delete](procedures/web.md#server-detail-backups-schedule-delete), [web:server-detail-settings-general](procedures/web.md#server-detail-settings-general), [web:server-detail-settings-version](procedures/web.md#server-detail-settings-version), [web:server-detail-settings-resources](procedures/web.md#server-detail-settings-resources), [web:server-detail-settings-networking](procedures/web.md#server-detail-settings-networking), [web:server-detail-settings-environment](procedures/web.md#server-detail-settings-environment), [web:server-detail-settings-lifecycle](procedures/web.md#server-detail-settings-lifecycle), [web:server-detail-settings-scheduled-backups](procedures/web.md#server-detail-settings-scheduled-backups), [web:server-detail-settings-network-capture](procedures/web.md#server-detail-settings-network-capture), [web:server-detail-settings-placement](procedures/web.md#server-detail-settings-placement), [web:server-detail-settings-access](procedures/web.md#server-detail-settings-access), [web:server-detail-settings-sharelinks-create](procedures/web.md#server-detail-settings-sharelinks-create), [web:server-detail-settings-sharelinks-view](procedures/web.md#server-detail-settings-sharelinks-view), [web:server-detail-settings-sharelinks-revoke](procedures/web.md#server-detail-settings-sharelinks-revoke), [web:server-detail-settings-danger-delete](procedures/web.md#server-detail-settings-danger-delete), [web:server-detail-settings-danger-transfer](procedures/web.md#server-detail-settings-danger-transfer), [web:modules-catalog-browse](procedures/web.md#modules-catalog-browse), [web:modules-search](procedures/web.md#modules-search), [web:modules-filter-by-source](procedures/web.md#modules-filter-by-source), [web:modules-filter-by-category](procedures/web.md#modules-filter-by-category), [web:modules-install](procedures/web.md#modules-install), [web:modules-upgrade](procedures/web.md#modules-upgrade), [web:modules-uninstall](procedures/web.md#modules-uninstall), [web:modules-upload-custom](procedures/web.md#modules-upload-custom), [web:users-list-view](procedures/web.md#users-list-view), [web:users-invite](procedures/web.md#users-invite), [web:users-edit-role](procedures/web.md#users-edit-role), [web:users-reset-password](procedures/web.md#users-reset-password), [web:users-delete](procedures/web.md#users-delete), [web:users-manage-roles](procedures/web.md#users-manage-roles), [web:admin-settings-general](procedures/web.md#admin-settings-general), [web:admin-settings-auth](procedures/web.md#admin-settings-auth), [web:admin-settings-backup-destinations](procedures/web.md#admin-settings-backup-destinations), [web:admin-settings-module-sources](procedures/web.md#admin-settings-module-sources), [web:admin-settings-mod-registries](procedures/web.md#admin-settings-mod-registries), [web:admin-settings-notifications](procedures/web.md#admin-settings-notifications), [web:admin-settings-telemetry](procedures/web.md#admin-settings-telemetry), [web:admin-settings-updates](procedures/web.md#admin-settings-updates), [web:admin-settings-about](procedures/web.md#admin-settings-about), [web:theme-settings-import](procedures/web.md#theme-settings-import), [web:backups-list-view](procedures/web.md#backups-list-view), [web:backups-filter-by-server](procedures/web.md#backups-filter-by-server), [web:backups-filter-by-phase](procedures/web.md#backups-filter-by-phase), [web:backups-backup-now](procedures/web.md#backups-backup-now), [web:backups-restore](procedures/web.md#backups-restore), [web:backups-view-detail](procedures/web.md#backups-view-detail), [web:backups-schedules-create](procedures/web.md#backups-schedules-create), [web:backups-schedules-edit](procedures/web.md#backups-schedules-edit), [web:backups-schedules-toggle-suspend](procedures/web.md#backups-schedules-toggle-suspend), [web:backups-schedules-delete](procedures/web.md#backups-schedules-delete), [web:backups-restores-view](procedures/web.md#backups-restores-view), [web:audit-log-view](procedures/web.md#audit-log-view), [web:audit-log-filter-by-status-class](procedures/web.md#audit-log-filter-by-status-class), [web:audit-log-filter-by-method](procedures/web.md#audit-log-filter-by-method), [web:audit-log-filter-by-actor](procedures/web.md#audit-log-filter-by-actor), [web:audit-log-pagination](procedures/web.md#audit-log-pagination), [web:audit-log-verify-integrity](procedures/web.md#audit-log-verify-integrity), [web:admin-logs-view-api](procedures/web.md#admin-logs-view-api), [web:admin-logs-view-operator](procedures/web.md#admin-logs-view-operator), [web:admin-logs-tail-option](procedures/web.md#admin-logs-tail-option), [web:admin-logs-follow](procedures/web.md#admin-logs-follow), [web:share-server-start](procedures/web.md#share-server-start), [web:share-server-view-status](procedures/web.md#share-server-view-status) + +**api-auth** (53): [api:public-healthz-get](procedures/api.md#public-healthz-get), [api:public-metrics-get](procedures/api.md#public-metrics-get), [api:public-auth-providers-list](procedures/api.md#public-auth-providers-list), [api:public-auth-login](procedures/api.md#public-auth-login), [api:public-auth-logout](procedures/api.md#public-auth-logout), [api:public-auth-oidc-provider-start](procedures/api.md#public-auth-oidc-provider-start), [api:audit-read-paginated](procedures/api.md#audit-read-paginated), [api:audit-verify-chain](procedures/api.md#audit-verify-chain), [api:audit-export-csv](procedures/api.md#audit-export-csv), [api:audit-export-json](procedures/api.md#audit-export-json), [api:config-read-all](procedures/api.md#config-read-all), [api:config-write-section](procedures/api.md#config-write-section), [api:auth-provider-secret-put](procedures/api.md#auth-provider-secret-put), [api:auth-provider-secret-delete](procedures/api.md#auth-provider-secret-delete), [api:notifications-secret-put](procedures/api.md#notifications-secret-put), [api:registry-secret-put](procedures/api.md#registry-secret-put), [api:users-list](procedures/api.md#users-list), [api:users-create](procedures/api.md#users-create), [api:users-me](procedures/api.md#users-me), [api:users-preferences-get](procedures/api.md#users-preferences-get), [api:users-preferences-put](procedures/api.md#users-preferences-put), [api:users-preferences-reset](procedures/api.md#users-preferences-reset), [api:users-get](procedures/api.md#users-get), [api:users-update](procedures/api.md#users-update), [api:users-reset-password](procedures/api.md#users-reset-password), [api:users-bindings-list](procedures/api.md#users-bindings-list), [api:users-bindings-add](procedures/api.md#users-bindings-add), [api:users-delete](procedures/api.md#users-delete), [api:roles-list](procedures/api.md#roles-list), [api:roles-permissions-catalog](procedures/api.md#roles-permissions-catalog), [api:cluster-view](procedures/api.md#cluster-view), [api:cluster-info](procedures/api.md#cluster-info), [api:cluster-stats](procedures/api.md#cluster-stats), [api:cluster-join-node](procedures/api.md#cluster-join-node), [api:cluster-download-kubeconfig](procedures/api.md#cluster-download-kubeconfig), [api:clusters-list](procedures/api.md#clusters-list), [api:modules-list-installed](procedures/api.md#modules-list-installed), [api:modules-list-sources](procedures/api.md#modules-list-sources), [api:modules-catalog](procedures/api.md#modules-catalog), [api:backup-destinations-list](procedures/api.md#backup-destinations-list), [api:events-sse](procedures/api.md#events-sse), [api:system-logs-api](procedures/api.md#system-logs-api), [api:system-logs-operator](procedures/api.md#system-logs-operator), [aux:audit-syslog-bridge-blocked-candidate](procedures/aux.md#audit-syslog-bridge-blocked-candidate), [aux:telemetry-receiver-opt-in](procedures/aux.md#telemetry-receiver-opt-in), [helm:audit-webhook-sink](procedures/helm.md#audit-webhook-sink), [helm:syslog-bridge-audit](procedures/helm.md#syslog-bridge-audit), [helm:audit-stdout-logging](procedures/helm.md#audit-stdout-logging), [helm:web-dashboard-ui](procedures/helm.md#web-dashboard-ui), [helm:ingress-configuration](procedures/helm.md#ingress-configuration), [helm:image-tag-override](procedures/helm.md#image-tag-override), [web:login-username-password](procedures/web.md#login-username-password), [web:login-safe-mode](procedures/web.md#login-safe-mode) + +**api-mods** (35): [crd:backup-create-and-run](procedures/crd.md#backup-create-and-run), [crd:backup-failure-and-phase](procedures/crd.md#backup-failure-and-phase), [crd:restore-create-and-suspend-server](procedures/crd.md#restore-create-and-suspend-server), [crd:restore-running-to-succeeded](procedures/crd.md#restore-running-to-succeeded), [crd:backup-schedule-create](procedures/crd.md#backup-schedule-create), [crd:backup-schedule-tick-creates-backup](procedures/crd.md#backup-schedule-tick-creates-backup), [crd:backup-schedule-retention-prunes](procedures/crd.md#backup-schedule-retention-prunes), [crd:module-create-pending](procedures/crd.md#module-create-pending), [crd:module-pulling-to-ready](procedures/crd.md#module-pulling-to-ready), [crd:module-bad-signature-fails](procedures/crd.md#module-bad-signature-fails), [crd:modulesource-oci-sync](procedures/crd.md#modulesource-oci-sync), [crd:modulesource-git-sync-error](procedures/crd.md#modulesource-git-sync-error), [crd:backup-volumesnapshot-strategy](procedures/crd.md#backup-volumesnapshot-strategy), [crd:restore-volumesnapshot-strategy](procedures/crd.md#restore-volumesnapshot-strategy), [helm:telemetry-receiver-bundled](procedures/helm.md#telemetry-receiver-bundled), [helm:mcp-server-deployment](procedures/helm.md#mcp-server-deployment), [helm:default-module-source](procedures/helm.md#default-module-source), [helm:module-signature-verification](procedures/helm.md#module-signature-verification), [helm:upload-module-source](procedures/helm.md#upload-module-source), [modules:garrys-mod](procedures/modules.md#garrys-mod), [modules:farming-simulator-25](procedures/modules.md#farming-simulator-25), [modules:beammp](procedures/modules.md#beammp), [modules:valheim](procedures/modules.md#valheim), [modules:dont-starve-together](procedures/modules.md#dont-starve-together), [modules:tmodloader](procedures/modules.md#tmodloader), [modules:terraria](procedures/modules.md#terraria), [modules:factorio](procedures/modules.md#factorio), [modules:dayz](procedures/modules.md#dayz), [modules:palworld](procedures/modules.md#palworld), [modules:fivem](procedures/modules.md#fivem), [modules:satisfactory](procedures/modules.md#satisfactory), [modules:ark-survival-ascended](procedures/modules.md#ark-survival-ascended), [modules:cs2](procedures/modules.md#cs2), [modules:minecraft-java](procedures/modules.md#minecraft-java), [modules:rust](procedures/modules.md#rust) + +**operator** (28): [crd:gameserver-phase-pending-to-starting](procedures/crd.md#gameserver-phase-pending-to-starting), [crd:gameserver-phase-starting-to-running](procedures/crd.md#gameserver-phase-starting-to-running), [crd:gameserver-suspend](procedures/crd.md#gameserver-suspend), [crd:gameserver-unsuspend-wake](procedures/crd.md#gameserver-unsuspend-wake), [crd:gameserver-version-switch](procedures/crd.md#gameserver-version-switch), [crd:gameserver-idle-auto-sleep](procedures/crd.md#gameserver-idle-auto-sleep), [crd:gameserver-idle-wake-window](procedures/crd.md#gameserver-idle-wake-window), [crd:gameserver-delete-no-finalizer](procedures/crd.md#gameserver-delete-no-finalizer), [crd:gameserver-failed-phase-crash-loop](procedures/crd.md#gameserver-failed-phase-crash-loop), [crd:gametemplate-create](procedures/crd.md#gametemplate-create), [crd:networkcapture-create-pending](procedures/crd.md#networkcapture-create-pending), [crd:networkcapture-start-running](procedures/crd.md#networkcapture-start-running), [crd:networkcapture-stop-completed](procedures/crd.md#networkcapture-stop-completed), [crd:networkcapture-failed-sidecar-crash](procedures/crd.md#networkcapture-failed-sidecar-crash), [crd:networkcapture-expired-auto-delete](procedures/crd.md#networkcapture-expired-auto-delete), [helm:existing-storage-claim](procedures/helm.md#existing-storage-claim), [helm:operator-leader-election](procedures/helm.md#operator-leader-election), [nodes:scheduling](procedures/nodes.md#scheduling), [nodes:drain](procedures/nodes.md#drain), [web:dashboard-view-fleet-summary](procedures/web.md#dashboard-view-fleet-summary), [web:dashboard-view-cluster-resources](procedures/web.md#dashboard-view-cluster-resources), [web:servers-list-view](procedures/web.md#servers-list-view), [web:servers-filter-by-status](procedures/web.md#servers-filter-by-status), [web:servers-search-by-name](procedures/web.md#servers-search-by-name), [web:servers-filter-by-game](procedures/web.md#servers-filter-by-game), [web:server-detail-overview-tab](procedures/web.md#server-detail-overview-tab), [web:server-detail-events-view](procedures/web.md#server-detail-events-view), [web:cluster-view-nodes](procedures/web.md#cluster-view-nodes) + +**api-rbac** (23): [api:servers-list](procedures/api.md#servers-list), [api:servers-create](procedures/api.md#servers-create), [api:servers-get](procedures/api.md#servers-get), [api:servers-update](procedures/api.md#servers-update), [api:templates-list](procedures/api.md#templates-list), [api:templates-get](procedures/api.md#templates-get), [api:backups-list](procedures/api.md#backups-list), [api:schedules-list](procedures/api.md#schedules-list), [api:restores-list](procedures/api.md#restores-list), [api:capture-enable](procedures/api.md#capture-enable), [api:servers-start](procedures/api.md#servers-start), [api:servers-stop](procedures/api.md#servers-stop), [api:servers-restart](procedures/api.md#servers-restart), [api:servers-clone](procedures/api.md#servers-clone), [api:servers-wipe-data](procedures/api.md#servers-wipe-data), [api:servers-delete](procedures/api.md#servers-delete), [api:files-list](procedures/api.md#files-list), [api:files-read](procedures/api.md#files-read), [api:files-upload](procedures/api.md#files-upload), [api:players-list](procedures/api.md#players-list), [helm:cluster-operations-feature](procedures/helm.md#cluster-operations-feature), [helm:network-policies-enforcement](procedures/helm.md#network-policies-enforcement), [helm:pod-security-enforcement](procedures/helm.md#pod-security-enforcement) + +**api-roles** (6): [api:public-shares-resolve](procedures/api.md#public-shares-resolve), [api:public-shares-start](procedures/api.md#public-shares-start), [api:shares-create](procedures/api.md#shares-create), [api:shares-list](procedures/api.md#shares-list), [api:servers-collaborators-set](procedures/api.md#servers-collaborators-set), [api:servers-transfer](procedures/api.md#servers-transfer) + +**upgrade** (3): [helm:crd-auto-apply-hook](procedures/helm.md#crd-auto-apply-hook), [upgrade:upgrade-to-rc](procedures/upgrade.md#upgrade-to-rc), [upgrade:restart](procedures/upgrade.md#restart) + +**bot-heavy** (1): [modules:nuclear-option](procedures/modules.md#nuclear-option) + + ## Status-wording change set + +Copied from [contracts/status-wording.md](../contracts/status-wording.md) (T067 copy step) on 2026-10-05. That contract was last re-checked on 2026-10-04 on master `6750ba87`; it was not re-run or edited here. Applied as one commit only after the go decision (T071). Re-run the re-check command once more before applying. + +### Wording + +| Replace | With | +|---|---| +| `Status: **beta** (\`v0.2.0-beta.8\`)` and variants | `Status: **pre-v1 release** (\`v0.3.0\`)` | +| `## Beta Status & Limitations` | `## Pre-v1 Status & Limitations` (update the `#beta-status--limitations` anchor at `README.md:10`) | +| `Gameplane is currently in **beta**` | `Gameplane is a **pre-v1 release**` | +| `**Status:** Beta (\`v0.2.0-beta.8\`)` in CLAUDE.md | `**Status:** Pre-v1 release (\`v0.3.0\`)` | +| `**Status:** beta (v0.2.0-beta.8)` in module `specs.md` | `**Status:** pre-v1 (v0.3.0)` | +| roadmap "between beta and a v1 GA" | "between v0.3 and a v1 GA" | + +The new wording must not claim v1, "stable" or production support (OD-003). The remaining caveats stay in `docs/roadmap.md` under "Wanted for v1, not blocking". + +### Version markers → `0.3.0` + +- `charts/gameplane/Chart.yaml:5-6`: `version` and `appVersion` +- `web/package.json:4`, and the regenerated `web/package-lock.json` top-level version +- `README.md:8,39,61` (also the `#beta-status--limitations` link at `README.md:10`, the `## Beta Status & Limitations` heading at `README.md:37`, and "rolling beta" at `README.md:216`) +- `CLAUDE.md:5` (was `:6`; the line now reads `**Status:** beta \`v0.2.0-beta.8\`; v1 scope feature-complete, stabilizing.`, so the table row for CLAUDE.md matches by meaning, not by literal text) +- `docs/roadmap.md:3,6,223` (was `:211`; line 6 and 223 hold the "between beta and a v1 GA" wording) +- `docs/install.md:14` (example version), `docs/install.md:34` (edge-channel heading wording, was `:27`), `docs/install.md:636` ("Releases up to `0.2.0-beta.8`", new: reword by meaning, the fact stays true) +- `docs/dependencies.md:29,33,320` (was `:26,28,226`) +- `telemetry-receiver/README.md:9,28`, and `telemetry-receiver/specs.md:53,65` (new: the example payload and metric carry `0.2.0-beta.7`) +- `web/specs.md:745` (was `:740`, the `package.json` description line) +- Status lines in `*/specs.md`: `agent`, `api`, `audit-syslog-bridge`, `capture-sidecar`, `gameaction`, `gameproto`, `mcp-server`, `netguard`, `operator`, `sentinel`, `telemetry-receiver`, `tunnel`, `web`, `test/e2e`, and `test/e2e/internal/**/spec.md`. Keep each file's existing qualifiers, such as "probe depth measured" and "in-progress". Some `test/e2e/internal/*/spec.md` status lines carry no version (`**Status:** beta; probe depth measured: ...`, 13 files, plus one `**Status:** Beta (implemented, not yet CI-verified)` and one `**Status:** beta (heavy-set, hand-run only)`): change the bare word to `pre-v1` and keep the qualifier. The other `test/e2e` status lines, including `test/e2e/specs.md:3` and `test/e2e/internal/specs.md:3`, carry `(v0.2.0-beta.8)` and follow the module `specs.md` row of the Wording table. +- `.github/workflows/publish-edge.yaml:3`: the comment says "beta images". Change it to "edge images". + +### Coupled changes, in the same release but not wording + +- The upgrade baseline goes from `0.2.0-beta.5` to `0.2.0-beta.8`: `deploy/kind/upgrade.sh:35`, `.github/workflows/ci.yaml:869-881,1307`, `.claude/agents/ci-triager.md:66`. **Already landed on master** (re-check 2026-10-04): all three now read `0.2.0-beta.8`. The fixture `charts/gameplane/testdata/upgrade-from-v0.2.0-beta.8-values.yaml` is a frozen copy of beta.8's values (its `ref: v0.2.0-beta.6` at `:431` is intentionally historical, leave it). +- The default git module source `ref: v0.2.0-beta.6` (`charts/gameplane/values.yaml:576`, was `:473`) moves to the `gameplane-module` tag tested with v0.3.0. +- `hack/check-doc-versions.sh` only recognises `-beta.N` versions: see lines 19, 94, 103 and 151, where the single-digit `[0-9]` pattern disagrees with the `[0-9]+` in the header. Without a fix it can't catch stale `0.3.0` or `-rc.N` strings. It has to accept `X.Y.Z` and `X.Y.Z-(beta|rc).N` before the wording commit. This is seeded as a finding. **Already landed on master** (re-check 2026-10-04): `hack/check-doc-versions.sh:19-26,110-121` now matches bare `v?0.X.Y` and `-(beta|rc).N` (OD-011). Confirm in the T071 pass that the script has no remaining single-digit patterns. +- `hack/check-links.sh:60-67,211`: the anchor self-test hard-codes `"Beta Status & Limitations"` -> `beta-status--limitations`. Keep it as a pure slug-algorithm example (it does not read the README), or update it with the heading; either way `make check-links` must pass after the README rename. +- `CHANGELOG.md` gets a `## [0.3.0]` section. The "Unreleased" entries, including the OIDC Helm role mappings flagged in 012 OD-8, move into it or into the right RC sections. + +### Left as-is (historical or unrelated) + +- Lines marked `` (including `README.md:232`, `docs/install.md:61,694`, `docs/oidc.md:50,91,383`, `docs/roadmap.md:18,36,41,179`), "shipped v0.2.0-beta.X" roadmap headings, and past CHANGELOG sections. +- Chart comments about `<= 0.2.0-beta.5` behaviour (`charts/gameplane/templates/api.yaml:231,332`, was `:219,315`; `crd-apply-hook.yaml:115`, was `:71`). +- Kubernetes "This is a beta field" text in generated CRDs, `service.beta.kubernetes.io` annotations, and test fixtures that use "beta" as a server name. +- Fixtures and tooling that use these strings on purpose: `hack/testdata/check-doc-versions/**` (the checker's own pass/fail fixtures), `charts/gameplane/testdata/upgrade-from-v0.2.0-beta.8-values.yaml`. (`hack/check-links.sh:60-67,211` is not left as-is: see Coupled changes above.) +- Roadmap headings "(shipped v0.2.0-beta.8)" (`docs/roadmap.md:76,100,143,189,204`), `.github/workflows/release.yaml:265` (comment about past release pages), `deploy/kind/upgrade.sh:80` ("beta.5 published no web"). +- `web/specs.md:455,510` ("released/beta/unstable" version channel in the picker, a product term), `docs/comparison-sources.md:24,307` (24 quotes the README status line as verified evidence: re-verify after the README change; 307 is Agones's own "Beta" label). +- Test fixtures using "beta"/"Beta"/"alpha" as names, in `*_test.go`, `*.test.tsx`, `web/src/test/handlers.ts:165`, `web/e2e/specs/restoreFlow.spec.ts:51`, `web/src/routes/tabs/settings/Networking.tsx:450` (`service.beta.kubernetes.io`), `web/src/test/screenshotData.ts:1088` (sample log line, a version string in demo data: bump only if the screenshot dataset is refreshed). +- Web tests that assert no version or "beta" text leaks onto public pages (`web/src/routes/Share.test.tsx:137,559`, `web/e2e/specs/slice5.spec.ts:124`). These are login-privacy guards and must stay. +- `reddit.md` (`:6,23`) and `IDEA.md` (`:10`). They're maintainer notes. Flag them to the maintainer, but they're not part of the product docs. + +### Re-check command + +```sh +git grep -n -E '0\.2\.0-beta\.[0-9]+|\b[Bb]eta\b' -- ':!specs/**' ':!CHANGELOG.md' ':!**/package-lock.json' ':!*.pen' ':!design-export/**' +``` +Every remaining hit must fall under "Left as-is". + +### Re-checked 2026-10-04 on master 6750ba87 + +Re-ran the command above on a checkout with master `6750ba87` merged in (T067). 256 matching lines, against 239 when the same command is run at the 2026-09-23 commit `652df873`. Almost all of the +17 are test fixtures and tooling that fall under "Left as-is". Product-facing changes: + +- **Moved:** `CLAUDE.md:6`->`5` (and its wording changed), `docs/roadmap.md:211`->`223`, `docs/install.md:27`->`34`, `docs/dependencies.md:26,28,226`->`29,33,320`, `web/specs.md:740`->`745`, `charts/gameplane/values.yaml:473`->`576`, `.github/workflows/ci.yaml:968-970`->`869-881,1307`, `deploy/kind/upgrade.sh:36`->`35`, `.claude/agents/ci-triager.md:65`->`66`, `charts/gameplane/templates/api.yaml:219,315`->`231,332`, `crd-apply-hook.yaml:71`->`115`. The list above carries the new numbers. +- **New hits to change:** `docs/install.md:636`, `telemetry-receiver/specs.md:53,65`, the version-less `Status: beta` lines in 15 `test/e2e/internal/*/spec.md` files, `README.md:10,37,216` (listed explicitly now). +- **New hits left as-is:** `hack/testdata/check-doc-versions/**`, `charts/gameplane/testdata/upgrade-from-v0.2.0-beta.8-values.yaml`, `docs/comparison-sources.md:24,307`, `web/specs.md:455,510`, `release.yaml:265`, `deploy/kind/upgrade.sh:80`, the new test-fixture names. `hack/check-links.sh:60-67,211` is a coupled change (see above). +- **Resolved on master:** the `check-doc-versions.sh` pattern fix and the upgrade baseline bump (both noted above). +- **Still outstanding:** the roadmap/README/CLAUDE.md/Chart/package.json/specs.md wording and version bumps, which are applied only after the go decision. Re-run once more before T071 and copy the final set into `audit/report.md` once T066 creates it. From 6a752d7122ed140f15a7baf3a97b33a4427905a5 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 23:07:54 +0000 Subject: [PATCH 2/4] docs(specs): 018 record the v0.3.0 go decision (T070) Maintainer decision 2026-10-05: go, with the Not met release criteria accepted as known risk. Met column filled from the report's evidence; RC-08 waits for the v0.3.0 tag. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01UshpSigdLccuYZi7oFJX9y Signed-off-by: Claude --- .../audit/release-criteria.md | 17 +++++++++-------- .../018-v0-3-release-readiness/audit/report.md | 9 +++++---- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/specs/018-v0-3-release-readiness/audit/release-criteria.md b/specs/018-v0-3-release-readiness/audit/release-criteria.md index dd4247242..3f20a154a 100644 --- a/specs/018-v0-3-release-readiness/audit/release-criteria.md +++ b/specs/018-v0-3-release-readiness/audit/release-criteria.md @@ -4,15 +4,16 @@ Written before round 0 (FR-015). Columns are fixed by [contracts/audit-records.m | ID | Criterion | Source | Evidence | Met | |----|-----------|--------|----------|-----| -| RC-01 | Every inventory row has an outcome, zero rows `fail`, and every `blocked` row names its prerequisite and is listed as not live-verified | SC-001 | [report.md#totals](report.md#totals), [report.md#not-live-verified](report.md#not-live-verified) | pending | -| RC-02 | Every component has a `complete` review record | SC-002 | [coverage.md](coverage.md), [report.md#by-component](report.md#by-component) | pending | -| RC-03 | Zero findings in `imported`, `open`, `fixing` or `fixed-unverified` | SC-003, SC-004 | [report.md#open-findings](report.md#open-findings), [findings.md](findings.md) | pending | -| RC-04 | Each FR-008 boundary has at least one active violation attempt recorded | SC-007 | [inventory.md#sec](inventory.md#sec) | pending | -| RC-05 | Live beta.8 → RC upgrade with zero data loss and zero lost accounts | SC-005, OD-005 | [inventory.md#upg](inventory.md#upg) | pending | -| RC-06 | The baseline snapshot matches the post-cleanup snapshot, with zero `audit018-` resources remaining | SC-006 | [rounds.md](rounds.md), [kubelab-baseline.md](kubelab-baseline.md) | pending | -| RC-07 | Every `not-a-defect` and `out-of-scope` closure is justified, and each out-of-scope one cites a roadmap line | SC-009 | [findings.md](findings.md) | pending | -| RC-08 | CI is green on the tagged commit | FR-017 | [rounds.md#v030](rounds.md#v030) | pending | +| RC-01 | Every inventory row has an outcome, zero rows `fail`, and every `blocked` row names its prerequisite and is listed as not live-verified | SC-001 | [report.md#totals](report.md#totals), [report.md#not-live-verified](report.md#not-live-verified) | not met (accepted risk, T070) | +| RC-02 | Every component has a `complete` review record | SC-002 | [coverage.md](coverage.md), [report.md#by-component](report.md#by-component) | met | +| RC-03 | Zero findings in `imported`, `open`, `fixing` or `fixed-unverified` | SC-003, SC-004 | [report.md#open-findings](report.md#open-findings), [findings.md](findings.md) | not met (accepted risk, T070) | +| RC-04 | Each FR-008 boundary has at least one active violation attempt recorded | SC-007 | [inventory.md#sec](inventory.md#sec) | not met (accepted risk, T070) | +| RC-05 | Live beta.8 → RC upgrade with zero data loss and zero lost accounts | SC-005, OD-005 | [inventory.md#upg](inventory.md#upg) | not met (accepted risk, T070) | +| RC-06 | The baseline snapshot matches the post-cleanup snapshot, with zero `audit018-` resources remaining | SC-006 | [rounds.md](rounds.md), [kubelab-baseline.md](kubelab-baseline.md) | not met (accepted risk, T070) | +| RC-07 | Every `not-a-defect` and `out-of-scope` closure is justified, and each out-of-scope one cites a roadmap line | SC-009 | [findings.md](findings.md) | partially (accepted risk, T070) | +| RC-08 | CI is green on the tagged commit | FR-017 | [rounds.md#v030](rounds.md#v030) | pending (set after the v0.3.0 tag, T073) | ## Change log - 2026-09-24: RC-03 now also counts `imported` findings as blocking, matching data-model.md's blocking statuses. Maintainer decision, OD-010 in [../OPEN-DECISIONS.md](../OPEN-DECISIONS.md#od-010-rc-03-leaves-out-the-imported-status--resolved-2026-09-24). +- 2026-10-05: `Met` filled at the go/no-go decision (T070, maintainer valgulnecron: go, with Not met criteria accepted as known risk; see [report.md#decision](report.md#decision)). Criteria themselves unchanged. diff --git a/specs/018-v0-3-release-readiness/audit/report.md b/specs/018-v0-3-release-readiness/audit/report.md index 4457dafdc..2c368ab9d 100644 --- a/specs/018-v0-3-release-readiness/audit/report.md +++ b/specs/018-v0-3-release-readiness/audit/report.md @@ -6,11 +6,12 @@ Built from the audit records at the end of the audit (T066). Readable cold in un ## Decision -Not decided. This section is the maintainer's (T070): name, date and go/no-go go here. +**Go**, with the open criteria accepted as known risk (maintainer decision, T070). -- Go/no-go: _pending_ -- Maintainer: _pending_ -- Date: _pending_ +- Go/no-go: **go** +- Maintainer: valgulnecron +- Date: 2026-10-05 +- Accepted risk: the release criteria marked Not met / Partially below (RC-01, RC-03..RC-08) are not blocking for v0.3.0 by this decision; the gaps stay listed under [Not live-verified](#not-live-verified) and in the release notes. The cold read ([evidence/cold-read.md](evidence/cold-read.md)) recommended no-go; the maintainer chose go. ## Release criteria From 8bc889357741bfca2798a79d98cf4ee88779b70c Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 23:13:31 +0000 Subject: [PATCH 3/4] docs(specs): 018 record screen and feature rows as pass from the live sweep (OD-030) Maintainer attestation 2026-10-05: all screens and features were tested live on kubelab in the 2026-10-04 sweep. 459 WEB/API/CRD/AGT/AUX/HELM/MOD rows move from untested to pass; blocked, UPG, NODE and SEC rows and the findings are unchanged. Report totals, Not live-verified and release notes recounted. RC-01 stays not met (8 UPG/NODE + 16 SEC rows untested). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01UshpSigdLccuYZi7oFJX9y Signed-off-by: Claude --- .../OPEN-DECISIONS.md | 8 + .../audit/evidence/release-notes-v0.3.0.md | 2 +- .../audit/inventory.md | 918 +++++++++--------- .../audit/release-criteria.md | 1 + .../audit/report.md | 30 +- 5 files changed, 484 insertions(+), 475 deletions(-) diff --git a/specs/018-v0-3-release-readiness/OPEN-DECISIONS.md b/specs/018-v0-3-release-readiness/OPEN-DECISIONS.md index 5415d21a9..bdbd2e48f 100644 --- a/specs/018-v0-3-release-readiness/OPEN-DECISIONS.md +++ b/specs/018-v0-3-release-readiness/OPEN-DECISIONS.md @@ -374,3 +374,11 @@ Decision (maintainer, 2026-10-05, as recorded in #549): accept the RBAC widening ### OD-029: the live round runs on the latest `master` commit, not on rc.2 — RESOLVED 2026-10-05 Decision (maintainer, 2026-10-05): the live round was run on the latest `master` commit on kubelab (the 2026-10-04 live sweep, fixes in #548 and #549) instead of on a published rc.2. That sweep stands in for the formal per-row round: T025–T033 are withdrawn, and its bugs are recorded as F-273..F-293 (`audit/rounds.md` § live-sweep 2026-10-04). Per-row `INV-*` outcomes were not recorded, so `audit/inventory.md` rows keep their pre-round Outcome. T034 (cleanup after the round), the upgrade and node rounds (T061, T062, T065), and RC-TAG-2 are not changed by this decision. + +### OD-030: screen and feature rows recorded as pass from the live sweep — RESOLVED 2026-10-05 + +Decision (maintainer valgulnecron, 2026-10-05), attestation: "all screen and feature where tested live in a cluster". It refers to the 2026-10-04 live sweep on kubelab (OD-029; `audit/rounds.md` § live-sweep 2026-10-04; fixes in #548 and #549; findings F-273..F-293). On that basis every `audit/inventory.md` row in the `WEB`, `API`, `CRD`, `AGT`, `AUX`, `HELM` and `MOD` areas whose Outcome was `untested` (459 rows) is recorded as `pass`, Round `live-sweep 2026-10-04`, with Evidence pointing at this entry. The Reason and Findings cells are unchanged. + +Not covered: the `UPG` (5) and `NODE` (3) rows stay `untested`, the 16 `INV-SEC-*` rows in `audit/held/inventory-SEC.md` stay `untested`, and the 19 rows that were already `blocked` stay `blocked` (CRD 2, AUX 5, MOD 12). Finding statuses are not changed by this decision: the findings from the sweep keep their current status. + +This is a maintainer attestation, not per-row evidence: the sweep did not record a per-row outcome, and no `evidence/INV-*/` record was created for these rows. The report and the release notes say so. It resolves the "no row is `pass`" gap noted under OD-029 for these areas only; it does not change T034, the upgrade and node rounds (T061, T062, T065) or RC-TAG-2. diff --git a/specs/018-v0-3-release-readiness/audit/evidence/release-notes-v0.3.0.md b/specs/018-v0-3-release-readiness/audit/evidence/release-notes-v0.3.0.md index e1a0b2041..acd49fde3 100644 --- a/specs/018-v0-3-release-readiness/audit/evidence/release-notes-v0.3.0.md +++ b/specs/018-v0-3-release-readiness/audit/evidence/release-notes-v0.3.0.md @@ -91,7 +91,7 @@ Rows are not live-verified if they are `blocked` (listed below, with the prerequ ### Untested rows -- **467 of 486 inventory rows in `audit/inventory.md` are still `untested`** (WEB 145, API 146, CRD 35, AGT 36, AUX 13, HELM 28, MOD 56, UPG 5, NODE 3). The formal per-row live round did not run (OD-029): the 2026-10-04 informal live sweep on `master` stands in for it, and it did not record per-row outcomes, so no row is marked `pass`. +- **8 of 486 inventory rows in `audit/inventory.md` are still `untested`** (UPG 5, NODE 3); 24 of 502 with the `INV-SEC-*` rows. 459 rows (WEB 145, API 146, CRD 35, AGT 36, AUX 13, HELM 28, MOD 56) are `pass` on the strength of a maintainer attestation, not per-row evidence: the formal per-row live round did not run (OD-029) and the 2026-10-04 informal live sweep on `master` did not record per-row outcomes, so on 2026-10-05 the maintainer attested that "all screen and feature where tested live in a cluster" (OD-030). The attestation does not cover `UPG`, `NODE`, `SEC` or the 19 `blocked` rows. - The 16 security-control rows (`INV-SEC-001` to `INV-SEC-016`) are kept in `audit/held/inventory-SEC.md`, not in `audit/inventory.md` (OD-019; that file has been in git since 8249db80) and are all `untested` there, so no active violation attempt is recorded for them. - No upgrade or node round has run (T061, T062, T065): the beta.8 to RC upgrade (`UPG`, 5 rows) and the node behaviour rows (`NODE`, 3 rows) are `untested`. - 229 findings are `fixed-unverified`: their fixes merged but have not been re-verified on a release candidate (T058 has not run). diff --git a/specs/018-v0-3-release-readiness/audit/inventory.md b/specs/018-v0-3-release-readiness/audit/inventory.md index 0b7584799..7d6897d1f 100644 --- a/specs/018-v0-3-release-readiness/audit/inventory.md +++ b/specs/018-v0-3-release-readiness/audit/inventory.md @@ -5,500 +5,500 @@ Enumerated from code (research R2). Columns and allowed values are fixed by [con ## WEB | ID | Capability | Component | Source | Procedure | CI test | Outcome | Reason | Evidence | Round | Findings | |----|------------|-----------|--------|-----------|---------|---------|--------|----------|-------|----------| -| INV-WEB-001 | Sign in with username and password | web/ | web/src/routes/Login.tsx:69-92 | [p](procedures/web.md#login-username-password) | TestAPI_BootstrapAndLogin | untested | | [e](evidence/INV-WEB-001/) | | | -| INV-WEB-002 | Toggle password visibility on login form | web/ | web/src/routes/Login.tsx:172-186 | [p](procedures/web.md#login-toggle-password-visibility) | none | untested | | [e](evidence/INV-WEB-002/) | | | -| INV-WEB-003 | Sign in with SSO provider | web/ | web/src/routes/Login.tsx:295-312 | [p](procedures/web.md#login-sso-provider) | TestAPI_DynamicAuthProviders, TestAPI_OIDCHelmSeeded_AdminOnFirstLogin | untested | | [e](evidence/INV-WEB-003/) | | | -| INV-WEB-004 | Sign in with safe mode (custom CSS disabled) | web/ | web/src/routes/Login.tsx:69-86 | [p](procedures/web.md#login-safe-mode) | none | untested | | [e](evidence/INV-WEB-004/) | | | -| INV-WEB-005 | Display password reset hint on login | web/ | web/src/routes/Login.tsx:151-159 | [p](procedures/web.md#login-password-forgotten-hint) | TestAPI_PasswordResetInvalidatesSession | untested | | [e](evidence/INV-WEB-005/) | | | -| INV-WEB-006 | View fleet status card (running, stopped, failed servers) | web/ | web/src/routes/Dashboard.tsx:196-249 | [p](procedures/web.md#dashboard-view-fleet-summary) | none | untested | | [e](evidence/INV-WEB-006/) | | | -| INV-WEB-007 | View cluster resources metrics (CPU, memory, storage, nodes) | web/ | web/src/routes/Dashboard.tsx:296-350 | [p](procedures/web.md#dashboard-view-cluster-resources) | none | untested | | [e](evidence/INV-WEB-007/) | | | -| INV-WEB-008 | View recent activity (audit events) | web/ | web/src/routes/Dashboard.tsx:372-410 | [p](procedures/web.md#dashboard-view-recent-activity) | TestAPI_AuditEmitsOnMutation | untested | | [e](evidence/INV-WEB-008/) | | | -| INV-WEB-009 | View recent backups | web/ | web/src/routes/Dashboard.tsx:412-477 | [p](procedures/web.md#dashboard-view-recent-backups) | TestBackup_OperatorMaterializesJob | untested | | [e](evidence/INV-WEB-009/) | | | -| INV-WEB-010 | Create server from dashboard button | web/ | web/src/routes/Dashboard.tsx:113-121 | [p](procedures/web.md#dashboard-create-server-button) | TestAPI_LifecycleClone | untested | | [e](evidence/INV-WEB-010/) | | | -| INV-WEB-011 | List all servers | web/ | web/src/routes/Servers.tsx:38-174 | [p](procedures/web.md#servers-list-view) | none | untested | | [e](evidence/INV-WEB-011/) | | | -| INV-WEB-012 | Filter servers by status (all, running, stopped) | web/ | web/src/routes/Servers.tsx:230-262 | [p](procedures/web.md#servers-filter-by-status) | none | untested | | [e](evidence/INV-WEB-012/) | | | -| INV-WEB-013 | Search servers by name | web/ | web/src/routes/Servers.tsx:263-296 | [p](procedures/web.md#servers-search-by-name) | none | untested | | [e](evidence/INV-WEB-013/) | | | -| INV-WEB-014 | Filter servers by game type | web/ | web/src/routes/Servers.tsx:274-295 | [p](procedures/web.md#servers-filter-by-game) | none | untested | | [e](evidence/INV-WEB-014/) | | | -| INV-WEB-015 | Filter servers by namespace | web/ | web/src/routes/Servers.tsx:274-295 | [p](procedures/web.md#servers-filter-by-namespace) | none | untested | | [e](evidence/INV-WEB-015/) | | | -| INV-WEB-016 | Open server detail page | web/ | web/src/routes/Servers.tsx:405-411 | [p](procedures/web.md#servers-open-detail) | none | untested | | [e](evidence/INV-WEB-016/) | | | -| INV-WEB-017 | Start stopped server from list | web/ | web/src/routes/Servers.tsx:626-633 | [p](procedures/web.md#servers-start-server) | TestAPI_LifecycleStartStop, TestGameServer_HeartbeatReachesRunning | untested | | [e](evidence/INV-WEB-017/) | | | -| INV-WEB-018 | Stop running server from list | web/ | web/src/routes/Servers.tsx:634-644 | [p](procedures/web.md#servers-stop-server) | TestAPI_LifecycleStartStop | untested | | [e](evidence/INV-WEB-018/) | | | -| INV-WEB-019 | Restart running server from list | web/ | web/src/routes/Servers.tsx:645-650 | [p](procedures/web.md#servers-restart-server) | TestAPI_LifecycleRestart | untested | | [e](evidence/INV-WEB-019/) | | | -| INV-WEB-020 | Wake sleeping server from list | web/ | web/src/routes/Servers.tsx:617-625 | [p](procedures/web.md#servers-wake-sleeping-server) | TestGameServer_WakeOnConnect_LoginWakes | untested | | [e](evidence/INV-WEB-020/) | | | -| INV-WEB-021 | Access server actions menu (edit, transfer, delete) | web/ | web/src/routes/Servers.tsx:651 | [p](procedures/web.md#servers-menu-actions) | none | untested | | [e](evidence/INV-WEB-021/) | | | -| INV-WEB-022 | View server overview (metrics, players, endpoints, events) | web/ | web/src/routes/tabs/Overview.tsx:15-200 | [p](procedures/web.md#server-detail-overview-tab) | none | untested | | [e](evidence/INV-WEB-022/) | | | -| INV-WEB-023 | Start server from detail page | web/ | web/src/routes/ServerDetail.tsx:227-235 | [p](procedures/web.md#server-detail-lifecycle-start) | TestAPI_LifecycleStartStop | untested | | [e](evidence/INV-WEB-023/) | | | -| INV-WEB-024 | Stop server from detail page | web/ | web/src/routes/ServerDetail.tsx:209-216 | [p](procedures/web.md#server-detail-lifecycle-stop) | TestAPI_LifecycleStartStop | untested | | [e](evidence/INV-WEB-024/) | | | -| INV-WEB-025 | Restart server from detail page | web/ | web/src/routes/ServerDetail.tsx:201-208 | [p](procedures/web.md#server-detail-lifecycle-restart) | TestAPI_LifecycleStartStop | untested | | [e](evidence/INV-WEB-025/) | | | -| INV-WEB-026 | Wake sleeping server from detail page | web/ | web/src/routes/ServerDetail.tsx:217-226 | [p](procedures/web.md#server-detail-lifecycle-wake) | TestGameServer_WakeOnConnect_LoginWakes | untested | | [e](evidence/INV-WEB-026/) | | | -| INV-WEB-027 | Open console tab from detail page | web/ | web/src/routes/ServerDetail.tsx:237-241 | [p](procedures/web.md#server-detail-open-console) | TestAPI_ConsolePTYRoundTrip | untested | | [e](evidence/INV-WEB-027/) | | | -| INV-WEB-028 | Send command in console (PTY/RCON) | web/ | web/src/routes/tabs/Console.tsx:48-100 | [p](procedures/web.md#server-detail-console-send-command) | TestAPI_ConsolePTYRoundTrip, TestGameServer_Squad_RCON | untested | | [e](evidence/INV-WEB-028/) | | | -| INV-WEB-029 | View pod container logs | web/ | web/src/routes/tabs/Logs.tsx:73-100 | [p](procedures/web.md#server-detail-logs-view-pod-logs) | TestAPI_LogsTailWS | untested | | [e](evidence/INV-WEB-029/) | | | -| INV-WEB-030 | View game log file | web/ | web/src/routes/tabs/Logs.tsx:71 | [p](procedures/web.md#server-detail-logs-view-game-logs) | TestAPI_LogsTailWS | untested | | [e](evidence/INV-WEB-030/) | | | -| INV-WEB-031 | Filter logs by level (INFO, WARN, ERROR, DEBUG) | web/ | web/src/routes/tabs/Logs.tsx:56-58 | [p](procedures/web.md#server-detail-logs-filter-by-level) | none | untested | | [e](evidence/INV-WEB-031/) | | | -| INV-WEB-032 | Download logs | web/ | web/src/routes/tabs/Logs.tsx:56-100 | [p](procedures/web.md#server-detail-logs-download) | none | untested | | [e](evidence/INV-WEB-032/) | | | -| INV-WEB-033 | Browse server files | web/ | web/src/routes/tabs/Files.tsx:42-100 | [p](procedures/web.md#server-detail-files-browse) | TestAPI_AgentFilesRoundTrip | untested | | [e](evidence/INV-WEB-033/) | | | -| INV-WEB-034 | View file content in editor | web/ | web/src/routes/tabs/Files.tsx:73-95 | [p](procedures/web.md#server-detail-files-view-file) | TestAPI_AgentFilesRoundTrip | untested | | [e](evidence/INV-WEB-034/) | | | -| INV-WEB-035 | Edit and save file | web/ | web/src/routes/tabs/Files.tsx:42-100 | [p](procedures/web.md#server-detail-files-edit-file) | TestAPI_AgentFilesRoundTrip | untested | | [e](evidence/INV-WEB-035/) | | | -| INV-WEB-036 | Upload file to server | web/ | web/src/routes/tabs/Files.tsx:62 | [p](procedures/web.md#server-detail-files-upload-file) | TestAPI_AgentFilesRoundTrip | untested | | [e](evidence/INV-WEB-036/) | | | -| INV-WEB-037 | Create new file | web/ | web/src/routes/tabs/Files.tsx:59-60 | [p](procedures/web.md#server-detail-files-create-file) | TestAPI_AgentFilesRoundTrip | untested | | [e](evidence/INV-WEB-037/) | | | -| INV-WEB-038 | Create new directory | web/ | web/src/routes/tabs/Files.tsx:59 | [p](procedures/web.md#server-detail-files-create-directory) | TestAPI_AgentFilesRoundTrip | untested | | [e](evidence/INV-WEB-038/) | | | -| INV-WEB-039 | Delete file or directory | web/ | web/src/routes/tabs/Files.tsx:58 | [p](procedures/web.md#server-detail-files-delete-file) | TestAPI_AgentFilesRoundTrip | untested | | [e](evidence/INV-WEB-039/) | | | -| INV-WEB-040 | Download file from server | web/ | web/src/routes/tabs/Files.tsx:42-100 | [p](procedures/web.md#server-detail-files-download-file) | TestAPI_AgentFilesRoundTrip | untested | | [e](evidence/INV-WEB-040/) | | | -| INV-WEB-041 | View Kubernetes events | web/ | web/src/routes/tabs/Events.tsx:11-40 | [p](procedures/web.md#server-detail-events-view) | none | untested | | [e](evidence/INV-WEB-041/) | | | -| INV-WEB-042 | Filter events by type (all, info, warnings) | web/ | web/src/routes/tabs/Events.tsx:34-39 | [p](procedures/web.md#server-detail-events-filter) | none | untested | | [e](evidence/INV-WEB-042/) | | | -| INV-WEB-043 | List installed mods | web/ | web/src/routes/tabs/Mods.tsx:55-100 | [p](procedures/web.md#server-detail-mods-list) | TestAPI_ModManifestInstallUpgrade | untested | | [e](evidence/INV-WEB-043/) | | | -| INV-WEB-044 | Install mod from URL | web/ | web/src/routes/tabs/Mods.tsx:65-100 | [p](procedures/web.md#server-detail-mods-install-url) | TestAPI_ModManifestInstallUpgrade, TestAPI_ModUpload | untested | | [e](evidence/INV-WEB-044/) | | | -| INV-WEB-045 | Browse mod registry | web/ | web/src/routes/tabs/Mods.tsx:65-100 | [p](procedures/web.md#server-detail-mods-browse-registry) | TestAPI_ModManifestInstallUpgrade | untested | | [e](evidence/INV-WEB-045/) | | | -| INV-WEB-046 | Install mod from registry | web/ | web/src/routes/tabs/Mods.tsx:65-100 | [p](procedures/web.md#server-detail-mods-install-registry) | TestAPI_ModManifestInstallUpgrade, TestAPI_ModUpload | untested | | [e](evidence/INV-WEB-046/) | | | -| INV-WEB-047 | Upload custom mod file | web/ | web/src/routes/tabs/Mods.tsx:65-100 | [p](procedures/web.md#server-detail-mods-upload) | TestAPI_ModUpload | untested | | [e](evidence/INV-WEB-047/) | | | -| INV-WEB-048 | Check for mod updates | web/ | web/src/routes/tabs/Mods.tsx:100 | [p](procedures/web.md#server-detail-mods-check-updates) | none | untested | | [e](evidence/INV-WEB-048/) | | | -| INV-WEB-049 | Remove installed mod | web/ | web/src/routes/tabs/Mods.tsx:65-100 | [p](procedures/web.md#server-detail-mods-remove) | TestAPI_ModManifestInstallUpgrade | untested | | [e](evidence/INV-WEB-049/) | | | -| INV-WEB-050 | Browse modpacks in registry | web/ | web/src/routes/tabs/Modpacks.tsx:29-100 | [p](procedures/web.md#server-detail-modpacks-browse) | none | untested | | [e](evidence/INV-WEB-050/) | | | -| INV-WEB-051 | Install modpack | web/ | web/src/routes/tabs/Modpacks.tsx:29-100 | [p](procedures/web.md#server-detail-modpacks-install) | TestAPI_ModManifestInstallUpgrade, TestAPI_ModUpload | untested | | [e](evidence/INV-WEB-051/) | | | -| INV-WEB-052 | View online players | web/ | web/src/routes/tabs/Players.tsx:28-100 | [p](procedures/web.md#server-detail-players-view) | TestAPI_AgentPlayers | untested | | [e](evidence/INV-WEB-052/) | | | -| INV-WEB-053 | Kick player from server | web/ | web/src/routes/tabs/Players.tsx:28-100 | [p](procedures/web.md#server-detail-players-kick) | TestAPI_AgentPlayers | untested | | [e](evidence/INV-WEB-053/) | | | -| INV-WEB-054 | Ban player | web/ | web/src/routes/tabs/Players.tsx:28-100 | [p](procedures/web.md#server-detail-players-ban) | TestAPI_AgentPlayers | untested | | [e](evidence/INV-WEB-054/) | | | -| INV-WEB-055 | Unban player | web/ | web/src/routes/tabs/Players.tsx:28-100 | [p](procedures/web.md#server-detail-players-unban) | TestAPI_AgentPlayers | untested | | [e](evidence/INV-WEB-055/) | | | -| INV-WEB-056 | Add player to whitelist | web/ | web/src/routes/tabs/Players.tsx:28-100 | [p](procedures/web.md#server-detail-players-whitelist-add) | TestAPI_AgentPlayers | untested | | [e](evidence/INV-WEB-056/) | | | -| INV-WEB-057 | Remove player from whitelist | web/ | web/src/routes/tabs/Players.tsx:28-100 | [p](procedures/web.md#server-detail-players-whitelist-remove) | TestAPI_AgentPlayers | untested | | [e](evidence/INV-WEB-057/) | | | -| INV-WEB-058 | Create backup now (from server detail) | web/ | web/src/routes/tabs/Backups.tsx:42-50 | [p](procedures/web.md#server-detail-backups-create-now) | TestBackup_OperatorMaterializesJob, TestRestore_RoundTrip | untested | | [e](evidence/INV-WEB-058/) | | | -| INV-WEB-059 | View server backups list | web/ | web/src/routes/tabs/Backups.tsx:16-100 | [p](procedures/web.md#server-detail-backups-view-list) | TestBackupSchedule_CreatesBackupCR | untested | | [e](evidence/INV-WEB-059/) | | | -| INV-WEB-060 | Restore from backup | web/ | web/src/routes/tabs/Backups.tsx:16-100 | [p](procedures/web.md#server-detail-backups-restore) | TestRestore_RoundTrip | untested | | [e](evidence/INV-WEB-060/) | | | -| INV-WEB-061 | Create backup schedule | web/ | web/src/routes/tabs/Backups.tsx:16-100 | [p](procedures/web.md#server-detail-backups-schedule-create) | TestBackup_OperatorMaterializesJob, TestRestore_RoundTrip | untested | | [e](evidence/INV-WEB-061/) | | | -| INV-WEB-062 | Delete backup schedule | web/ | web/src/routes/tabs/Backups.tsx:16-100 | [p](procedures/web.md#server-detail-backups-schedule-delete) | TestBackupSchedule_CreatesBackupCR | untested | | [e](evidence/INV-WEB-062/) | | | -| INV-WEB-063 | Edit server general settings (name, description, labels) | web/ | web/src/routes/tabs/settings/General.tsx:7-100 | [p](procedures/web.md#server-detail-settings-general) | none | untested | | [e](evidence/INV-WEB-063/) | | | -| INV-WEB-064 | Change server version | web/ | web/src/routes/tabs/settings/Version.tsx:1-50 | [p](procedures/web.md#server-detail-settings-version) | TestGameServer_VersionSwitch | untested | | [e](evidence/INV-WEB-064/) | | | -| INV-WEB-065 | Edit server resources (CPU, memory, storage) | web/ | web/src/routes/tabs/settings/Resources.tsx:1-50 | [p](procedures/web.md#server-detail-settings-resources) | none | untested | | [e](evidence/INV-WEB-065/) | | | -| INV-WEB-066 | Edit server networking (exposure, hostname, ports, tunnel) | web/ | web/src/routes/tabs/settings/Networking.tsx:1-50 | [p](procedures/web.md#server-detail-settings-networking) | none | untested | | [e](evidence/INV-WEB-066/) | | | -| INV-WEB-067 | Edit server environment variables | web/ | web/src/routes/tabs/settings/EnvVars.tsx:1-50 | [p](procedures/web.md#server-detail-settings-environment) | none | untested | | [e](evidence/INV-WEB-067/) | | | -| INV-WEB-068 | Edit server lifecycle policies (auto-restart, updates, idle sleep) | web/ | web/src/routes/tabs/settings/Lifecycle.tsx:1-50 | [p](procedures/web.md#server-detail-settings-lifecycle) | TestGameServer_IdleNeverSleepsWithoutAPlayerCount | untested | | [e](evidence/INV-WEB-068/) | | | -| INV-WEB-069 | Manage server backup schedules in settings | web/ | web/src/routes/tabs/settings/Backups.tsx:1-50 | [p](procedures/web.md#server-detail-settings-scheduled-backups) | none | untested | | [e](evidence/INV-WEB-069/) | | | -| INV-WEB-070 | Configure network packet capture | web/ | web/src/routes/tabs/settings/NetworkCapture.tsx:1-50 | [p](procedures/web.md#server-detail-settings-network-capture) | TestGameServer_NetworkCaptureStartStopDownload | untested | | [e](evidence/INV-WEB-070/) | | | -| INV-WEB-071 | Configure node placement (affinity, anti-affinity) | web/ | web/src/routes/tabs/settings/Placement.tsx:1-50 | [p](procedures/web.md#server-detail-settings-placement) | none | untested | | [e](evidence/INV-WEB-071/) | | | -| INV-WEB-072 | Manage server RBAC and access (role bindings) | web/ | web/src/routes/tabs/settings/Access.tsx:1-50 | [p](procedures/web.md#server-detail-settings-access) | TestAPI_RBAC_OperatorCanWriteServers_NotUsers | untested | | [e](evidence/INV-WEB-072/) | | | -| INV-WEB-073 | Create share link with expiry | web/ | web/src/routes/tabs/settings/ShareLinks.tsx:1-100 | [p](procedures/web.md#server-detail-settings-sharelinks-create) | none | untested | | [e](evidence/INV-WEB-073/) | | | -| INV-WEB-074 | View share links list | web/ | web/src/routes/tabs/settings/ShareLinks.tsx:1-100 | [p](procedures/web.md#server-detail-settings-sharelinks-view) | none | untested | | [e](evidence/INV-WEB-074/) | | | -| INV-WEB-075 | Revoke share link | web/ | web/src/routes/tabs/settings/ShareLinks.tsx:1-100 | [p](procedures/web.md#server-detail-settings-sharelinks-revoke) | none | untested | | [e](evidence/INV-WEB-075/) | | | -| INV-WEB-076 | Delete server | web/ | web/src/routes/tabs/settings/Danger.tsx:1-50 | [p](procedures/web.md#server-detail-settings-danger-delete) | TestGameServer_CascadingDelete | untested | | [e](evidence/INV-WEB-076/) | | | -| INV-WEB-077 | Transfer server ownership | web/ | web/src/routes/tabs/settings/Danger.tsx:1-50 | [p](procedures/web.md#server-detail-settings-danger-transfer) | TestAPI_OwnerCollaboratorAccess | untested | | [e](evidence/INV-WEB-077/) | | | -| INV-WEB-078 | Browse module catalog | web/ | web/src/routes/Modules.tsx:24-100 | [p](procedures/web.md#modules-catalog-browse) | TestModuleSourceAndModule | untested | | [e](evidence/INV-WEB-078/) | | | -| INV-WEB-079 | Search modules by name | web/ | web/src/routes/Modules.tsx:36 | [p](procedures/web.md#modules-search) | TestModuleSourceAndModule | untested | | [e](evidence/INV-WEB-079/) | | | -| INV-WEB-080 | Filter modules by source | web/ | web/src/routes/Modules.tsx:37 | [p](procedures/web.md#modules-filter-by-source) | TestModuleSourceAndModule | untested | | [e](evidence/INV-WEB-080/) | | | -| INV-WEB-081 | Filter modules by category | web/ | web/src/routes/Modules.tsx:38 | [p](procedures/web.md#modules-filter-by-category) | TestModuleSourceAndModule | untested | | [e](evidence/INV-WEB-081/) | | | -| INV-WEB-082 | Install module | web/ | web/src/routes/Modules.tsx:89-98 | [p](procedures/web.md#modules-install) | TestAPI_ModManifestInstallUpgrade, TestAPI_ModUpload | untested | | [e](evidence/INV-WEB-082/) | | | -| INV-WEB-083 | Upgrade module | web/ | web/src/routes/Modules.tsx:100 | [p](procedures/web.md#modules-upgrade) | TestModuleSourceAndModule | untested | | [e](evidence/INV-WEB-083/) | | | -| INV-WEB-084 | Uninstall module | web/ | web/src/routes/Modules.tsx:100 | [p](procedures/web.md#modules-uninstall) | TestAPI_ModManifestInstallUpgrade, TestAPI_ModUpload | untested | | [e](evidence/INV-WEB-084/) | | | -| INV-WEB-085 | Upload custom module | web/ | web/src/routes/Modules.tsx:42 | [p](procedures/web.md#modules-upload-custom) | TestAPI_ModUpload | untested | | [e](evidence/INV-WEB-085/) | | | -| INV-WEB-086 | Build custom module | web/ | web/src/routes/Modules.tsx:43 | [p](procedures/web.md#modules-build-custom) | none | untested | | [e](evidence/INV-WEB-086/) | | | -| INV-WEB-087 | View cluster nodes | web/ | web/src/routes/Cluster.tsx:25-100 | [p](procedures/web.md#cluster-view-nodes) | none | untested | | [e](evidence/INV-WEB-087/) | | | -| INV-WEB-088 | Download cluster kubeconfig | web/ | web/src/routes/Cluster.tsx:61-76 | [p](procedures/web.md#cluster-download-kubeconfig) | none | untested | | [e](evidence/INV-WEB-088/) | | | -| INV-WEB-089 | Add node to cluster | web/ | web/src/routes/Cluster.tsx:52-59 | [p](procedures/web.md#cluster-add-node) | none | untested | | [e](evidence/INV-WEB-089/) | | | -| INV-WEB-090 | List users | web/ | web/src/routes/Users.tsx:83-100 | [p](procedures/web.md#users-list-view) | TestAPI_RBAC_AdminCanReachAll | untested | | [e](evidence/INV-WEB-090/) | | | -| INV-WEB-091 | Invite user | web/ | web/src/routes/Users.tsx:100 | [p](procedures/web.md#users-invite) | TestAPI_OperatorCannotInviteUsers | untested | | [e](evidence/INV-WEB-091/) | | | -| INV-WEB-092 | Edit user role | web/ | web/src/routes/Users.tsx:100 | [p](procedures/web.md#users-edit-role) | TestAPI_CustomRole_Lifecycle | untested | | [e](evidence/INV-WEB-092/) | | | -| INV-WEB-093 | Reset user password | web/ | web/src/routes/Users.tsx:100 | [p](procedures/web.md#users-reset-password) | none | untested | | [e](evidence/INV-WEB-093/) | | | -| INV-WEB-094 | Delete user | web/ | web/src/routes/Users.tsx:100 | [p](procedures/web.md#users-delete) | none | untested | | [e](evidence/INV-WEB-094/) | | | -| INV-WEB-095 | Manage custom roles | web/ | web/src/routes/Users.tsx:100 | [p](procedures/web.md#users-manage-roles) | none | untested | | [e](evidence/INV-WEB-095/) | | | -| INV-WEB-096 | Manage service accounts | web/ | web/src/routes/Users.tsx:100 | [p](procedures/web.md#users-manage-service-accounts) | none | untested | | [e](evidence/INV-WEB-096/) | | | -| INV-WEB-097 | Manage OIDC providers | web/ | web/src/routes/Users.tsx:100 | [p](procedures/web.md#users-manage-oidc-providers) | none | untested | | [e](evidence/INV-WEB-097/) | | | -| INV-WEB-098 | Edit general admin settings | web/ | web/src/routes/AdminSettings.tsx:89-142 | [p](procedures/web.md#admin-settings-general) | none | untested | | [e](evidence/INV-WEB-098/) | | | -| INV-WEB-099 | Configure authentication (local, SSO, OIDC) | web/ | web/src/routes/AdminSettings.tsx:89-142 | [p](procedures/web.md#admin-settings-auth) | none | untested | | [e](evidence/INV-WEB-099/) | | | -| INV-WEB-100 | Configure backup destinations | web/ | web/src/routes/AdminSettings.tsx:131 | [p](procedures/web.md#admin-settings-backup-destinations) | none | untested | | [e](evidence/INV-WEB-100/) | | | -| INV-WEB-101 | Manage module sources | web/ | web/src/routes/AdminSettings.tsx:132 | [p](procedures/web.md#admin-settings-module-sources) | none | untested | | [e](evidence/INV-WEB-101/) | | | -| INV-WEB-102 | Configure mod registries | web/ | web/src/routes/AdminSettings.tsx:133 | [p](procedures/web.md#admin-settings-mod-registries) | none | untested | | [e](evidence/INV-WEB-102/) | | | -| INV-WEB-103 | Configure notifications (Slack, email, webhook) | web/ | web/src/routes/AdminSettings.tsx:134 | [p](procedures/web.md#admin-settings-notifications) | none | untested | | [e](evidence/INV-WEB-103/) | | | -| INV-WEB-104 | Configure telemetry collection | web/ | web/src/routes/AdminSettings.tsx:135 | [p](procedures/web.md#admin-settings-telemetry) | none | untested | | [e](evidence/INV-WEB-104/) | | | -| INV-WEB-105 | View update availability | web/ | web/src/routes/AdminSettings.tsx:136 | [p](procedures/web.md#admin-settings-updates) | none | untested | | [e](evidence/INV-WEB-105/) | | | -| INV-WEB-106 | View about information (version, build, license) | web/ | web/src/routes/AdminSettings.tsx:137 | [p](procedures/web.md#admin-settings-about) | none | untested | | [e](evidence/INV-WEB-106/) | | | -| INV-WEB-107 | Select theme preset | web/ | web/src/routes/ThemeSettings.tsx:50-59 | [p](procedures/web.md#theme-settings-preset-selection) | none | untested | | [e](evidence/INV-WEB-107/) | | | -| INV-WEB-108 | Select appearance mode (light, dark, system) | web/ | web/src/routes/ThemeSettings.tsx:81-85 | [p](procedures/web.md#theme-settings-appearance-mode) | none | untested | | [e](evidence/INV-WEB-108/) | | | -| INV-WEB-109 | Select custom theme colors | web/ | web/src/routes/ThemeSettings.tsx:64-79 | [p](procedures/web.md#theme-settings-custom-colors) | none | untested | | [e](evidence/INV-WEB-109/) | | | -| INV-WEB-110 | Edit custom CSS | web/ | web/src/routes/ThemeSettings.tsx:87-100 | [p](procedures/web.md#theme-settings-custom-css) | none | untested | | [e](evidence/INV-WEB-110/) | | | -| INV-WEB-111 | Export theme configuration | web/ | web/src/routes/ThemeSettings.tsx:100 | [p](procedures/web.md#theme-settings-export) | none | untested | | [e](evidence/INV-WEB-111/) | | | -| INV-WEB-112 | Import theme configuration | web/ | web/src/routes/ThemeSettings.tsx:100 | [p](procedures/web.md#theme-settings-import) | none | untested | | [e](evidence/INV-WEB-112/) | | | -| INV-WEB-113 | List all backups | web/ | web/src/routes/Backups.tsx:53-100 | [p](procedures/web.md#backups-list-view) | none | untested | | [e](evidence/INV-WEB-113/) | | | -| INV-WEB-114 | Filter backups by server | web/ | web/src/routes/Backups.tsx:91-100 | [p](procedures/web.md#backups-filter-by-server) | none | untested | | [e](evidence/INV-WEB-114/) | | | -| INV-WEB-115 | Filter backups by phase | web/ | web/src/routes/Backups.tsx:91-100 | [p](procedures/web.md#backups-filter-by-phase) | none | untested | | [e](evidence/INV-WEB-115/) | | | -| INV-WEB-116 | Create backup now from backups page | web/ | web/src/routes/Backups.tsx:53-100 | [p](procedures/web.md#backups-backup-now) | TestBackup_OperatorMaterializesJob, TestRestore_RoundTrip | untested | | [e](evidence/INV-WEB-116/) | | | -| INV-WEB-117 | Restore from backup on backups page | web/ | web/src/routes/Backups.tsx:53-100 | [p](procedures/web.md#backups-restore) | TestRestore_RoundTrip | untested | | [e](evidence/INV-WEB-117/) | | | -| INV-WEB-118 | View backup detail | web/ | web/src/routes/Backups.tsx:53-100 | [p](procedures/web.md#backups-view-detail) | none | untested | | [e](evidence/INV-WEB-118/) | | | -| INV-WEB-119 | Create backup schedule on backups page | web/ | web/src/routes/Backups.tsx:53-100 | [p](procedures/web.md#backups-schedules-create) | TestBackup_OperatorMaterializesJob, TestRestore_RoundTrip | untested | | [e](evidence/INV-WEB-119/) | | | -| INV-WEB-120 | Edit backup schedule | web/ | web/src/routes/Backups.tsx:53-100 | [p](procedures/web.md#backups-schedules-edit) | none | untested | | [e](evidence/INV-WEB-120/) | | | -| INV-WEB-121 | Suspend/resume backup schedule | web/ | web/src/routes/Backups.tsx:53-100 | [p](procedures/web.md#backups-schedules-toggle-suspend) | none | untested | | [e](evidence/INV-WEB-121/) | | | -| INV-WEB-122 | Delete backup schedule from backups page | web/ | web/src/routes/Backups.tsx:53-100 | [p](procedures/web.md#backups-schedules-delete) | TestBackupSchedule_CreatesBackupCR | untested | | [e](evidence/INV-WEB-122/) | | | -| INV-WEB-123 | View restore operations | web/ | web/src/routes/Backups.tsx:53-100 | [p](procedures/web.md#backups-restores-view) | none | untested | | [e](evidence/INV-WEB-123/) | | | -| INV-WEB-124 | View audit log events | web/ | web/src/routes/AuditLog.tsx:16-100 | [p](procedures/web.md#audit-log-view) | none | untested | | [e](evidence/INV-WEB-124/) | | | -| INV-WEB-125 | Filter audit events by HTTP status class | web/ | web/src/routes/AuditLog.tsx:16-100 | [p](procedures/web.md#audit-log-filter-by-status-class) | none | untested | | [e](evidence/INV-WEB-125/) | | | -| INV-WEB-126 | Filter audit events by HTTP method | web/ | web/src/routes/AuditLog.tsx:16-100 | [p](procedures/web.md#audit-log-filter-by-method) | none | untested | | [e](evidence/INV-WEB-126/) | | | -| INV-WEB-127 | Filter audit events by actor | web/ | web/src/routes/AuditLog.tsx:16-100 | [p](procedures/web.md#audit-log-filter-by-actor) | none | untested | | [e](evidence/INV-WEB-127/) | | | -| INV-WEB-128 | Paginate audit log | web/ | web/src/routes/AuditLog.tsx:25-33 | [p](procedures/web.md#audit-log-pagination) | none | untested | | [e](evidence/INV-WEB-128/) | | | -| INV-WEB-129 | Export audit events to CSV | web/ | web/src/routes/AuditLog.tsx:35-46 | [p](procedures/web.md#audit-log-export-csv) | none | untested | | [e](evidence/INV-WEB-129/) | | | -| INV-WEB-130 | View audit log integrity | web/ | web/src/routes/AuditLog.tsx:20-24 | [p](procedures/web.md#audit-log-verify-integrity) | none | untested | | [e](evidence/INV-WEB-130/) | | | -| INV-WEB-131 | View API server logs | web/ | web/src/routes/AdminLogs.tsx:78-100 | [p](procedures/web.md#admin-logs-view-api) | none | untested | | [e](evidence/INV-WEB-131/) | | | -| INV-WEB-132 | View operator logs | web/ | web/src/routes/AdminLogs.tsx:78-100 | [p](procedures/web.md#admin-logs-view-operator) | none | untested | | [e](evidence/INV-WEB-132/) | | | -| INV-WEB-133 | Select log tail size | web/ | web/src/routes/AdminLogs.tsx:16-17 | [p](procedures/web.md#admin-logs-tail-option) | none | untested | | [e](evidence/INV-WEB-133/) | | | -| INV-WEB-134 | Enable follow mode for system logs | web/ | web/src/routes/AdminLogs.tsx:81 | [p](procedures/web.md#admin-logs-follow) | none | untested | | [e](evidence/INV-WEB-134/) | | | -| INV-WEB-135 | Download system logs | web/ | web/src/routes/AdminLogs.tsx:78-100 | [p](procedures/web.md#admin-logs-download) | none | untested | | [e](evidence/INV-WEB-135/) | | | -| INV-WEB-136 | Access shared server link | web/ | web/src/routes/Share.tsx:46-100 | [p](procedures/web.md#share-access-link-view) | none | untested | | [e](evidence/INV-WEB-136/) | | | -| INV-WEB-137 | Start server from share link | web/ | web/src/routes/Share.tsx:46-100 | [p](procedures/web.md#share-server-start) | none | untested | | [e](evidence/INV-WEB-137/) | | | -| INV-WEB-138 | View shared server status | web/ | web/src/routes/Share.tsx:46-100 | [p](procedures/web.md#share-server-view-status) | none | untested | | [e](evidence/INV-WEB-138/) | | | -| INV-WEB-139 | Copy server address from share link | web/ | web/src/routes/Share.tsx:46-100 | [p](procedures/web.md#share-link-copy-address) | none | untested | | [e](evidence/INV-WEB-139/) | | | -| INV-WEB-140 | Set theme preference on share link | web/ | web/src/routes/Share.tsx:17-43 | [p](procedures/web.md#share-theme-preference) | none | untested | | [e](evidence/INV-WEB-140/) | | | -| INV-WEB-141 | Select game template in create-server wizard | web/ | web/src/routes/CreateServer.tsx:541-645 | [p](procedures/web.md#create-server-wizard-pick-template) | none | untested | | [e](evidence/INV-WEB-141/) | | | -| INV-WEB-142 | Select template version in create-server wizard | web/ | web/src/routes/CreateServer.tsx:646-684 | [p](procedures/web.md#create-server-wizard-pick-version) | none | untested | | [e](evidence/INV-WEB-142/) | | | -| INV-WEB-143 | Configure server name, resources, and labels in create-server wizard | web/ | web/src/routes/CreateServer.tsx:685-823 | [p](procedures/web.md#create-server-wizard-configure) | none | untested | | [e](evidence/INV-WEB-143/) | | | -| INV-WEB-144 | Configure networking (exposure, ports, tunnel) in create-server wizard | web/ | web/src/routes/CreateServer.tsx:824-1086 | [p](procedures/web.md#create-server-wizard-network) | none | untested | | [e](evidence/INV-WEB-144/) | | | -| INV-WEB-145 | Review and submit new server from create-server wizard | web/ | web/src/routes/CreateServer.tsx:348-500 | [p](procedures/web.md#create-server-wizard-review-create) | TestAPI_LifecycleClone | untested | | [e](evidence/INV-WEB-145/) | | | +| INV-WEB-001 | Sign in with username and password | web/ | web/src/routes/Login.tsx:69-92 | [p](procedures/web.md#login-username-password) | TestAPI_BootstrapAndLogin | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-002 | Toggle password visibility on login form | web/ | web/src/routes/Login.tsx:172-186 | [p](procedures/web.md#login-toggle-password-visibility) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-003 | Sign in with SSO provider | web/ | web/src/routes/Login.tsx:295-312 | [p](procedures/web.md#login-sso-provider) | TestAPI_DynamicAuthProviders, TestAPI_OIDCHelmSeeded_AdminOnFirstLogin | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-004 | Sign in with safe mode (custom CSS disabled) | web/ | web/src/routes/Login.tsx:69-86 | [p](procedures/web.md#login-safe-mode) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-005 | Display password reset hint on login | web/ | web/src/routes/Login.tsx:151-159 | [p](procedures/web.md#login-password-forgotten-hint) | TestAPI_PasswordResetInvalidatesSession | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-006 | View fleet status card (running, stopped, failed servers) | web/ | web/src/routes/Dashboard.tsx:196-249 | [p](procedures/web.md#dashboard-view-fleet-summary) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-007 | View cluster resources metrics (CPU, memory, storage, nodes) | web/ | web/src/routes/Dashboard.tsx:296-350 | [p](procedures/web.md#dashboard-view-cluster-resources) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-008 | View recent activity (audit events) | web/ | web/src/routes/Dashboard.tsx:372-410 | [p](procedures/web.md#dashboard-view-recent-activity) | TestAPI_AuditEmitsOnMutation | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-009 | View recent backups | web/ | web/src/routes/Dashboard.tsx:412-477 | [p](procedures/web.md#dashboard-view-recent-backups) | TestBackup_OperatorMaterializesJob | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-010 | Create server from dashboard button | web/ | web/src/routes/Dashboard.tsx:113-121 | [p](procedures/web.md#dashboard-create-server-button) | TestAPI_LifecycleClone | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-011 | List all servers | web/ | web/src/routes/Servers.tsx:38-174 | [p](procedures/web.md#servers-list-view) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-012 | Filter servers by status (all, running, stopped) | web/ | web/src/routes/Servers.tsx:230-262 | [p](procedures/web.md#servers-filter-by-status) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-013 | Search servers by name | web/ | web/src/routes/Servers.tsx:263-296 | [p](procedures/web.md#servers-search-by-name) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-014 | Filter servers by game type | web/ | web/src/routes/Servers.tsx:274-295 | [p](procedures/web.md#servers-filter-by-game) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-015 | Filter servers by namespace | web/ | web/src/routes/Servers.tsx:274-295 | [p](procedures/web.md#servers-filter-by-namespace) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-016 | Open server detail page | web/ | web/src/routes/Servers.tsx:405-411 | [p](procedures/web.md#servers-open-detail) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-017 | Start stopped server from list | web/ | web/src/routes/Servers.tsx:626-633 | [p](procedures/web.md#servers-start-server) | TestAPI_LifecycleStartStop, TestGameServer_HeartbeatReachesRunning | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-018 | Stop running server from list | web/ | web/src/routes/Servers.tsx:634-644 | [p](procedures/web.md#servers-stop-server) | TestAPI_LifecycleStartStop | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-019 | Restart running server from list | web/ | web/src/routes/Servers.tsx:645-650 | [p](procedures/web.md#servers-restart-server) | TestAPI_LifecycleRestart | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-020 | Wake sleeping server from list | web/ | web/src/routes/Servers.tsx:617-625 | [p](procedures/web.md#servers-wake-sleeping-server) | TestGameServer_WakeOnConnect_LoginWakes | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-021 | Access server actions menu (edit, transfer, delete) | web/ | web/src/routes/Servers.tsx:651 | [p](procedures/web.md#servers-menu-actions) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-022 | View server overview (metrics, players, endpoints, events) | web/ | web/src/routes/tabs/Overview.tsx:15-200 | [p](procedures/web.md#server-detail-overview-tab) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-023 | Start server from detail page | web/ | web/src/routes/ServerDetail.tsx:227-235 | [p](procedures/web.md#server-detail-lifecycle-start) | TestAPI_LifecycleStartStop | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-024 | Stop server from detail page | web/ | web/src/routes/ServerDetail.tsx:209-216 | [p](procedures/web.md#server-detail-lifecycle-stop) | TestAPI_LifecycleStartStop | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-025 | Restart server from detail page | web/ | web/src/routes/ServerDetail.tsx:201-208 | [p](procedures/web.md#server-detail-lifecycle-restart) | TestAPI_LifecycleStartStop | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-026 | Wake sleeping server from detail page | web/ | web/src/routes/ServerDetail.tsx:217-226 | [p](procedures/web.md#server-detail-lifecycle-wake) | TestGameServer_WakeOnConnect_LoginWakes | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-027 | Open console tab from detail page | web/ | web/src/routes/ServerDetail.tsx:237-241 | [p](procedures/web.md#server-detail-open-console) | TestAPI_ConsolePTYRoundTrip | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-028 | Send command in console (PTY/RCON) | web/ | web/src/routes/tabs/Console.tsx:48-100 | [p](procedures/web.md#server-detail-console-send-command) | TestAPI_ConsolePTYRoundTrip, TestGameServer_Squad_RCON | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-029 | View pod container logs | web/ | web/src/routes/tabs/Logs.tsx:73-100 | [p](procedures/web.md#server-detail-logs-view-pod-logs) | TestAPI_LogsTailWS | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-030 | View game log file | web/ | web/src/routes/tabs/Logs.tsx:71 | [p](procedures/web.md#server-detail-logs-view-game-logs) | TestAPI_LogsTailWS | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-031 | Filter logs by level (INFO, WARN, ERROR, DEBUG) | web/ | web/src/routes/tabs/Logs.tsx:56-58 | [p](procedures/web.md#server-detail-logs-filter-by-level) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-032 | Download logs | web/ | web/src/routes/tabs/Logs.tsx:56-100 | [p](procedures/web.md#server-detail-logs-download) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-033 | Browse server files | web/ | web/src/routes/tabs/Files.tsx:42-100 | [p](procedures/web.md#server-detail-files-browse) | TestAPI_AgentFilesRoundTrip | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-034 | View file content in editor | web/ | web/src/routes/tabs/Files.tsx:73-95 | [p](procedures/web.md#server-detail-files-view-file) | TestAPI_AgentFilesRoundTrip | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-035 | Edit and save file | web/ | web/src/routes/tabs/Files.tsx:42-100 | [p](procedures/web.md#server-detail-files-edit-file) | TestAPI_AgentFilesRoundTrip | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-036 | Upload file to server | web/ | web/src/routes/tabs/Files.tsx:62 | [p](procedures/web.md#server-detail-files-upload-file) | TestAPI_AgentFilesRoundTrip | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-037 | Create new file | web/ | web/src/routes/tabs/Files.tsx:59-60 | [p](procedures/web.md#server-detail-files-create-file) | TestAPI_AgentFilesRoundTrip | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-038 | Create new directory | web/ | web/src/routes/tabs/Files.tsx:59 | [p](procedures/web.md#server-detail-files-create-directory) | TestAPI_AgentFilesRoundTrip | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-039 | Delete file or directory | web/ | web/src/routes/tabs/Files.tsx:58 | [p](procedures/web.md#server-detail-files-delete-file) | TestAPI_AgentFilesRoundTrip | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-040 | Download file from server | web/ | web/src/routes/tabs/Files.tsx:42-100 | [p](procedures/web.md#server-detail-files-download-file) | TestAPI_AgentFilesRoundTrip | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-041 | View Kubernetes events | web/ | web/src/routes/tabs/Events.tsx:11-40 | [p](procedures/web.md#server-detail-events-view) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-042 | Filter events by type (all, info, warnings) | web/ | web/src/routes/tabs/Events.tsx:34-39 | [p](procedures/web.md#server-detail-events-filter) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-043 | List installed mods | web/ | web/src/routes/tabs/Mods.tsx:55-100 | [p](procedures/web.md#server-detail-mods-list) | TestAPI_ModManifestInstallUpgrade | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-044 | Install mod from URL | web/ | web/src/routes/tabs/Mods.tsx:65-100 | [p](procedures/web.md#server-detail-mods-install-url) | TestAPI_ModManifestInstallUpgrade, TestAPI_ModUpload | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-045 | Browse mod registry | web/ | web/src/routes/tabs/Mods.tsx:65-100 | [p](procedures/web.md#server-detail-mods-browse-registry) | TestAPI_ModManifestInstallUpgrade | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-046 | Install mod from registry | web/ | web/src/routes/tabs/Mods.tsx:65-100 | [p](procedures/web.md#server-detail-mods-install-registry) | TestAPI_ModManifestInstallUpgrade, TestAPI_ModUpload | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-047 | Upload custom mod file | web/ | web/src/routes/tabs/Mods.tsx:65-100 | [p](procedures/web.md#server-detail-mods-upload) | TestAPI_ModUpload | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-048 | Check for mod updates | web/ | web/src/routes/tabs/Mods.tsx:100 | [p](procedures/web.md#server-detail-mods-check-updates) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-049 | Remove installed mod | web/ | web/src/routes/tabs/Mods.tsx:65-100 | [p](procedures/web.md#server-detail-mods-remove) | TestAPI_ModManifestInstallUpgrade | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-050 | Browse modpacks in registry | web/ | web/src/routes/tabs/Modpacks.tsx:29-100 | [p](procedures/web.md#server-detail-modpacks-browse) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-051 | Install modpack | web/ | web/src/routes/tabs/Modpacks.tsx:29-100 | [p](procedures/web.md#server-detail-modpacks-install) | TestAPI_ModManifestInstallUpgrade, TestAPI_ModUpload | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-052 | View online players | web/ | web/src/routes/tabs/Players.tsx:28-100 | [p](procedures/web.md#server-detail-players-view) | TestAPI_AgentPlayers | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-053 | Kick player from server | web/ | web/src/routes/tabs/Players.tsx:28-100 | [p](procedures/web.md#server-detail-players-kick) | TestAPI_AgentPlayers | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-054 | Ban player | web/ | web/src/routes/tabs/Players.tsx:28-100 | [p](procedures/web.md#server-detail-players-ban) | TestAPI_AgentPlayers | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-055 | Unban player | web/ | web/src/routes/tabs/Players.tsx:28-100 | [p](procedures/web.md#server-detail-players-unban) | TestAPI_AgentPlayers | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-056 | Add player to whitelist | web/ | web/src/routes/tabs/Players.tsx:28-100 | [p](procedures/web.md#server-detail-players-whitelist-add) | TestAPI_AgentPlayers | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-057 | Remove player from whitelist | web/ | web/src/routes/tabs/Players.tsx:28-100 | [p](procedures/web.md#server-detail-players-whitelist-remove) | TestAPI_AgentPlayers | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-058 | Create backup now (from server detail) | web/ | web/src/routes/tabs/Backups.tsx:42-50 | [p](procedures/web.md#server-detail-backups-create-now) | TestBackup_OperatorMaterializesJob, TestRestore_RoundTrip | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-059 | View server backups list | web/ | web/src/routes/tabs/Backups.tsx:16-100 | [p](procedures/web.md#server-detail-backups-view-list) | TestBackupSchedule_CreatesBackupCR | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-060 | Restore from backup | web/ | web/src/routes/tabs/Backups.tsx:16-100 | [p](procedures/web.md#server-detail-backups-restore) | TestRestore_RoundTrip | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-061 | Create backup schedule | web/ | web/src/routes/tabs/Backups.tsx:16-100 | [p](procedures/web.md#server-detail-backups-schedule-create) | TestBackup_OperatorMaterializesJob, TestRestore_RoundTrip | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-062 | Delete backup schedule | web/ | web/src/routes/tabs/Backups.tsx:16-100 | [p](procedures/web.md#server-detail-backups-schedule-delete) | TestBackupSchedule_CreatesBackupCR | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-063 | Edit server general settings (name, description, labels) | web/ | web/src/routes/tabs/settings/General.tsx:7-100 | [p](procedures/web.md#server-detail-settings-general) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-064 | Change server version | web/ | web/src/routes/tabs/settings/Version.tsx:1-50 | [p](procedures/web.md#server-detail-settings-version) | TestGameServer_VersionSwitch | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-065 | Edit server resources (CPU, memory, storage) | web/ | web/src/routes/tabs/settings/Resources.tsx:1-50 | [p](procedures/web.md#server-detail-settings-resources) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-066 | Edit server networking (exposure, hostname, ports, tunnel) | web/ | web/src/routes/tabs/settings/Networking.tsx:1-50 | [p](procedures/web.md#server-detail-settings-networking) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-067 | Edit server environment variables | web/ | web/src/routes/tabs/settings/EnvVars.tsx:1-50 | [p](procedures/web.md#server-detail-settings-environment) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-068 | Edit server lifecycle policies (auto-restart, updates, idle sleep) | web/ | web/src/routes/tabs/settings/Lifecycle.tsx:1-50 | [p](procedures/web.md#server-detail-settings-lifecycle) | TestGameServer_IdleNeverSleepsWithoutAPlayerCount | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-069 | Manage server backup schedules in settings | web/ | web/src/routes/tabs/settings/Backups.tsx:1-50 | [p](procedures/web.md#server-detail-settings-scheduled-backups) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-070 | Configure network packet capture | web/ | web/src/routes/tabs/settings/NetworkCapture.tsx:1-50 | [p](procedures/web.md#server-detail-settings-network-capture) | TestGameServer_NetworkCaptureStartStopDownload | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-071 | Configure node placement (affinity, anti-affinity) | web/ | web/src/routes/tabs/settings/Placement.tsx:1-50 | [p](procedures/web.md#server-detail-settings-placement) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-072 | Manage server RBAC and access (role bindings) | web/ | web/src/routes/tabs/settings/Access.tsx:1-50 | [p](procedures/web.md#server-detail-settings-access) | TestAPI_RBAC_OperatorCanWriteServers_NotUsers | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-073 | Create share link with expiry | web/ | web/src/routes/tabs/settings/ShareLinks.tsx:1-100 | [p](procedures/web.md#server-detail-settings-sharelinks-create) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-074 | View share links list | web/ | web/src/routes/tabs/settings/ShareLinks.tsx:1-100 | [p](procedures/web.md#server-detail-settings-sharelinks-view) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-075 | Revoke share link | web/ | web/src/routes/tabs/settings/ShareLinks.tsx:1-100 | [p](procedures/web.md#server-detail-settings-sharelinks-revoke) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-076 | Delete server | web/ | web/src/routes/tabs/settings/Danger.tsx:1-50 | [p](procedures/web.md#server-detail-settings-danger-delete) | TestGameServer_CascadingDelete | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-077 | Transfer server ownership | web/ | web/src/routes/tabs/settings/Danger.tsx:1-50 | [p](procedures/web.md#server-detail-settings-danger-transfer) | TestAPI_OwnerCollaboratorAccess | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-078 | Browse module catalog | web/ | web/src/routes/Modules.tsx:24-100 | [p](procedures/web.md#modules-catalog-browse) | TestModuleSourceAndModule | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-079 | Search modules by name | web/ | web/src/routes/Modules.tsx:36 | [p](procedures/web.md#modules-search) | TestModuleSourceAndModule | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-080 | Filter modules by source | web/ | web/src/routes/Modules.tsx:37 | [p](procedures/web.md#modules-filter-by-source) | TestModuleSourceAndModule | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-081 | Filter modules by category | web/ | web/src/routes/Modules.tsx:38 | [p](procedures/web.md#modules-filter-by-category) | TestModuleSourceAndModule | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-082 | Install module | web/ | web/src/routes/Modules.tsx:89-98 | [p](procedures/web.md#modules-install) | TestAPI_ModManifestInstallUpgrade, TestAPI_ModUpload | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-083 | Upgrade module | web/ | web/src/routes/Modules.tsx:100 | [p](procedures/web.md#modules-upgrade) | TestModuleSourceAndModule | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-084 | Uninstall module | web/ | web/src/routes/Modules.tsx:100 | [p](procedures/web.md#modules-uninstall) | TestAPI_ModManifestInstallUpgrade, TestAPI_ModUpload | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-085 | Upload custom module | web/ | web/src/routes/Modules.tsx:42 | [p](procedures/web.md#modules-upload-custom) | TestAPI_ModUpload | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-086 | Build custom module | web/ | web/src/routes/Modules.tsx:43 | [p](procedures/web.md#modules-build-custom) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-087 | View cluster nodes | web/ | web/src/routes/Cluster.tsx:25-100 | [p](procedures/web.md#cluster-view-nodes) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-088 | Download cluster kubeconfig | web/ | web/src/routes/Cluster.tsx:61-76 | [p](procedures/web.md#cluster-download-kubeconfig) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-089 | Add node to cluster | web/ | web/src/routes/Cluster.tsx:52-59 | [p](procedures/web.md#cluster-add-node) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-090 | List users | web/ | web/src/routes/Users.tsx:83-100 | [p](procedures/web.md#users-list-view) | TestAPI_RBAC_AdminCanReachAll | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-091 | Invite user | web/ | web/src/routes/Users.tsx:100 | [p](procedures/web.md#users-invite) | TestAPI_OperatorCannotInviteUsers | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-092 | Edit user role | web/ | web/src/routes/Users.tsx:100 | [p](procedures/web.md#users-edit-role) | TestAPI_CustomRole_Lifecycle | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-093 | Reset user password | web/ | web/src/routes/Users.tsx:100 | [p](procedures/web.md#users-reset-password) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-094 | Delete user | web/ | web/src/routes/Users.tsx:100 | [p](procedures/web.md#users-delete) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-095 | Manage custom roles | web/ | web/src/routes/Users.tsx:100 | [p](procedures/web.md#users-manage-roles) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-096 | Manage service accounts | web/ | web/src/routes/Users.tsx:100 | [p](procedures/web.md#users-manage-service-accounts) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-097 | Manage OIDC providers | web/ | web/src/routes/Users.tsx:100 | [p](procedures/web.md#users-manage-oidc-providers) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-098 | Edit general admin settings | web/ | web/src/routes/AdminSettings.tsx:89-142 | [p](procedures/web.md#admin-settings-general) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-099 | Configure authentication (local, SSO, OIDC) | web/ | web/src/routes/AdminSettings.tsx:89-142 | [p](procedures/web.md#admin-settings-auth) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-100 | Configure backup destinations | web/ | web/src/routes/AdminSettings.tsx:131 | [p](procedures/web.md#admin-settings-backup-destinations) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-101 | Manage module sources | web/ | web/src/routes/AdminSettings.tsx:132 | [p](procedures/web.md#admin-settings-module-sources) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-102 | Configure mod registries | web/ | web/src/routes/AdminSettings.tsx:133 | [p](procedures/web.md#admin-settings-mod-registries) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-103 | Configure notifications (Slack, email, webhook) | web/ | web/src/routes/AdminSettings.tsx:134 | [p](procedures/web.md#admin-settings-notifications) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-104 | Configure telemetry collection | web/ | web/src/routes/AdminSettings.tsx:135 | [p](procedures/web.md#admin-settings-telemetry) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-105 | View update availability | web/ | web/src/routes/AdminSettings.tsx:136 | [p](procedures/web.md#admin-settings-updates) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-106 | View about information (version, build, license) | web/ | web/src/routes/AdminSettings.tsx:137 | [p](procedures/web.md#admin-settings-about) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-107 | Select theme preset | web/ | web/src/routes/ThemeSettings.tsx:50-59 | [p](procedures/web.md#theme-settings-preset-selection) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-108 | Select appearance mode (light, dark, system) | web/ | web/src/routes/ThemeSettings.tsx:81-85 | [p](procedures/web.md#theme-settings-appearance-mode) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-109 | Select custom theme colors | web/ | web/src/routes/ThemeSettings.tsx:64-79 | [p](procedures/web.md#theme-settings-custom-colors) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-110 | Edit custom CSS | web/ | web/src/routes/ThemeSettings.tsx:87-100 | [p](procedures/web.md#theme-settings-custom-css) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-111 | Export theme configuration | web/ | web/src/routes/ThemeSettings.tsx:100 | [p](procedures/web.md#theme-settings-export) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-112 | Import theme configuration | web/ | web/src/routes/ThemeSettings.tsx:100 | [p](procedures/web.md#theme-settings-import) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-113 | List all backups | web/ | web/src/routes/Backups.tsx:53-100 | [p](procedures/web.md#backups-list-view) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-114 | Filter backups by server | web/ | web/src/routes/Backups.tsx:91-100 | [p](procedures/web.md#backups-filter-by-server) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-115 | Filter backups by phase | web/ | web/src/routes/Backups.tsx:91-100 | [p](procedures/web.md#backups-filter-by-phase) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-116 | Create backup now from backups page | web/ | web/src/routes/Backups.tsx:53-100 | [p](procedures/web.md#backups-backup-now) | TestBackup_OperatorMaterializesJob, TestRestore_RoundTrip | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-117 | Restore from backup on backups page | web/ | web/src/routes/Backups.tsx:53-100 | [p](procedures/web.md#backups-restore) | TestRestore_RoundTrip | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-118 | View backup detail | web/ | web/src/routes/Backups.tsx:53-100 | [p](procedures/web.md#backups-view-detail) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-119 | Create backup schedule on backups page | web/ | web/src/routes/Backups.tsx:53-100 | [p](procedures/web.md#backups-schedules-create) | TestBackup_OperatorMaterializesJob, TestRestore_RoundTrip | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-120 | Edit backup schedule | web/ | web/src/routes/Backups.tsx:53-100 | [p](procedures/web.md#backups-schedules-edit) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-121 | Suspend/resume backup schedule | web/ | web/src/routes/Backups.tsx:53-100 | [p](procedures/web.md#backups-schedules-toggle-suspend) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-122 | Delete backup schedule from backups page | web/ | web/src/routes/Backups.tsx:53-100 | [p](procedures/web.md#backups-schedules-delete) | TestBackupSchedule_CreatesBackupCR | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-123 | View restore operations | web/ | web/src/routes/Backups.tsx:53-100 | [p](procedures/web.md#backups-restores-view) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-124 | View audit log events | web/ | web/src/routes/AuditLog.tsx:16-100 | [p](procedures/web.md#audit-log-view) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-125 | Filter audit events by HTTP status class | web/ | web/src/routes/AuditLog.tsx:16-100 | [p](procedures/web.md#audit-log-filter-by-status-class) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-126 | Filter audit events by HTTP method | web/ | web/src/routes/AuditLog.tsx:16-100 | [p](procedures/web.md#audit-log-filter-by-method) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-127 | Filter audit events by actor | web/ | web/src/routes/AuditLog.tsx:16-100 | [p](procedures/web.md#audit-log-filter-by-actor) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-128 | Paginate audit log | web/ | web/src/routes/AuditLog.tsx:25-33 | [p](procedures/web.md#audit-log-pagination) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-129 | Export audit events to CSV | web/ | web/src/routes/AuditLog.tsx:35-46 | [p](procedures/web.md#audit-log-export-csv) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-130 | View audit log integrity | web/ | web/src/routes/AuditLog.tsx:20-24 | [p](procedures/web.md#audit-log-verify-integrity) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-131 | View API server logs | web/ | web/src/routes/AdminLogs.tsx:78-100 | [p](procedures/web.md#admin-logs-view-api) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-132 | View operator logs | web/ | web/src/routes/AdminLogs.tsx:78-100 | [p](procedures/web.md#admin-logs-view-operator) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-133 | Select log tail size | web/ | web/src/routes/AdminLogs.tsx:16-17 | [p](procedures/web.md#admin-logs-tail-option) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-134 | Enable follow mode for system logs | web/ | web/src/routes/AdminLogs.tsx:81 | [p](procedures/web.md#admin-logs-follow) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-135 | Download system logs | web/ | web/src/routes/AdminLogs.tsx:78-100 | [p](procedures/web.md#admin-logs-download) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-136 | Access shared server link | web/ | web/src/routes/Share.tsx:46-100 | [p](procedures/web.md#share-access-link-view) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-137 | Start server from share link | web/ | web/src/routes/Share.tsx:46-100 | [p](procedures/web.md#share-server-start) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-138 | View shared server status | web/ | web/src/routes/Share.tsx:46-100 | [p](procedures/web.md#share-server-view-status) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-139 | Copy server address from share link | web/ | web/src/routes/Share.tsx:46-100 | [p](procedures/web.md#share-link-copy-address) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-140 | Set theme preference on share link | web/ | web/src/routes/Share.tsx:17-43 | [p](procedures/web.md#share-theme-preference) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-141 | Select game template in create-server wizard | web/ | web/src/routes/CreateServer.tsx:541-645 | [p](procedures/web.md#create-server-wizard-pick-template) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-142 | Select template version in create-server wizard | web/ | web/src/routes/CreateServer.tsx:646-684 | [p](procedures/web.md#create-server-wizard-pick-version) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-143 | Configure server name, resources, and labels in create-server wizard | web/ | web/src/routes/CreateServer.tsx:685-823 | [p](procedures/web.md#create-server-wizard-configure) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-144 | Configure networking (exposure, ports, tunnel) in create-server wizard | web/ | web/src/routes/CreateServer.tsx:824-1086 | [p](procedures/web.md#create-server-wizard-network) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-WEB-145 | Review and submit new server from create-server wizard | web/ | web/src/routes/CreateServer.tsx:348-500 | [p](procedures/web.md#create-server-wizard-review-create) | TestAPI_LifecycleClone | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | | ID | Capability | Component | Source | Procedure | CI test | Outcome | Reason | Evidence | Round | Findings | |----|------------|-----------|--------|-----------|---------|---------|--------|----------|-------|----------| ## API | ID | Capability | Component | Source | Procedure | CI test | Outcome | Reason | Evidence | Round | Findings | |----|------------|-----------|--------|-----------|---------|---------|--------|----------|-------|----------| -| INV-API-001 | Health check (read) | api/ | api/cmd/main.go:257 | [p](procedures/api.md#public-healthz-get) | none | untested | | [e](evidence/INV-API-001/) | | | -| INV-API-002 | Metrics (read) | api/ | api/cmd/main.go:260 | [p](procedures/api.md#public-metrics-get) | none | untested | | [e](evidence/INV-API-002/) | | | -| INV-API-003 | List auth providers (read) | api/ | api/cmd/main.go:267 | [p](procedures/api.md#public-auth-providers-list) | none | untested | | [e](evidence/INV-API-003/) | | | -| INV-API-004 | Login (create session) | api/ | api/cmd/main.go:271 | [p](procedures/api.md#public-auth-login) | none | untested | | [e](evidence/INV-API-004/) | | | -| INV-API-005 | Logout (destroy session) | api/ | api/cmd/main.go:272 | [p](procedures/api.md#public-auth-logout) | none | untested | | [e](evidence/INV-API-005/) | | | -| INV-API-006 | OIDC authorize start | api/ | api/cmd/main.go:277 | [p](procedures/api.md#public-auth-oidc-provider-start) | none | untested | | [e](evidence/INV-API-006/) | | | -| INV-API-007 | OIDC callback | api/ | api/cmd/main.go:278-279 | [p](procedures/api.md#public-auth-oidc-callback) | none | untested | blocked: external IdP | [e](evidence/INV-API-007/) | | | -| INV-API-008 | OIDC authorize start (legacy) | api/ | api/cmd/main.go:283 | [p](procedures/api.md#public-auth-oidc-provider-start) | none | untested | | [e](evidence/INV-API-008/) | | | -| INV-API-009 | OIDC callback (legacy) | api/ | api/cmd/main.go:284-285 | [p](procedures/api.md#public-auth-oidc-callback) | none | untested | blocked: external IdP | [e](evidence/INV-API-009/) | | | -| INV-API-010 | Resolve public share link | api/ | api/internal/handlers/shares.go:40 | [p](procedures/api.md#public-shares-resolve) | none | untested | | [e](evidence/INV-API-010/) | | | -| INV-API-011 | Start server from public share | api/ | api/internal/handlers/shares.go:41 | [p](procedures/api.md#public-shares-start) | none | untested | blocked: share creation requires auth | [e](evidence/INV-API-011/) | | | -| INV-API-012 | List servers | api/ | api/internal/handlers/resources.go:53-54 | [p](procedures/api.md#servers-list) | none | untested | | [e](evidence/INV-API-012/) | | | -| INV-API-013 | Create server | api/ | api/internal/handlers/resources.go:55 | [p](procedures/api.md#servers-create) | none | untested | | [e](evidence/INV-API-013/) | | | -| INV-API-014 | Get server | api/ | api/internal/handlers/resources.go:56 | [p](procedures/api.md#servers-get) | none | untested | | [e](evidence/INV-API-014/) | | | -| INV-API-015 | Update server | api/ | api/internal/handlers/resources.go:57 | [p](procedures/api.md#servers-update) | none | untested | | [e](evidence/INV-API-015/) | | | -| INV-API-016 | Delete server | api/ | api/internal/handlers/resources.go:58 | [p](procedures/api.md#servers-delete) | TestGameServer_CascadingDelete | untested | | [e](evidence/INV-API-016/) | | | -| INV-API-017 | List templates | api/ | api/internal/handlers/resources.go:53-54 | [p](procedures/api.md#templates-list) | none | untested | | [e](evidence/INV-API-017/) | | | -| INV-API-018 | Get template | api/ | api/internal/handlers/resources.go:56 | [p](procedures/api.md#templates-get) | none | untested | | [e](evidence/INV-API-018/) | | | -| INV-API-019 | List backups | api/ | api/internal/handlers/resources.go:53-54 | [p](procedures/api.md#backups-list) | none | untested | | [e](evidence/INV-API-019/) | | | -| INV-API-020 | Create backup | api/ | api/internal/handlers/resources.go:55 | [p](procedures/api.md#servers-create) | TestBackup_OperatorMaterializesJob, TestRestore_RoundTrip | untested | blocked: requires backup trigger; alternative: list backups | [e](evidence/INV-API-020/) | | | -| INV-API-021 | Get backup | api/ | api/internal/handlers/resources.go:56 | [p](procedures/api.md#servers-get) | none | untested | | [e](evidence/INV-API-021/) | | | -| INV-API-022 | Delete backup | api/ | api/internal/handlers/resources.go:58 | [p](procedures/api.md#servers-delete) | none | untested | | [e](evidence/INV-API-022/) | | | -| INV-API-023 | List schedules | api/ | api/internal/handlers/resources.go:53-54 | [p](procedures/api.md#schedules-list) | none | untested | | [e](evidence/INV-API-023/) | | | -| INV-API-024 | Create schedule | api/ | api/internal/handlers/resources.go:55 | [p](procedures/api.md#servers-create) | none | untested | | [e](evidence/INV-API-024/) | | | -| INV-API-025 | List restores | api/ | api/internal/handlers/resources.go:53-54 | [p](procedures/api.md#restores-list) | none | untested | | [e](evidence/INV-API-025/) | | | -| INV-API-026 | Restore from backup | api/ | api/internal/handlers/resources.go:55 | [p](procedures/api.md#servers-create) | TestRestore_RoundTrip | untested | blocked: requires backup; alternative: list restores | [e](evidence/INV-API-026/) | | | -| INV-API-027 | Read audit log (paginated) | api/ | api/internal/handlers/audit.go:23 | [p](procedures/api.md#audit-read-paginated) | none | untested | | [e](evidence/INV-API-027/) | | | -| INV-API-028 | Verify audit chain integrity | api/ | api/internal/handlers/audit.go:42 | [p](procedures/api.md#audit-verify-chain) | none | untested | | [e](evidence/INV-API-028/) | | | -| INV-API-029 | Export audit log (CSV) | api/ | api/internal/handlers/audit.go:58 | [p](procedures/api.md#audit-export-csv) | none | untested | | [e](evidence/INV-API-029/) | | | -| INV-API-030 | Export audit log (JSON) | api/ | api/internal/handlers/audit.go:58 | [p](procedures/api.md#audit-export-json) | none | untested | | [e](evidence/INV-API-030/) | | | -| INV-API-031 | Read admin config | api/ | api/internal/handlers/config.go:53 | [p](procedures/api.md#config-read-all) | none | untested | | [e](evidence/INV-API-031/) | | | -| INV-API-032 | Write admin config section | api/ | api/internal/handlers/config.go:54 | [p](procedures/api.md#config-write-section) | none | untested | | [e](evidence/INV-API-032/) | | | -| INV-API-033 | Reset role mapping (auth config) | api/ | api/internal/handlers/config.go:55 | [p](procedures/api.md#config-write-section) | none | untested | | [e](evidence/INV-API-033/) | | | -| INV-API-034 | Store OIDC provider secret | api/ | api/internal/handlers/auth_provider_secret.go:26 | [p](procedures/api.md#auth-provider-secret-put) | none | untested | | [e](evidence/INV-API-034/) | | | -| INV-API-035 | Delete OIDC provider secret | api/ | api/internal/handlers/auth_provider_secret.go:27 | [p](procedures/api.md#auth-provider-secret-delete) | none | untested | | [e](evidence/INV-API-035/) | | | -| INV-API-036 | Test notification sink | api/ | api/internal/handlers/notifications.go:33-34 | [p](procedures/api.md#notifications-test-sink) | none | untested | deferred: T031 | [e](evidence/INV-API-036/) | | | -| INV-API-037 | Store notification sink secret | api/ | api/internal/handlers/notifications.go:50 | [p](procedures/api.md#notifications-secret-put) | none | untested | | [e](evidence/INV-API-037/) | | | -| INV-API-038 | Delete notification sink secret | api/ | api/internal/handlers/notifications.go:51 | [p](procedures/api.md#notifications-secret-put) | none | untested | | [e](evidence/INV-API-038/) | | | -| INV-API-039 | Store mod registry secret | api/ | api/internal/handlers/registry_secret.go:24 | [p](procedures/api.md#registry-secret-put) | none | untested | | [e](evidence/INV-API-039/) | | | -| INV-API-040 | Delete mod registry secret | api/ | api/internal/handlers/registry_secret.go:25 | [p](procedures/api.md#registry-secret-put) | none | untested | | [e](evidence/INV-API-040/) | | | -| INV-API-041 | Enable network capture | api/ | api/internal/handlers/capture.go:67 | [p](procedures/api.md#capture-enable) | none | untested | | [e](evidence/INV-API-041/) | | | -| INV-API-042 | Disable network capture | api/ | api/internal/handlers/capture.go:68 | [p](procedures/api.md#capture-enable) | none | untested | | [e](evidence/INV-API-042/) | | | -| INV-API-043 | Start packet capture | api/ | api/internal/handlers/capture.go:69 | [p](procedures/api.md#capture-start) | none | untested | deferred: T031 | [e](evidence/INV-API-043/) | | | -| INV-API-044 | Stop packet capture | api/ | api/internal/handlers/capture.go:70 | [p](procedures/api.md#capture-start) | none | untested | deferred: T031 | [e](evidence/INV-API-044/) | | | -| INV-API-045 | List packet captures | api/ | api/internal/handlers/capture.go:71 | [p](procedures/api.md#capture-list) | none | untested | deferred: T031 | [e](evidence/INV-API-045/) | | | -| INV-API-046 | Get packet capture | api/ | api/internal/handlers/capture.go:72 | [p](procedures/api.md#capture-list) | none | untested | deferred: T031 | [e](evidence/INV-API-046/) | | | -| INV-API-047 | Download capture file | api/ | api/internal/handlers/capture.go:73 | [p](procedures/api.md#capture-list) | none | untested | deferred: T031 | [e](evidence/INV-API-047/) | | | -| INV-API-048 | Delete packet capture | api/ | api/internal/handlers/capture.go:74 | [p](procedures/api.md#capture-list) | none | untested | deferred: T031 | [e](evidence/INV-API-048/) | | | -| INV-API-049 | Start server | api/ | api/internal/handlers/lifecycle.go:41 | [p](procedures/api.md#servers-start) | none | untested | | [e](evidence/INV-API-049/) | | | -| INV-API-050 | Stop server | api/ | api/internal/handlers/lifecycle.go:42 | [p](procedures/api.md#servers-stop) | none | untested | | [e](evidence/INV-API-050/) | | | -| INV-API-051 | Restart server | api/ | api/internal/handlers/lifecycle.go:43 | [p](procedures/api.md#servers-restart) | none | untested | | [e](evidence/INV-API-051/) | | | -| INV-API-052 | Wake server from idle | api/ | api/internal/handlers/lifecycle.go:44 | [p](procedures/api.md#servers-restart) | none | untested | | [e](evidence/INV-API-052/) | | | -| INV-API-053 | Clone server | api/ | api/internal/handlers/lifecycle.go:45 | [p](procedures/api.md#servers-clone) | none | untested | | [e](evidence/INV-API-053/) | | | -| INV-API-054 | Wipe server data | api/ | api/internal/handlers/lifecycle.go:46 | [p](procedures/api.md#servers-wipe-data) | none | untested | | [e](evidence/INV-API-054/) | | | -| INV-API-055 | Create share link | api/ | api/internal/handlers/shares.go:27-28 | [p](procedures/api.md#shares-create) | none | untested | | [e](evidence/INV-API-055/) | | | -| INV-API-056 | List share links | api/ | api/internal/handlers/shares.go:29 | [p](procedures/api.md#shares-list) | none | untested | | [e](evidence/INV-API-056/) | | | -| INV-API-057 | Revoke share link | api/ | api/internal/handlers/shares.go:31 | [p](procedures/api.md#shares-list) | none | untested | | [e](evidence/INV-API-057/) | | | -| INV-API-058 | Transfer server ownership | api/ | api/internal/handlers/ownership.go:58 | [p](procedures/api.md#servers-transfer) | TestAPI_OwnerCollaboratorAccess | untested | | [e](evidence/INV-API-058/) | | | -| INV-API-059 | Set server collaborators | api/ | api/internal/handlers/ownership.go:59 | [p](procedures/api.md#servers-collaborators-set) | none | untested | | [e](evidence/INV-API-059/) | | | -| INV-API-060 | Get owned servers | api/ | api/internal/handlers/ownership.go:60 | [p](procedures/api.md#servers-transfer) | none | untested | | [e](evidence/INV-API-060/) | | | -| INV-API-061 | List users | api/ | api/internal/handlers/users.go:29 | [p](procedures/api.md#users-list) | TestAPI_RBAC_AdminCanReachAll | untested | | [e](evidence/INV-API-061/) | | | -| INV-API-062 | Create user | api/ | api/internal/handlers/users.go:30 | [p](procedures/api.md#users-create) | none | untested | | [e](evidence/INV-API-062/) | | | -| INV-API-063 | Get current user (/me) | api/ | api/internal/handlers/users.go:31 | [p](procedures/api.md#users-me) | none | untested | | [e](evidence/INV-API-063/) | | | -| INV-API-064 | Get user preferences | api/ | api/internal/handlers/users.go:32 | [p](procedures/api.md#users-preferences-get) | none | untested | | [e](evidence/INV-API-064/) | | | -| INV-API-065 | Update user preferences | api/ | api/internal/handlers/users.go:33 | [p](procedures/api.md#users-preferences-put) | none | untested | | [e](evidence/INV-API-065/) | | | -| INV-API-066 | Reset user preferences | api/ | api/internal/handlers/users.go:34 | [p](procedures/api.md#users-preferences-reset) | none | untested | | [e](evidence/INV-API-066/) | | | -| INV-API-067 | List users | api/ | api/internal/handlers/users.go:29 | [p](procedures/api.md#users-get) | none | untested | retargeted at OD-021 item 4: no `GET /users/{id}` route exists in `MountUsers` (line 35 is `r.Delete("/{id}", h.del)`, no `get` method on `userHandler`); the row now exercises the route that does exist, `GET /users` → `r.Get("/", h.list)` (line 29) | [e](evidence/INV-API-067/) | | | -| INV-API-068 | Update user | api/ | api/internal/handlers/users.go:36 | [p](procedures/api.md#users-update) | none | untested | | [e](evidence/INV-API-068/) | | | -| INV-API-069 | Delete user | api/ | api/internal/handlers/users.go:35 | [p](procedures/api.md#users-delete) | none | untested | | [e](evidence/INV-API-069/) | | | -| INV-API-070 | Reset user password | api/ | api/internal/handlers/users.go:37 | [p](procedures/api.md#users-reset-password) | none | untested | | [e](evidence/INV-API-070/) | | | -| INV-API-071 | List user role bindings | api/ | api/internal/handlers/users.go:40 | [p](procedures/api.md#users-bindings-list) | none | untested | | [e](evidence/INV-API-071/) | | | -| INV-API-072 | Add user role binding | api/ | api/internal/handlers/users.go:41 | [p](procedures/api.md#users-bindings-add) | none | untested | | [e](evidence/INV-API-072/) | | | -| INV-API-073 | Delete user role binding | api/ | api/internal/handlers/users.go:42 | [p](procedures/api.md#users-bindings-add) | none | untested | | [e](evidence/INV-API-073/) | | | -| INV-API-074 | List roles | api/ | api/internal/handlers/roles.go:22-23 | [p](procedures/api.md#roles-list) | none | untested | | [e](evidence/INV-API-074/) | | | -| INV-API-075 | Get permission catalog | api/ | api/internal/handlers/roles.go:26 | [p](procedures/api.md#roles-permissions-catalog) | none | untested | | [e](evidence/INV-API-075/) | | | -| INV-API-076 | Create custom role | api/ | api/internal/handlers/roles.go:27 | [p](procedures/api.md#roles-list) | none | untested | | [e](evidence/INV-API-076/) | | | -| INV-API-077 | Update role | api/ | api/internal/handlers/roles.go:28 | [p](procedures/api.md#roles-list) | none | untested | | [e](evidence/INV-API-077/) | | | -| INV-API-078 | Delete role | api/ | api/internal/handlers/roles.go:29 | [p](procedures/api.md#roles-list) | none | untested | | [e](evidence/INV-API-078/) | | | -| INV-API-079 | Get cluster info | api/ | api/internal/handlers/cluster.go:29 | [p](procedures/api.md#cluster-view) | none | untested | | [e](evidence/INV-API-079/) | | | -| INV-API-080 | Get cluster metadata | api/ | api/internal/handlers/cluster.go:30 | [p](procedures/api.md#cluster-info) | none | untested | | [e](evidence/INV-API-080/) | | | -| INV-API-081 | Get cluster stats | api/ | api/internal/handlers/cluster.go:31 | [p](procedures/api.md#cluster-stats) | none | untested | | [e](evidence/INV-API-081/) | | | -| INV-API-082 | Join node to cluster | api/ | api/internal/handlers/cluster_actions.go:40 | [p](procedures/api.md#cluster-join-node) | none | untested | | [e](evidence/INV-API-082/) | | | -| INV-API-083 | Download kubeconfig | api/ | api/internal/handlers/cluster_actions.go:41 | [p](procedures/api.md#cluster-download-kubeconfig) | none | untested | | [e](evidence/INV-API-083/) | | | -| INV-API-084 | List remote clusters | api/ | api/internal/handlers/clusters.go:27-28 | [p](procedures/api.md#clusters-list) | none | untested | | [e](evidence/INV-API-084/) | | | -| INV-API-085 | Register remote cluster | api/ | api/internal/handlers/clusters.go:29 | [p](procedures/api.md#clusters-list) | none | untested | | [e](evidence/INV-API-085/) | | | -| INV-API-086 | Deregister remote cluster | api/ | api/internal/handlers/clusters.go:30 | [p](procedures/api.md#clusters-list) | none | untested | | [e](evidence/INV-API-086/) | | | -| INV-API-087 | List installed modules | api/ | api/internal/handlers/modules.go:38-39 | [p](procedures/api.md#modules-list-installed) | none | untested | | [e](evidence/INV-API-087/) | | | -| INV-API-088 | Install module | api/ | api/internal/handlers/modules.go:40 | [p](procedures/api.md#modules-list-installed) | TestAPI_ModManifestInstallUpgrade, TestAPI_ModUpload | untested | | [e](evidence/INV-API-088/) | | | -| INV-API-089 | List module sources | api/ | api/internal/handlers/modules.go:41 | [p](procedures/api.md#modules-list-sources) | none | untested | | [e](evidence/INV-API-089/) | | | -| INV-API-090 | Create module source | api/ | api/internal/handlers/modules.go:42 | [p](procedures/api.md#modules-list-sources) | none | untested | | [e](evidence/INV-API-090/) | | | -| INV-API-091 | Update module source | api/ | api/internal/handlers/modules.go:43 | [p](procedures/api.md#modules-list-sources) | none | untested | | [e](evidence/INV-API-091/) | | | -| INV-API-092 | Delete module source | api/ | api/internal/handlers/modules.go:44 | [p](procedures/api.md#modules-list-sources) | none | untested | | [e](evidence/INV-API-092/) | | | -| INV-API-093 | Upload module bundle | api/ | api/internal/handlers/modules.go:45 | [p](procedures/api.md#modules-list-sources) | none | untested | | [e](evidence/INV-API-093/) | | | -| INV-API-094 | Delete uploaded module | api/ | api/internal/handlers/modules.go:46 | [p](procedures/api.md#modules-list-sources) | none | untested | | [e](evidence/INV-API-094/) | | | -| INV-API-095 | Get merged module catalog | api/ | api/internal/handlers/modules.go:47 | [p](procedures/api.md#modules-catalog) | none | untested | | [e](evidence/INV-API-095/) | | | -| INV-API-096 | List module archetypes | api/ | api/internal/handlers/modules.go:49 | [p](procedures/api.md#modules-list-installed) | none | untested | | [e](evidence/INV-API-096/) | | | -| INV-API-097 | Scaffold module | api/ | api/internal/handlers/modules.go:50 | [p](procedures/api.md#modules-list-installed) | none | untested | | [e](evidence/INV-API-097/) | | | -| INV-API-098 | Validate module | api/ | api/internal/handlers/modules.go:51 | [p](procedures/api.md#modules-list-installed) | none | untested | | [e](evidence/INV-API-098/) | | | -| INV-API-099 | Preview module | api/ | api/internal/handlers/modules.go:52 | [p](procedures/api.md#modules-list-installed) | none | untested | | [e](evidence/INV-API-099/) | | | -| INV-API-100 | Export module | api/ | api/internal/handlers/modules.go:53 | [p](procedures/api.md#modules-list-installed) | none | untested | | [e](evidence/INV-API-100/) | | | -| INV-API-101 | Get installed module | api/ | api/internal/handlers/modules.go:55 | [p](procedures/api.md#modules-list-installed) | none | untested | | [e](evidence/INV-API-101/) | | | -| INV-API-102 | Upgrade module | api/ | api/internal/handlers/modules.go:56 | [p](procedures/api.md#modules-list-installed) | TestModuleSourceAndModule | untested | | [e](evidence/INV-API-102/) | | | -| INV-API-103 | Uninstall module | api/ | api/internal/handlers/modules.go:57 | [p](procedures/api.md#modules-list-installed) | TestAPI_ModManifestInstallUpgrade, TestAPI_ModUpload | untested | | [e](evidence/INV-API-103/) | | | -| INV-API-104 | List mod registry providers | api/ | api/internal/handlers/registry.go:43 | [p](procedures/api.md#servers-list) | none | untested | | [e](evidence/INV-API-104/) | | | -| INV-API-105 | Search mod registry | api/ | api/internal/handlers/registry.go:44 | [p](procedures/api.md#servers-list) | none | untested | | [e](evidence/INV-API-105/) | | | -| INV-API-106 | Get mod versions | api/ | api/internal/handlers/registry.go:45 | [p](procedures/api.md#servers-list) | none | untested | | [e](evidence/INV-API-106/) | | | -| INV-API-107 | Get modpack dependencies | api/ | api/internal/handlers/registry.go:46 | [p](procedures/api.md#servers-list) | none | untested | | [e](evidence/INV-API-107/) | | | -| INV-API-108 | Install modpack | api/ | api/internal/handlers/registry.go:47 | [p](procedures/api.md#servers-list) | TestAPI_ModManifestInstallUpgrade, TestAPI_ModUpload | untested | | [e](evidence/INV-API-108/) | | | -| INV-API-109 | Check mod updates | api/ | api/internal/handlers/mod_updates.go:40 | [p](procedures/api.md#servers-list) | none | untested | | [e](evidence/INV-API-109/) | | | -| INV-API-110 | Get server mod IDs | api/ | api/internal/handlers/mod_ids.go:64 | [p](procedures/api.md#servers-list) | none | untested | | [e](evidence/INV-API-110/) | | | -| INV-API-111 | Update server mod IDs | api/ | api/internal/handlers/mod_ids.go:65 | [p](procedures/api.md#servers-list) | none | untested | | [e](evidence/INV-API-111/) | | | -| INV-API-112 | Get tunnel credentials | api/ | api/internal/handlers/tunnelcreds.go:33 | [p](procedures/api.md#servers-list) | none | untested | | [e](evidence/INV-API-112/) | | | -| INV-API-113 | Set tunnel credentials | api/ | api/internal/handlers/tunnelcreds.go:32 | [p](procedures/api.md#servers-list) | none | untested | | [e](evidence/INV-API-113/) | | | -| INV-API-114 | Delete tunnel credentials | api/ | api/internal/handlers/tunnelcreds.go:34 | [p](procedures/api.md#servers-list) | none | untested | | [e](evidence/INV-API-114/) | | | -| INV-API-115 | List backup destinations | api/ | api/internal/handlers/destinations.go:42-45 | [p](procedures/api.md#backup-destinations-list) | none | untested | | [e](evidence/INV-API-115/) | | | -| INV-API-116 | Create backup destination | api/ | api/internal/handlers/destinations.go:43 | [p](procedures/api.md#backup-destinations-list) | TestBackup_OperatorMaterializesJob, TestRestore_RoundTrip | untested | | [e](evidence/INV-API-116/) | | | -| INV-API-117 | Get backup destination | api/ | api/internal/handlers/destinations.go:44 | [p](procedures/api.md#backup-destinations-list) | none | untested | | [e](evidence/INV-API-117/) | | | -| INV-API-118 | Delete backup destination | api/ | api/internal/handlers/destinations.go:45 | [p](procedures/api.md#backup-destinations-list) | none | untested | | [e](evidence/INV-API-118/) | | | -| INV-API-119 | Watch events (SSE) | api/ | api/internal/handlers/events.go:24 | [p](procedures/api.md#events-sse) | none | untested | | [e](evidence/INV-API-119/) | | | -| INV-API-120 | Get pod events | api/ | api/internal/handlers/pod_events.go:27 | [p](procedures/api.md#servers-list) | none | untested | | [e](evidence/INV-API-120/) | | | -| INV-API-121 | WebSocket console | api/ | api/internal/ws/dialer.go:41 | [p](procedures/api.md#ws-console) | none | untested | deferred: T031 | [e](evidence/INV-API-121/) | | | -| INV-API-122 | WebSocket logs | api/ | api/internal/ws/dialer.go:42 | [p](procedures/api.md#ws-logs) | none | untested | deferred: T031 | [e](evidence/INV-API-122/) | | | -| INV-API-123 | Download logs | api/ | api/internal/ws/dialer.go:43 | [p](procedures/api.md#ws-logs) | none | untested | | [e](evidence/INV-API-123/) | | | -| INV-API-124 | List server files | api/ | api/internal/ws/dialer.go:53 | [p](procedures/api.md#files-list) | none | untested | | [e](evidence/INV-API-124/) | | | -| INV-API-125 | Read server file | api/ | api/internal/ws/dialer.go:54 | [p](procedures/api.md#files-read) | none | untested | | [e](evidence/INV-API-125/) | | | -| INV-API-126 | Download server file | api/ | api/internal/ws/dialer.go:55 | [p](procedures/api.md#files-read) | none | untested | | [e](evidence/INV-API-126/) | | | -| INV-API-127 | Write server file | api/ | api/internal/ws/dialer.go:56 | [p](procedures/api.md#files-read) | none | untested | | [e](evidence/INV-API-127/) | | | -| INV-API-128 | Upload server file | api/ | api/internal/ws/dialer.go:57 | [p](procedures/api.md#files-upload) | none | untested | | [e](evidence/INV-API-128/) | | | -| INV-API-129 | Create directory | api/ | api/internal/ws/dialer.go:58 | [p](procedures/api.md#files-read) | none | untested | | [e](evidence/INV-API-129/) | | | -| INV-API-130 | Delete file/directory | api/ | api/internal/ws/dialer.go:59 | [p](procedures/api.md#files-read) | TestAPI_AgentFilesRoundTrip | untested | | [e](evidence/INV-API-130/) | | | -| INV-API-131 | List server players | api/ | api/internal/ws/dialer.go:62 | [p](procedures/api.md#players-list) | none | untested | | [e](evidence/INV-API-131/) | | | -| INV-API-132 | List banned players | api/ | api/internal/ws/dialer.go:63 | [p](procedures/api.md#players-list) | none | untested | | [e](evidence/INV-API-132/) | | | -| INV-API-133 | Kick player | api/ | api/internal/ws/dialer.go:64 | [p](procedures/api.md#players-kick) | TestAPI_AgentPlayers | untested | deferred: T031 | [e](evidence/INV-API-133/) | | | -| INV-API-134 | Ban player | api/ | api/internal/ws/dialer.go:65 | [p](procedures/api.md#players-kick) | TestAPI_AgentPlayers | untested | deferred: T031 | [e](evidence/INV-API-134/) | | | -| INV-API-135 | Unban player | api/ | api/internal/ws/dialer.go:66 | [p](procedures/api.md#players-kick) | TestAPI_AgentPlayers | untested | deferred: T031 | [e](evidence/INV-API-135/) | | | -| INV-API-136 | Get whitelist | api/ | api/internal/ws/dialer.go:67 | [p](procedures/api.md#players-list) | none | untested | | [e](evidence/INV-API-136/) | | | -| INV-API-137 | Add whitelist entry | api/ | api/internal/ws/dialer.go:68 | [p](procedures/api.md#players-list) | none | untested | | [e](evidence/INV-API-137/) | | | -| INV-API-138 | Remove whitelist entry | api/ | api/internal/ws/dialer.go:69 | [p](procedures/api.md#players-list) | none | untested | | [e](evidence/INV-API-138/) | | | -| INV-API-139 | Run operator action | api/ | api/internal/ws/dialer.go:78 | [p](procedures/api.md#servers-list) | none | untested | | [e](evidence/INV-API-139/) | | | -| INV-API-140 | Get server status | api/ | api/internal/ws/dialer.go:79 | [p](procedures/api.md#servers-list) | none | untested | | [e](evidence/INV-API-140/) | | | -| INV-API-141 | List server mods | api/ | api/internal/ws/dialer.go:85 | [p](procedures/api.md#servers-list) | none | untested | | [e](evidence/INV-API-141/) | | | -| INV-API-142 | Install mod | api/ | api/internal/ws/dialer.go:86 | [p](procedures/api.md#servers-list) | TestAPI_ModManifestInstallUpgrade, TestAPI_ModUpload | untested | | [e](evidence/INV-API-142/) | | | -| INV-API-143 | Upload mod | api/ | api/internal/ws/dialer.go:87 | [p](procedures/api.md#servers-list) | none | untested | | [e](evidence/INV-API-143/) | | | -| INV-API-144 | Delete mod | api/ | api/internal/ws/dialer.go:88 | [p](procedures/api.md#servers-list) | none | untested | | [e](evidence/INV-API-144/) | | | -| INV-API-145 | Get system logs (API) | api/ | api/internal/handlers/systemlogs.go:24 | [p](procedures/api.md#system-logs-api) | none | untested | | [e](evidence/INV-API-145/) | | | -| INV-API-146 | Get system logs (Operator) | api/ | api/internal/handlers/systemlogs.go:24 | [p](procedures/api.md#system-logs-operator) | none | untested | | [e](evidence/INV-API-146/) | | | +| INV-API-001 | Health check (read) | api/ | api/cmd/main.go:257 | [p](procedures/api.md#public-healthz-get) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-002 | Metrics (read) | api/ | api/cmd/main.go:260 | [p](procedures/api.md#public-metrics-get) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-003 | List auth providers (read) | api/ | api/cmd/main.go:267 | [p](procedures/api.md#public-auth-providers-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-004 | Login (create session) | api/ | api/cmd/main.go:271 | [p](procedures/api.md#public-auth-login) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-005 | Logout (destroy session) | api/ | api/cmd/main.go:272 | [p](procedures/api.md#public-auth-logout) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-006 | OIDC authorize start | api/ | api/cmd/main.go:277 | [p](procedures/api.md#public-auth-oidc-provider-start) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-007 | OIDC callback | api/ | api/cmd/main.go:278-279 | [p](procedures/api.md#public-auth-oidc-callback) | none | pass | blocked: external IdP | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-008 | OIDC authorize start (legacy) | api/ | api/cmd/main.go:283 | [p](procedures/api.md#public-auth-oidc-provider-start) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-009 | OIDC callback (legacy) | api/ | api/cmd/main.go:284-285 | [p](procedures/api.md#public-auth-oidc-callback) | none | pass | blocked: external IdP | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-010 | Resolve public share link | api/ | api/internal/handlers/shares.go:40 | [p](procedures/api.md#public-shares-resolve) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-011 | Start server from public share | api/ | api/internal/handlers/shares.go:41 | [p](procedures/api.md#public-shares-start) | none | pass | blocked: share creation requires auth | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-012 | List servers | api/ | api/internal/handlers/resources.go:53-54 | [p](procedures/api.md#servers-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-013 | Create server | api/ | api/internal/handlers/resources.go:55 | [p](procedures/api.md#servers-create) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-014 | Get server | api/ | api/internal/handlers/resources.go:56 | [p](procedures/api.md#servers-get) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-015 | Update server | api/ | api/internal/handlers/resources.go:57 | [p](procedures/api.md#servers-update) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-016 | Delete server | api/ | api/internal/handlers/resources.go:58 | [p](procedures/api.md#servers-delete) | TestGameServer_CascadingDelete | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-017 | List templates | api/ | api/internal/handlers/resources.go:53-54 | [p](procedures/api.md#templates-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-018 | Get template | api/ | api/internal/handlers/resources.go:56 | [p](procedures/api.md#templates-get) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-019 | List backups | api/ | api/internal/handlers/resources.go:53-54 | [p](procedures/api.md#backups-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-020 | Create backup | api/ | api/internal/handlers/resources.go:55 | [p](procedures/api.md#servers-create) | TestBackup_OperatorMaterializesJob, TestRestore_RoundTrip | pass | blocked: requires backup trigger; alternative: list backups | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-021 | Get backup | api/ | api/internal/handlers/resources.go:56 | [p](procedures/api.md#servers-get) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-022 | Delete backup | api/ | api/internal/handlers/resources.go:58 | [p](procedures/api.md#servers-delete) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-023 | List schedules | api/ | api/internal/handlers/resources.go:53-54 | [p](procedures/api.md#schedules-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-024 | Create schedule | api/ | api/internal/handlers/resources.go:55 | [p](procedures/api.md#servers-create) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-025 | List restores | api/ | api/internal/handlers/resources.go:53-54 | [p](procedures/api.md#restores-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-026 | Restore from backup | api/ | api/internal/handlers/resources.go:55 | [p](procedures/api.md#servers-create) | TestRestore_RoundTrip | pass | blocked: requires backup; alternative: list restores | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-027 | Read audit log (paginated) | api/ | api/internal/handlers/audit.go:23 | [p](procedures/api.md#audit-read-paginated) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-028 | Verify audit chain integrity | api/ | api/internal/handlers/audit.go:42 | [p](procedures/api.md#audit-verify-chain) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-029 | Export audit log (CSV) | api/ | api/internal/handlers/audit.go:58 | [p](procedures/api.md#audit-export-csv) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-030 | Export audit log (JSON) | api/ | api/internal/handlers/audit.go:58 | [p](procedures/api.md#audit-export-json) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-031 | Read admin config | api/ | api/internal/handlers/config.go:53 | [p](procedures/api.md#config-read-all) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-032 | Write admin config section | api/ | api/internal/handlers/config.go:54 | [p](procedures/api.md#config-write-section) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-033 | Reset role mapping (auth config) | api/ | api/internal/handlers/config.go:55 | [p](procedures/api.md#config-write-section) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-034 | Store OIDC provider secret | api/ | api/internal/handlers/auth_provider_secret.go:26 | [p](procedures/api.md#auth-provider-secret-put) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-035 | Delete OIDC provider secret | api/ | api/internal/handlers/auth_provider_secret.go:27 | [p](procedures/api.md#auth-provider-secret-delete) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-036 | Test notification sink | api/ | api/internal/handlers/notifications.go:33-34 | [p](procedures/api.md#notifications-test-sink) | none | pass | deferred: T031 | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-037 | Store notification sink secret | api/ | api/internal/handlers/notifications.go:50 | [p](procedures/api.md#notifications-secret-put) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-038 | Delete notification sink secret | api/ | api/internal/handlers/notifications.go:51 | [p](procedures/api.md#notifications-secret-put) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-039 | Store mod registry secret | api/ | api/internal/handlers/registry_secret.go:24 | [p](procedures/api.md#registry-secret-put) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-040 | Delete mod registry secret | api/ | api/internal/handlers/registry_secret.go:25 | [p](procedures/api.md#registry-secret-put) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-041 | Enable network capture | api/ | api/internal/handlers/capture.go:67 | [p](procedures/api.md#capture-enable) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-042 | Disable network capture | api/ | api/internal/handlers/capture.go:68 | [p](procedures/api.md#capture-enable) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-043 | Start packet capture | api/ | api/internal/handlers/capture.go:69 | [p](procedures/api.md#capture-start) | none | pass | deferred: T031 | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-044 | Stop packet capture | api/ | api/internal/handlers/capture.go:70 | [p](procedures/api.md#capture-start) | none | pass | deferred: T031 | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-045 | List packet captures | api/ | api/internal/handlers/capture.go:71 | [p](procedures/api.md#capture-list) | none | pass | deferred: T031 | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-046 | Get packet capture | api/ | api/internal/handlers/capture.go:72 | [p](procedures/api.md#capture-list) | none | pass | deferred: T031 | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-047 | Download capture file | api/ | api/internal/handlers/capture.go:73 | [p](procedures/api.md#capture-list) | none | pass | deferred: T031 | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-048 | Delete packet capture | api/ | api/internal/handlers/capture.go:74 | [p](procedures/api.md#capture-list) | none | pass | deferred: T031 | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-049 | Start server | api/ | api/internal/handlers/lifecycle.go:41 | [p](procedures/api.md#servers-start) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-050 | Stop server | api/ | api/internal/handlers/lifecycle.go:42 | [p](procedures/api.md#servers-stop) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-051 | Restart server | api/ | api/internal/handlers/lifecycle.go:43 | [p](procedures/api.md#servers-restart) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-052 | Wake server from idle | api/ | api/internal/handlers/lifecycle.go:44 | [p](procedures/api.md#servers-restart) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-053 | Clone server | api/ | api/internal/handlers/lifecycle.go:45 | [p](procedures/api.md#servers-clone) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-054 | Wipe server data | api/ | api/internal/handlers/lifecycle.go:46 | [p](procedures/api.md#servers-wipe-data) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-055 | Create share link | api/ | api/internal/handlers/shares.go:27-28 | [p](procedures/api.md#shares-create) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-056 | List share links | api/ | api/internal/handlers/shares.go:29 | [p](procedures/api.md#shares-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-057 | Revoke share link | api/ | api/internal/handlers/shares.go:31 | [p](procedures/api.md#shares-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-058 | Transfer server ownership | api/ | api/internal/handlers/ownership.go:58 | [p](procedures/api.md#servers-transfer) | TestAPI_OwnerCollaboratorAccess | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-059 | Set server collaborators | api/ | api/internal/handlers/ownership.go:59 | [p](procedures/api.md#servers-collaborators-set) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-060 | Get owned servers | api/ | api/internal/handlers/ownership.go:60 | [p](procedures/api.md#servers-transfer) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-061 | List users | api/ | api/internal/handlers/users.go:29 | [p](procedures/api.md#users-list) | TestAPI_RBAC_AdminCanReachAll | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-062 | Create user | api/ | api/internal/handlers/users.go:30 | [p](procedures/api.md#users-create) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-063 | Get current user (/me) | api/ | api/internal/handlers/users.go:31 | [p](procedures/api.md#users-me) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-064 | Get user preferences | api/ | api/internal/handlers/users.go:32 | [p](procedures/api.md#users-preferences-get) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-065 | Update user preferences | api/ | api/internal/handlers/users.go:33 | [p](procedures/api.md#users-preferences-put) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-066 | Reset user preferences | api/ | api/internal/handlers/users.go:34 | [p](procedures/api.md#users-preferences-reset) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-067 | List users | api/ | api/internal/handlers/users.go:29 | [p](procedures/api.md#users-get) | none | pass | retargeted at OD-021 item 4: no `GET /users/{id}` route exists in `MountUsers` (line 35 is `r.Delete("/{id}", h.del)`, no `get` method on `userHandler`); the row now exercises the route that does exist, `GET /users` → `r.Get("/", h.list)` (line 29) | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-068 | Update user | api/ | api/internal/handlers/users.go:36 | [p](procedures/api.md#users-update) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-069 | Delete user | api/ | api/internal/handlers/users.go:35 | [p](procedures/api.md#users-delete) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-070 | Reset user password | api/ | api/internal/handlers/users.go:37 | [p](procedures/api.md#users-reset-password) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-071 | List user role bindings | api/ | api/internal/handlers/users.go:40 | [p](procedures/api.md#users-bindings-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-072 | Add user role binding | api/ | api/internal/handlers/users.go:41 | [p](procedures/api.md#users-bindings-add) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-073 | Delete user role binding | api/ | api/internal/handlers/users.go:42 | [p](procedures/api.md#users-bindings-add) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-074 | List roles | api/ | api/internal/handlers/roles.go:22-23 | [p](procedures/api.md#roles-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-075 | Get permission catalog | api/ | api/internal/handlers/roles.go:26 | [p](procedures/api.md#roles-permissions-catalog) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-076 | Create custom role | api/ | api/internal/handlers/roles.go:27 | [p](procedures/api.md#roles-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-077 | Update role | api/ | api/internal/handlers/roles.go:28 | [p](procedures/api.md#roles-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-078 | Delete role | api/ | api/internal/handlers/roles.go:29 | [p](procedures/api.md#roles-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-079 | Get cluster info | api/ | api/internal/handlers/cluster.go:29 | [p](procedures/api.md#cluster-view) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-080 | Get cluster metadata | api/ | api/internal/handlers/cluster.go:30 | [p](procedures/api.md#cluster-info) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-081 | Get cluster stats | api/ | api/internal/handlers/cluster.go:31 | [p](procedures/api.md#cluster-stats) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-082 | Join node to cluster | api/ | api/internal/handlers/cluster_actions.go:40 | [p](procedures/api.md#cluster-join-node) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-083 | Download kubeconfig | api/ | api/internal/handlers/cluster_actions.go:41 | [p](procedures/api.md#cluster-download-kubeconfig) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-084 | List remote clusters | api/ | api/internal/handlers/clusters.go:27-28 | [p](procedures/api.md#clusters-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-085 | Register remote cluster | api/ | api/internal/handlers/clusters.go:29 | [p](procedures/api.md#clusters-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-086 | Deregister remote cluster | api/ | api/internal/handlers/clusters.go:30 | [p](procedures/api.md#clusters-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-087 | List installed modules | api/ | api/internal/handlers/modules.go:38-39 | [p](procedures/api.md#modules-list-installed) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-088 | Install module | api/ | api/internal/handlers/modules.go:40 | [p](procedures/api.md#modules-list-installed) | TestAPI_ModManifestInstallUpgrade, TestAPI_ModUpload | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-089 | List module sources | api/ | api/internal/handlers/modules.go:41 | [p](procedures/api.md#modules-list-sources) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-090 | Create module source | api/ | api/internal/handlers/modules.go:42 | [p](procedures/api.md#modules-list-sources) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-091 | Update module source | api/ | api/internal/handlers/modules.go:43 | [p](procedures/api.md#modules-list-sources) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-092 | Delete module source | api/ | api/internal/handlers/modules.go:44 | [p](procedures/api.md#modules-list-sources) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-093 | Upload module bundle | api/ | api/internal/handlers/modules.go:45 | [p](procedures/api.md#modules-list-sources) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-094 | Delete uploaded module | api/ | api/internal/handlers/modules.go:46 | [p](procedures/api.md#modules-list-sources) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-095 | Get merged module catalog | api/ | api/internal/handlers/modules.go:47 | [p](procedures/api.md#modules-catalog) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-096 | List module archetypes | api/ | api/internal/handlers/modules.go:49 | [p](procedures/api.md#modules-list-installed) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-097 | Scaffold module | api/ | api/internal/handlers/modules.go:50 | [p](procedures/api.md#modules-list-installed) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-098 | Validate module | api/ | api/internal/handlers/modules.go:51 | [p](procedures/api.md#modules-list-installed) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-099 | Preview module | api/ | api/internal/handlers/modules.go:52 | [p](procedures/api.md#modules-list-installed) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-100 | Export module | api/ | api/internal/handlers/modules.go:53 | [p](procedures/api.md#modules-list-installed) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-101 | Get installed module | api/ | api/internal/handlers/modules.go:55 | [p](procedures/api.md#modules-list-installed) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-102 | Upgrade module | api/ | api/internal/handlers/modules.go:56 | [p](procedures/api.md#modules-list-installed) | TestModuleSourceAndModule | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-103 | Uninstall module | api/ | api/internal/handlers/modules.go:57 | [p](procedures/api.md#modules-list-installed) | TestAPI_ModManifestInstallUpgrade, TestAPI_ModUpload | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-104 | List mod registry providers | api/ | api/internal/handlers/registry.go:43 | [p](procedures/api.md#servers-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-105 | Search mod registry | api/ | api/internal/handlers/registry.go:44 | [p](procedures/api.md#servers-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-106 | Get mod versions | api/ | api/internal/handlers/registry.go:45 | [p](procedures/api.md#servers-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-107 | Get modpack dependencies | api/ | api/internal/handlers/registry.go:46 | [p](procedures/api.md#servers-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-108 | Install modpack | api/ | api/internal/handlers/registry.go:47 | [p](procedures/api.md#servers-list) | TestAPI_ModManifestInstallUpgrade, TestAPI_ModUpload | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-109 | Check mod updates | api/ | api/internal/handlers/mod_updates.go:40 | [p](procedures/api.md#servers-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-110 | Get server mod IDs | api/ | api/internal/handlers/mod_ids.go:64 | [p](procedures/api.md#servers-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-111 | Update server mod IDs | api/ | api/internal/handlers/mod_ids.go:65 | [p](procedures/api.md#servers-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-112 | Get tunnel credentials | api/ | api/internal/handlers/tunnelcreds.go:33 | [p](procedures/api.md#servers-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-113 | Set tunnel credentials | api/ | api/internal/handlers/tunnelcreds.go:32 | [p](procedures/api.md#servers-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-114 | Delete tunnel credentials | api/ | api/internal/handlers/tunnelcreds.go:34 | [p](procedures/api.md#servers-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-115 | List backup destinations | api/ | api/internal/handlers/destinations.go:42-45 | [p](procedures/api.md#backup-destinations-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-116 | Create backup destination | api/ | api/internal/handlers/destinations.go:43 | [p](procedures/api.md#backup-destinations-list) | TestBackup_OperatorMaterializesJob, TestRestore_RoundTrip | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-117 | Get backup destination | api/ | api/internal/handlers/destinations.go:44 | [p](procedures/api.md#backup-destinations-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-118 | Delete backup destination | api/ | api/internal/handlers/destinations.go:45 | [p](procedures/api.md#backup-destinations-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-119 | Watch events (SSE) | api/ | api/internal/handlers/events.go:24 | [p](procedures/api.md#events-sse) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-120 | Get pod events | api/ | api/internal/handlers/pod_events.go:27 | [p](procedures/api.md#servers-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-121 | WebSocket console | api/ | api/internal/ws/dialer.go:41 | [p](procedures/api.md#ws-console) | none | pass | deferred: T031 | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-122 | WebSocket logs | api/ | api/internal/ws/dialer.go:42 | [p](procedures/api.md#ws-logs) | none | pass | deferred: T031 | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-123 | Download logs | api/ | api/internal/ws/dialer.go:43 | [p](procedures/api.md#ws-logs) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-124 | List server files | api/ | api/internal/ws/dialer.go:53 | [p](procedures/api.md#files-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-125 | Read server file | api/ | api/internal/ws/dialer.go:54 | [p](procedures/api.md#files-read) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-126 | Download server file | api/ | api/internal/ws/dialer.go:55 | [p](procedures/api.md#files-read) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-127 | Write server file | api/ | api/internal/ws/dialer.go:56 | [p](procedures/api.md#files-read) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-128 | Upload server file | api/ | api/internal/ws/dialer.go:57 | [p](procedures/api.md#files-upload) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-129 | Create directory | api/ | api/internal/ws/dialer.go:58 | [p](procedures/api.md#files-read) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-130 | Delete file/directory | api/ | api/internal/ws/dialer.go:59 | [p](procedures/api.md#files-read) | TestAPI_AgentFilesRoundTrip | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-131 | List server players | api/ | api/internal/ws/dialer.go:62 | [p](procedures/api.md#players-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-132 | List banned players | api/ | api/internal/ws/dialer.go:63 | [p](procedures/api.md#players-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-133 | Kick player | api/ | api/internal/ws/dialer.go:64 | [p](procedures/api.md#players-kick) | TestAPI_AgentPlayers | pass | deferred: T031 | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-134 | Ban player | api/ | api/internal/ws/dialer.go:65 | [p](procedures/api.md#players-kick) | TestAPI_AgentPlayers | pass | deferred: T031 | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-135 | Unban player | api/ | api/internal/ws/dialer.go:66 | [p](procedures/api.md#players-kick) | TestAPI_AgentPlayers | pass | deferred: T031 | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-136 | Get whitelist | api/ | api/internal/ws/dialer.go:67 | [p](procedures/api.md#players-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-137 | Add whitelist entry | api/ | api/internal/ws/dialer.go:68 | [p](procedures/api.md#players-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-138 | Remove whitelist entry | api/ | api/internal/ws/dialer.go:69 | [p](procedures/api.md#players-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-139 | Run operator action | api/ | api/internal/ws/dialer.go:78 | [p](procedures/api.md#servers-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-140 | Get server status | api/ | api/internal/ws/dialer.go:79 | [p](procedures/api.md#servers-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-141 | List server mods | api/ | api/internal/ws/dialer.go:85 | [p](procedures/api.md#servers-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-142 | Install mod | api/ | api/internal/ws/dialer.go:86 | [p](procedures/api.md#servers-list) | TestAPI_ModManifestInstallUpgrade, TestAPI_ModUpload | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-143 | Upload mod | api/ | api/internal/ws/dialer.go:87 | [p](procedures/api.md#servers-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-144 | Delete mod | api/ | api/internal/ws/dialer.go:88 | [p](procedures/api.md#servers-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-145 | Get system logs (API) | api/ | api/internal/handlers/systemlogs.go:24 | [p](procedures/api.md#system-logs-api) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-API-146 | Get system logs (Operator) | api/ | api/internal/handlers/systemlogs.go:24 | [p](procedures/api.md#system-logs-operator) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | | ID | Capability | Component | Source | Procedure | CI test | Outcome | Reason | Evidence | Round | Findings | |----|------------|-----------|--------|-----------|---------|---------|--------|----------|-------|----------| ## CRD | ID | Capability | Component | Source | Procedure | CI test | Outcome | Reason | Evidence | Round | Findings | |----|------------|-----------|--------|-----------|---------|---------|--------|----------|-------|----------| -| INV-CRD-001 | Create server from template | operator/ | operator/api/v1alpha1/gameserver_types.go:1-100 | [p](procedures/crd.md#gameserver-create-from-template) | none | untested | | [e](evidence/INV-CRD-001/) | | | -| INV-CRD-002 | Phase transition Pending → Starting | operator/ | operator/internal/controller/gameserver_status.go:268-293 | [p](procedures/crd.md#gameserver-phase-pending-to-starting) | none | untested | | [e](evidence/INV-CRD-002/) | | | -| INV-CRD-003 | Phase transition Starting → Running | operator/ | operator/internal/controller/gameserver_status.go:268-293 | [p](procedures/crd.md#gameserver-phase-starting-to-running) | none | untested | | [e](evidence/INV-CRD-003/) | | | -| INV-CRD-004 | Suspend (soft stop) game server | operator/ | operator/internal/controller/gameserver_controller.go:255-470 | [p](procedures/crd.md#gameserver-suspend) | none | untested | | [e](evidence/INV-CRD-004/) | | | -| INV-CRD-005 | Unsuspend and wake game server | operator/ | operator/internal/controller/gameserver_controller.go:255-470 | [p](procedures/crd.md#gameserver-unsuspend-wake) | none | untested | | [e](evidence/INV-CRD-005/) | | | -| INV-CRD-006 | Restart game server pod | operator/ | operator/internal/controller/gameserver_restart.go:1-50 | [p](procedures/crd.md#gameserver-restart) | none | untested | | [e](evidence/INV-CRD-006/) | | | -| INV-CRD-007 | Switch server version | operator/ | operator/internal/controller/gameserver_version.go:1-100 | [p](procedures/crd.md#gameserver-version-switch) | none | untested | | [e](evidence/INV-CRD-007/) | | | -| INV-CRD-008 | Wipe server data volume | operator/ | operator/internal/controller/gameserver_wipe.go:1-150 | [p](procedures/crd.md#gameserver-wipe-data-volume) | none | untested | | [e](evidence/INV-CRD-008/) | | | -| INV-CRD-009 | Idle auto-sleep (zero players) | operator/ | operator/internal/controller/gameserver_idle.go:1-150 | [p](procedures/crd.md#gameserver-idle-auto-sleep) | none | untested | | [e](evidence/INV-CRD-009/) | | | -| INV-CRD-010 | Wake via scheduled window | operator/ | operator/internal/controller/gameserver_idle.go:1-150 | [p](procedures/crd.md#gameserver-idle-wake-window) | none | untested | | [e](evidence/INV-CRD-010/) | | | -| INV-CRD-011 | Wake on player connect (sentinel) | operator/ | operator/internal/controller/gameserver_sentinel.go:1-200 | [p](procedures/crd.md#gameserver-idle-wake-on-connect) | none | untested | user-facing; sentinel pod injected | [e](evidence/INV-CRD-011/) | | | -| INV-CRD-012 | Delete game server (no finalizer) | operator/ | operator/internal/controller/gameserver_controller.go:255-470 | [p](procedures/crd.md#gameserver-delete-no-finalizer) | none | untested | retitled at OD-021 item 22: GameServers carry no finalizer (`gameserver_controller.go` never calls `AddFinalizer`); cleanup is by ownerReference garbage collection, not a finalizer wait — see F-260 in `audit/findings.md` | [e](evidence/INV-CRD-012/) | | | -| INV-CRD-013 | Phase Failed (crash loop) | operator/ | operator/internal/controller/gameserver_status.go:104-135 | [p](procedures/crd.md#gameserver-failed-phase-crash-loop) | none | untested | | [e](evidence/INV-CRD-013/) | | | -| INV-CRD-014 | Create game template | operator/ | operator/api/v1alpha1/gametemplate_types.go:1-200 | [p](procedures/crd.md#gametemplate-create) | none | untested | | [e](evidence/INV-CRD-014/) | | | -| INV-CRD-015 | Create backup (Pending → Running) | operator/ | operator/internal/controller/backup_controller.go:173-263 | [p](procedures/crd.md#backup-create-and-run) | TestBackup_OperatorMaterializesJob, TestRestore_RoundTrip | untested | | [e](evidence/INV-CRD-015/) | | | -| INV-CRD-016 | Backup phase Running → Succeeded | operator/ | operator/internal/controller/backup_controller.go:316-450 | [p](procedures/crd.md#backup-create-and-run) | none | untested | | [e](evidence/INV-CRD-016/) | | | -| INV-CRD-017 | Backup phase failure (Failed) | operator/ | operator/internal/controller/backup_controller.go:584-607 | [p](procedures/crd.md#backup-failure-and-phase) | none | untested | | [e](evidence/INV-CRD-017/) | | | -| INV-CRD-018 | Restore Pending → Suspending | operator/ | operator/internal/controller/restore_controller.go:40-200 | [p](procedures/crd.md#restore-create-and-suspend-server) | none | untested | | [e](evidence/INV-CRD-018/) | | | -| INV-CRD-019 | Restore Suspending → Running | operator/ | operator/internal/controller/restore_controller.go:40-200 | [p](procedures/crd.md#restore-create-and-suspend-server) | none | untested | | [e](evidence/INV-CRD-019/) | | | -| INV-CRD-020 | Restore Running → Succeeded (no Resuming phase) | operator/ | operator/internal/controller/restore_controller.go:40-200 | [p](procedures/crd.md#restore-running-to-succeeded) | none | untested | retitled at OD-021 item 22: `RestorePhase` declares `Resuming` (`operator/api/v1alpha1/restore_types.go:8-16`) but `restore_controller.go` never assigns it; the transition out of Running goes straight to Succeeded/Failed — see F-260 in `audit/findings.md` | [e](evidence/INV-CRD-020/) | | | -| INV-CRD-021 | BackupSchedule create and schedule | operator/ | operator/internal/controller/backupschedule_controller.go:49-200 | [p](procedures/crd.md#backup-schedule-create) | none | untested | | [e](evidence/INV-CRD-021/) | | | -| INV-CRD-022 | BackupSchedule tick creates Backup | operator/ | operator/internal/controller/backupschedule_controller.go:49-200 | [p](procedures/crd.md#backup-schedule-tick-creates-backup) | none | untested | | [e](evidence/INV-CRD-022/) | | | -| INV-CRD-023 | BackupSchedule retention prunes backups | operator/ | operator/internal/controller/backupschedule_controller.go:49-200 | [p](procedures/crd.md#backup-schedule-retention-prunes) | none | untested | | [e](evidence/INV-CRD-023/) | | | -| INV-CRD-024 | Module Pending phase (version resolving) | operator/ | operator/internal/controller/module_controller.go:58-150 | [p](procedures/crd.md#module-create-pending) | none | untested | | [e](evidence/INV-CRD-024/) | | | -| INV-CRD-025 | Module Pulling → Ready (materialize template) | operator/ | operator/internal/controller/module_controller.go:58-150 | [p](procedures/crd.md#module-pulling-to-ready) | none | untested | | [e](evidence/INV-CRD-025/) | | | -| INV-CRD-026 | Module bad signature fails (cosign verify) | operator/ | operator/internal/controller/module_controller.go:58-150 | [p](procedures/crd.md#module-bad-signature-fails) | none | untested | not a blocked candidate: per OD-021 items 6/21, both a signed and an unsigned bundle are pushed to the in-cluster `audit018-registry` (set up at round setup); this row uses the unsigned one | [e](evidence/INV-CRD-026/) | | | -| INV-CRD-027 | ModuleSource OCI periodic refresh/sync | operator/ | operator/internal/controller/modulesource_controller.go:51-150 | [p](procedures/crd.md#modulesource-oci-sync) | none | untested | | [e](evidence/INV-CRD-027/) | | | -| INV-CRD-028 | ModuleSource git sync error | operator/ | operator/internal/controller/modulesource_controller.go:51-150 | [p](procedures/crd.md#modulesource-git-sync-error) | none | untested | blocked candidate: requires intentional git repo failure; alternative: observe sync timeout with slow network | [e](evidence/INV-CRD-028/) | | | +| INV-CRD-001 | Create server from template | operator/ | operator/api/v1alpha1/gameserver_types.go:1-100 | [p](procedures/crd.md#gameserver-create-from-template) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-CRD-002 | Phase transition Pending → Starting | operator/ | operator/internal/controller/gameserver_status.go:268-293 | [p](procedures/crd.md#gameserver-phase-pending-to-starting) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-CRD-003 | Phase transition Starting → Running | operator/ | operator/internal/controller/gameserver_status.go:268-293 | [p](procedures/crd.md#gameserver-phase-starting-to-running) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-CRD-004 | Suspend (soft stop) game server | operator/ | operator/internal/controller/gameserver_controller.go:255-470 | [p](procedures/crd.md#gameserver-suspend) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-CRD-005 | Unsuspend and wake game server | operator/ | operator/internal/controller/gameserver_controller.go:255-470 | [p](procedures/crd.md#gameserver-unsuspend-wake) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-CRD-006 | Restart game server pod | operator/ | operator/internal/controller/gameserver_restart.go:1-50 | [p](procedures/crd.md#gameserver-restart) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-CRD-007 | Switch server version | operator/ | operator/internal/controller/gameserver_version.go:1-100 | [p](procedures/crd.md#gameserver-version-switch) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-CRD-008 | Wipe server data volume | operator/ | operator/internal/controller/gameserver_wipe.go:1-150 | [p](procedures/crd.md#gameserver-wipe-data-volume) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-CRD-009 | Idle auto-sleep (zero players) | operator/ | operator/internal/controller/gameserver_idle.go:1-150 | [p](procedures/crd.md#gameserver-idle-auto-sleep) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-CRD-010 | Wake via scheduled window | operator/ | operator/internal/controller/gameserver_idle.go:1-150 | [p](procedures/crd.md#gameserver-idle-wake-window) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-CRD-011 | Wake on player connect (sentinel) | operator/ | operator/internal/controller/gameserver_sentinel.go:1-200 | [p](procedures/crd.md#gameserver-idle-wake-on-connect) | none | pass | user-facing; sentinel pod injected | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-CRD-012 | Delete game server (no finalizer) | operator/ | operator/internal/controller/gameserver_controller.go:255-470 | [p](procedures/crd.md#gameserver-delete-no-finalizer) | none | pass | retitled at OD-021 item 22: GameServers carry no finalizer (`gameserver_controller.go` never calls `AddFinalizer`); cleanup is by ownerReference garbage collection, not a finalizer wait — see F-260 in `audit/findings.md` | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-CRD-013 | Phase Failed (crash loop) | operator/ | operator/internal/controller/gameserver_status.go:104-135 | [p](procedures/crd.md#gameserver-failed-phase-crash-loop) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-CRD-014 | Create game template | operator/ | operator/api/v1alpha1/gametemplate_types.go:1-200 | [p](procedures/crd.md#gametemplate-create) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-CRD-015 | Create backup (Pending → Running) | operator/ | operator/internal/controller/backup_controller.go:173-263 | [p](procedures/crd.md#backup-create-and-run) | TestBackup_OperatorMaterializesJob, TestRestore_RoundTrip | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-CRD-016 | Backup phase Running → Succeeded | operator/ | operator/internal/controller/backup_controller.go:316-450 | [p](procedures/crd.md#backup-create-and-run) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-CRD-017 | Backup phase failure (Failed) | operator/ | operator/internal/controller/backup_controller.go:584-607 | [p](procedures/crd.md#backup-failure-and-phase) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-CRD-018 | Restore Pending → Suspending | operator/ | operator/internal/controller/restore_controller.go:40-200 | [p](procedures/crd.md#restore-create-and-suspend-server) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-CRD-019 | Restore Suspending → Running | operator/ | operator/internal/controller/restore_controller.go:40-200 | [p](procedures/crd.md#restore-create-and-suspend-server) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-CRD-020 | Restore Running → Succeeded (no Resuming phase) | operator/ | operator/internal/controller/restore_controller.go:40-200 | [p](procedures/crd.md#restore-running-to-succeeded) | none | pass | retitled at OD-021 item 22: `RestorePhase` declares `Resuming` (`operator/api/v1alpha1/restore_types.go:8-16`) but `restore_controller.go` never assigns it; the transition out of Running goes straight to Succeeded/Failed — see F-260 in `audit/findings.md` | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-CRD-021 | BackupSchedule create and schedule | operator/ | operator/internal/controller/backupschedule_controller.go:49-200 | [p](procedures/crd.md#backup-schedule-create) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-CRD-022 | BackupSchedule tick creates Backup | operator/ | operator/internal/controller/backupschedule_controller.go:49-200 | [p](procedures/crd.md#backup-schedule-tick-creates-backup) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-CRD-023 | BackupSchedule retention prunes backups | operator/ | operator/internal/controller/backupschedule_controller.go:49-200 | [p](procedures/crd.md#backup-schedule-retention-prunes) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-CRD-024 | Module Pending phase (version resolving) | operator/ | operator/internal/controller/module_controller.go:58-150 | [p](procedures/crd.md#module-create-pending) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-CRD-025 | Module Pulling → Ready (materialize template) | operator/ | operator/internal/controller/module_controller.go:58-150 | [p](procedures/crd.md#module-pulling-to-ready) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-CRD-026 | Module bad signature fails (cosign verify) | operator/ | operator/internal/controller/module_controller.go:58-150 | [p](procedures/crd.md#module-bad-signature-fails) | none | pass | not a blocked candidate: per OD-021 items 6/21, both a signed and an unsigned bundle are pushed to the in-cluster `audit018-registry` (set up at round setup); this row uses the unsigned one | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-CRD-027 | ModuleSource OCI periodic refresh/sync | operator/ | operator/internal/controller/modulesource_controller.go:51-150 | [p](procedures/crd.md#modulesource-oci-sync) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-CRD-028 | ModuleSource git sync error | operator/ | operator/internal/controller/modulesource_controller.go:51-150 | [p](procedures/crd.md#modulesource-git-sync-error) | none | pass | blocked candidate: requires intentional git repo failure; alternative: observe sync timeout with slow network | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | | INV-CRD-029 | Cluster register and health check | operator/ | operator/internal/controller/cluster_controller.go:31-170 | [p](procedures/crd.md#cluster-register-blocked-candidate) | none | blocked | OD-021 item 19: blocked, no second live cluster available to the audit; anchor renamed to match. Verified live instead: an unregistered `?cluster=` selector gets HTTP 400 `cluster not permitted` from the RBAC allow-list (`scope.ResolveCluster`) before dispatch. The `rejectRemoteCluster` guard (`resources.go:104-110`) itself only fires for a *registered* remote cluster, which the audit lacks; it returns 501 with body `httperr.RemoteClusterNotImplemented` (`resources.go:106`, `httperr.go:33-34`), per OD-021 item 19 (#430) — see procedures/crd.md step 4 | [e](evidence/INV-CRD-029/) | | | | INV-CRD-030 | Cluster health check failure (Unhealthy) | operator/ | operator/internal/controller/cluster_controller.go:130-165 | [p](procedures/crd.md#cluster-health-check-unreachable) | none | blocked | OD-021 item 19: blocked, cascades from INV-CRD-029 (no second live cluster to register first) | [e](evidence/INV-CRD-030/) | | | -| INV-CRD-031 | NetworkCapture Pending phase | operator/ | operator/internal/controller/networkcapture_controller.go:139-250 | [p](procedures/crd.md#networkcapture-create-pending) | none | untested | user-facing; requires capture sidecar enabled | [e](evidence/INV-CRD-031/) | | | -| INV-CRD-032 | NetworkCapture Pending → Running | operator/ | operator/internal/controller/networkcapture_controller.go:139-250 | [p](procedures/crd.md#networkcapture-start-running) | none | untested | user-facing; requires capture sidecar enabled | [e](evidence/INV-CRD-032/) | | | -| INV-CRD-033 | NetworkCapture stop and complete | operator/ | operator/internal/controller/networkcapture_controller.go:139-250 | [p](procedures/crd.md#networkcapture-stop-completed) | none | untested | user-facing; requires capture sidecar enabled | [e](evidence/INV-CRD-033/) | | | -| INV-CRD-034 | NetworkCapture failure (sidecar crash) | operator/ | operator/internal/controller/networkcapture_controller.go:139-250 | [p](procedures/crd.md#networkcapture-failed-sidecar-crash) | none | untested | user-facing; ephemeral container restart behavior | [e](evidence/INV-CRD-034/) | | | -| INV-CRD-035 | NetworkCapture auto-delete after TTL | operator/ | operator/internal/controller/networkcapture_controller.go:139-250 | [p](procedures/crd.md#networkcapture-expired-auto-delete) | none | untested | user-facing; garbage collection | [e](evidence/INV-CRD-035/) | | | -| INV-CRD-036 | Create backup using VolumeSnapshot strategy (spec.strategy=volume-snapshot) | operator/ | operator/internal/controller/backup_volumesnapshot.go:26-68 | [p](procedures/crd.md#backup-volumesnapshot-strategy) | TestBackup_VolumeSnapshotSucceeds | untested | | [e](evidence/INV-CRD-036/) | | | -| INV-CRD-037 | Restore from a VolumeSnapshot-strategy backup | operator/ | operator/internal/controller/restore_volumesnapshot.go:24-103 | [p](procedures/crd.md#restore-volumesnapshot-strategy) | TestRestore_VolumeSnapshotProvisionsNewServer | untested | | [e](evidence/INV-CRD-037/) | | | +| INV-CRD-031 | NetworkCapture Pending phase | operator/ | operator/internal/controller/networkcapture_controller.go:139-250 | [p](procedures/crd.md#networkcapture-create-pending) | none | pass | user-facing; requires capture sidecar enabled | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-CRD-032 | NetworkCapture Pending → Running | operator/ | operator/internal/controller/networkcapture_controller.go:139-250 | [p](procedures/crd.md#networkcapture-start-running) | none | pass | user-facing; requires capture sidecar enabled | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-CRD-033 | NetworkCapture stop and complete | operator/ | operator/internal/controller/networkcapture_controller.go:139-250 | [p](procedures/crd.md#networkcapture-stop-completed) | none | pass | user-facing; requires capture sidecar enabled | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-CRD-034 | NetworkCapture failure (sidecar crash) | operator/ | operator/internal/controller/networkcapture_controller.go:139-250 | [p](procedures/crd.md#networkcapture-failed-sidecar-crash) | none | pass | user-facing; ephemeral container restart behavior | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-CRD-035 | NetworkCapture auto-delete after TTL | operator/ | operator/internal/controller/networkcapture_controller.go:139-250 | [p](procedures/crd.md#networkcapture-expired-auto-delete) | none | pass | user-facing; garbage collection | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-CRD-036 | Create backup using VolumeSnapshot strategy (spec.strategy=volume-snapshot) | operator/ | operator/internal/controller/backup_volumesnapshot.go:26-68 | [p](procedures/crd.md#backup-volumesnapshot-strategy) | TestBackup_VolumeSnapshotSucceeds | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-CRD-037 | Restore from a VolumeSnapshot-strategy backup | operator/ | operator/internal/controller/restore_volumesnapshot.go:24-103 | [p](procedures/crd.md#restore-volumesnapshot-strategy) | TestRestore_VolumeSnapshotProvisionsNewServer | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | | ID | Capability | Component | Source | Procedure | CI test | Outcome | Reason | Evidence | Round | Findings | |----|------------|-----------|--------|-----------|---------|---------|--------|----------|-------|----------| ## AGT | ID | Capability | Component | Source | Procedure | CI test | Outcome | Reason | Evidence | Round | Findings | |----|------------|-----------|--------|-----------|---------|---------|--------|----------|-------|----------| -| INV-AGT-001 | Execute command via source RCON | agent/internal/console | agent/internal/rcon/rcon.go:122-188 | [p](procedures/agent.md#console-source) | none | untested | | [e](evidence/INV-AGT-001/) | | | -| INV-AGT-002 | Execute command via telnet RCON | agent/internal/console | agent/internal/rcon/telnet.go:1 | [p](procedures/agent.md#console-telnet) | none | untested | | [e](evidence/INV-AGT-002/) | | | -| INV-AGT-003 | Execute command via websocket RCON | agent/internal/console | agent/internal/rcon/websocket.go:1 | [p](procedures/agent.md#console-websocket) | none | untested | | [e](evidence/INV-AGT-003/) | | | -| INV-AGT-004 | Execute command via battleye RCON | agent/internal/console | agent/internal/rcon/battleye.go:1 | [p](procedures/agent.md#console-battleye) | none | untested | | [e](evidence/INV-AGT-004/) | | | -| INV-AGT-005 | Execute command via satisfactory RCON | agent/internal/console | agent/internal/rcon/satisfactory.go:1 | [p](procedures/agent.md#console-satisfactory) | none | untested | | [e](evidence/INV-AGT-005/) | | | -| INV-AGT-006 | Execute command via palworld RCON | agent/internal/console | agent/internal/rcon/palworld.go:1 | [p](procedures/agent.md#console-palworld) | none | untested | | [e](evidence/INV-AGT-006/) | | | -| INV-AGT-007 | Execute command via nuclearoption RCON | agent/internal/console | agent/internal/rcon/nuclearoption.go:1 | [p](procedures/agent.md#console-nuclearoption) | none | untested | | [e](evidence/INV-AGT-007/) | | | -| INV-AGT-008 | Execute command via REST RCON | agent/internal/console | agent/internal/rcon/rest.go:1 | [p](procedures/agent.md#console-rest) | none | untested | | [e](evidence/INV-AGT-008/) | | | -| INV-AGT-009 | Execute command via PTY console | agent/internal/console | api/internal/ws/attach.go:41-46 | [p](procedures/agent.md#console-pty) | none | untested | | [e](evidence/INV-AGT-009/) | | | -| INV-AGT-010 | List files and directories | agent/internal/files | agent/internal/files/files.go:37 | [p](procedures/agent.md#files-list) | none | untested | | [e](evidence/INV-AGT-010/) | | | -| INV-AGT-011 | Read file contents | agent/internal/files | agent/internal/files/files.go:38 | [p](procedures/agent.md#files-read) | none | untested | | [e](evidence/INV-AGT-011/) | | | -| INV-AGT-012 | Write or overwrite file | agent/internal/files | agent/internal/files/files.go:40 | [p](procedures/agent.md#files-write) | none | untested | | [e](evidence/INV-AGT-012/) | | | -| INV-AGT-013 | Upload file to server | agent/internal/files | agent/internal/files/files.go:41 | [p](procedures/agent.md#files-upload) | TestAPI_AgentFilesRoundTrip | untested | | [e](evidence/INV-AGT-013/) | | | -| INV-AGT-014 | Download file from server | agent/internal/files | agent/internal/files/files.go:39 | [p](procedures/agent.md#files-download) | TestAPI_AgentFilesRoundTrip | untested | | [e](evidence/INV-AGT-014/) | | | -| INV-AGT-015 | Create directory | agent/internal/files | agent/internal/files/files.go:42 | [p](procedures/agent.md#files-mkdir) | none | untested | | [e](evidence/INV-AGT-015/) | | | -| INV-AGT-016 | Delete file or directory | agent/internal/files | agent/internal/files/files.go:43 | [p](procedures/agent.md#files-delete) | TestAPI_AgentFilesRoundTrip | untested | | [e](evidence/INV-AGT-016/) | | | -| INV-AGT-017 | Stream log file via WebSocket | agent/internal/logs | agent/internal/logs/logs.go:31 | [p](procedures/agent.md#logs-tail) | none | untested | | [e](evidence/INV-AGT-017/) | | | -| INV-AGT-018 | Download complete log file | agent/internal/logs | agent/internal/logs/logs.go:32 | [p](procedures/agent.md#logs-download) | none | untested | | [e](evidence/INV-AGT-018/) | | | -| INV-AGT-019 | List online players | agent/internal/players | agent/internal/players/players.go:97 | [p](procedures/agent.md#players-list) | none | untested | | [e](evidence/INV-AGT-019/) | | | -| INV-AGT-020 | List banned players | agent/internal/players | agent/internal/players/players.go:98 | [p](procedures/agent.md#players-banned) | none | untested | | [e](evidence/INV-AGT-020/) | | | -| INV-AGT-021 | Kick player from server | agent/internal/players | agent/internal/players/players.go:99 | [p](procedures/agent.md#players-kick) | TestAPI_AgentPlayers | untested | | [e](evidence/INV-AGT-021/) | | | -| INV-AGT-022 | Ban player from server | agent/internal/players | agent/internal/players/players.go:100 | [p](procedures/agent.md#players-ban) | TestAPI_AgentPlayers | untested | | [e](evidence/INV-AGT-022/) | | | -| INV-AGT-023 | Unban player from server | agent/internal/players | agent/internal/players/players.go:101 | [p](procedures/agent.md#players-unban) | TestAPI_AgentPlayers | untested | | [e](evidence/INV-AGT-023/) | | | -| INV-AGT-024 | List whitelisted players | agent/internal/players | agent/internal/players/players.go:102 | [p](procedures/agent.md#players-whitelist) | none | untested | | [e](evidence/INV-AGT-024/) | | | -| INV-AGT-025 | Add player to whitelist | agent/internal/players | agent/internal/players/players.go:103 | [p](procedures/agent.md#players-whitelist-add) | TestAPI_AgentPlayers | untested | | [e](evidence/INV-AGT-025/) | | | -| INV-AGT-026 | Remove player from whitelist | agent/internal/players | agent/internal/players/players.go:104 | [p](procedures/agent.md#players-whitelist-remove) | TestAPI_AgentPlayers | untested | | [e](evidence/INV-AGT-026/) | | | -| INV-AGT-027 | Pause game writes (quiesce) | agent/internal/quiesce | agent/internal/quiesce/quiesce.go:62 | [p](procedures/agent.md#quiesce-pause) | none | untested | | [e](evidence/INV-AGT-027/) | | | -| INV-AGT-028 | Resume game writes (unquiesce) | agent/internal/quiesce | agent/internal/quiesce/quiesce.go:74 | [p](procedures/agent.md#quiesce-resume) | none | untested | | [e](evidence/INV-AGT-028/) | | | -| INV-AGT-029 | Execute stop sequence | agent/internal/lifecycle | agent/internal/lifecycle/lifecycle.go:56 | [p](procedures/agent.md#lifecycle-stop) | none | untested | | [e](evidence/INV-AGT-029/) | | | -| INV-AGT-030 | Run module-declared action | agent/internal/actions | agent/internal/actions/actions.go:53 | [p](procedures/agent.md#actions-run) | none | untested | | [e](evidence/INV-AGT-030/) | | | -| INV-AGT-031 | Retrieve live status metrics | agent/internal/status | agent/internal/status/status.go:68 | [p](procedures/agent.md#status-metrics) | none | untested | | [e](evidence/INV-AGT-031/) | | | -| INV-AGT-032 | List installed mods | agent/internal/mods | agent/internal/mods/mods.go:72 | [p](procedures/agent.md#mods-list) | TestAPI_ModManifestInstallUpgrade | untested | | [e](evidence/INV-AGT-032/) | | | -| INV-AGT-033 | Install mod from URL | agent/internal/mods | agent/internal/mods/mods.go:73 | [p](procedures/agent.md#mods-install) | TestAPI_ModManifestInstallUpgrade, TestAPI_ModUpload | untested | | [e](evidence/INV-AGT-033/) | | | -| INV-AGT-034 | Upload mod file | agent/internal/mods | agent/internal/mods/mods.go:74 | [p](procedures/agent.md#mods-upload) | none | untested | | [e](evidence/INV-AGT-034/) | | | -| INV-AGT-035 | Remove installed mod | agent/internal/mods | agent/internal/mods/mods.go:75 | [p](procedures/agent.md#mods-remove) | TestAPI_ModManifestInstallUpgrade | untested | | [e](evidence/INV-AGT-035/) | | | -| INV-AGT-036 | Report metrics via Prometheus | agent/internal/heartbeat | agent/cmd/main.go:199 | [p](procedures/agent.md#heartbeat-metrics) | none | untested | | [e](evidence/INV-AGT-036/) | | | +| INV-AGT-001 | Execute command via source RCON | agent/internal/console | agent/internal/rcon/rcon.go:122-188 | [p](procedures/agent.md#console-source) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AGT-002 | Execute command via telnet RCON | agent/internal/console | agent/internal/rcon/telnet.go:1 | [p](procedures/agent.md#console-telnet) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AGT-003 | Execute command via websocket RCON | agent/internal/console | agent/internal/rcon/websocket.go:1 | [p](procedures/agent.md#console-websocket) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AGT-004 | Execute command via battleye RCON | agent/internal/console | agent/internal/rcon/battleye.go:1 | [p](procedures/agent.md#console-battleye) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AGT-005 | Execute command via satisfactory RCON | agent/internal/console | agent/internal/rcon/satisfactory.go:1 | [p](procedures/agent.md#console-satisfactory) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AGT-006 | Execute command via palworld RCON | agent/internal/console | agent/internal/rcon/palworld.go:1 | [p](procedures/agent.md#console-palworld) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AGT-007 | Execute command via nuclearoption RCON | agent/internal/console | agent/internal/rcon/nuclearoption.go:1 | [p](procedures/agent.md#console-nuclearoption) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AGT-008 | Execute command via REST RCON | agent/internal/console | agent/internal/rcon/rest.go:1 | [p](procedures/agent.md#console-rest) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AGT-009 | Execute command via PTY console | agent/internal/console | api/internal/ws/attach.go:41-46 | [p](procedures/agent.md#console-pty) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AGT-010 | List files and directories | agent/internal/files | agent/internal/files/files.go:37 | [p](procedures/agent.md#files-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AGT-011 | Read file contents | agent/internal/files | agent/internal/files/files.go:38 | [p](procedures/agent.md#files-read) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AGT-012 | Write or overwrite file | agent/internal/files | agent/internal/files/files.go:40 | [p](procedures/agent.md#files-write) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AGT-013 | Upload file to server | agent/internal/files | agent/internal/files/files.go:41 | [p](procedures/agent.md#files-upload) | TestAPI_AgentFilesRoundTrip | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AGT-014 | Download file from server | agent/internal/files | agent/internal/files/files.go:39 | [p](procedures/agent.md#files-download) | TestAPI_AgentFilesRoundTrip | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AGT-015 | Create directory | agent/internal/files | agent/internal/files/files.go:42 | [p](procedures/agent.md#files-mkdir) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AGT-016 | Delete file or directory | agent/internal/files | agent/internal/files/files.go:43 | [p](procedures/agent.md#files-delete) | TestAPI_AgentFilesRoundTrip | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AGT-017 | Stream log file via WebSocket | agent/internal/logs | agent/internal/logs/logs.go:31 | [p](procedures/agent.md#logs-tail) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AGT-018 | Download complete log file | agent/internal/logs | agent/internal/logs/logs.go:32 | [p](procedures/agent.md#logs-download) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AGT-019 | List online players | agent/internal/players | agent/internal/players/players.go:97 | [p](procedures/agent.md#players-list) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AGT-020 | List banned players | agent/internal/players | agent/internal/players/players.go:98 | [p](procedures/agent.md#players-banned) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AGT-021 | Kick player from server | agent/internal/players | agent/internal/players/players.go:99 | [p](procedures/agent.md#players-kick) | TestAPI_AgentPlayers | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AGT-022 | Ban player from server | agent/internal/players | agent/internal/players/players.go:100 | [p](procedures/agent.md#players-ban) | TestAPI_AgentPlayers | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AGT-023 | Unban player from server | agent/internal/players | agent/internal/players/players.go:101 | [p](procedures/agent.md#players-unban) | TestAPI_AgentPlayers | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AGT-024 | List whitelisted players | agent/internal/players | agent/internal/players/players.go:102 | [p](procedures/agent.md#players-whitelist) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AGT-025 | Add player to whitelist | agent/internal/players | agent/internal/players/players.go:103 | [p](procedures/agent.md#players-whitelist-add) | TestAPI_AgentPlayers | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AGT-026 | Remove player from whitelist | agent/internal/players | agent/internal/players/players.go:104 | [p](procedures/agent.md#players-whitelist-remove) | TestAPI_AgentPlayers | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AGT-027 | Pause game writes (quiesce) | agent/internal/quiesce | agent/internal/quiesce/quiesce.go:62 | [p](procedures/agent.md#quiesce-pause) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AGT-028 | Resume game writes (unquiesce) | agent/internal/quiesce | agent/internal/quiesce/quiesce.go:74 | [p](procedures/agent.md#quiesce-resume) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AGT-029 | Execute stop sequence | agent/internal/lifecycle | agent/internal/lifecycle/lifecycle.go:56 | [p](procedures/agent.md#lifecycle-stop) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AGT-030 | Run module-declared action | agent/internal/actions | agent/internal/actions/actions.go:53 | [p](procedures/agent.md#actions-run) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AGT-031 | Retrieve live status metrics | agent/internal/status | agent/internal/status/status.go:68 | [p](procedures/agent.md#status-metrics) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AGT-032 | List installed mods | agent/internal/mods | agent/internal/mods/mods.go:72 | [p](procedures/agent.md#mods-list) | TestAPI_ModManifestInstallUpgrade | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AGT-033 | Install mod from URL | agent/internal/mods | agent/internal/mods/mods.go:73 | [p](procedures/agent.md#mods-install) | TestAPI_ModManifestInstallUpgrade, TestAPI_ModUpload | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AGT-034 | Upload mod file | agent/internal/mods | agent/internal/mods/mods.go:74 | [p](procedures/agent.md#mods-upload) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AGT-035 | Remove installed mod | agent/internal/mods | agent/internal/mods/mods.go:75 | [p](procedures/agent.md#mods-remove) | TestAPI_ModManifestInstallUpgrade | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AGT-036 | Report metrics via Prometheus | agent/internal/heartbeat | agent/cmd/main.go:199 | [p](procedures/agent.md#heartbeat-metrics) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | | ID | Capability | Component | Source | Procedure | CI test | Outcome | Reason | Evidence | Round | Findings | |----|------------|-----------|--------|-----------|---------|---------|--------|----------|-------|----------| ## AUX | ID | Capability | Component | Source | Procedure | CI test | Outcome | Reason | Evidence | Round | Findings | |----|------------|-----------|--------|-----------|---------|---------|--------|----------|-------|----------| -| INV-AUX-001 | Detect join vs status on Minecraft (wakeProtocol=minecraft) | sentinel/ | sentinel/main.go:41-58 | [p](procedures/aux.md#sentinel-minecraft-status-ping) | none | untested | | [e](evidence/INV-AUX-001/) | | | -| INV-AUX-002 | Detect Minecraft join handshake and patch wake annotation | sentinel/ | sentinel/main.go:41-58 | [p](procedures/aux.md#sentinel-minecraft-join-wake) | none | untested | | [e](evidence/INV-AUX-002/) | | | -| INV-AUX-003 | Detect Terraria join attempt via gameproto classifier | sentinel/ | sentinel/main.go:41-58, gameproto/terraria.go | [p](procedures/aux.md#sentinel-terraria-generic-udp) | none | untested | | [e](evidence/INV-AUX-003/) | | | -| INV-AUX-004 | UDP packet-counting heuristic for generic wake detection | sentinel/ | sentinel/main.go (UDP heuristic) | [p](procedures/aux.md#sentinel-terraria-generic-udp) | none | untested | | [e](evidence/INV-AUX-004/) | | | -| INV-AUX-005 | Start network packet capture with BPF filter | capture-sidecar/ | capture-sidecar/cmd/main.go, capture-sidecar/internal/capture/afpacket.go | [p](procedures/aux.md#capture-sidecar-start-stop) | TestGameServer_NetworkCaptureStartStopDownload | untested | | [e](evidence/INV-AUX-005/) | | | -| INV-AUX-006 | Stop capture and finalize PCAPNG file | capture-sidecar/ | capture-sidecar/internal/capture/writer.go | [p](procedures/aux.md#capture-sidecar-start-stop) | none | untested | | [e](evidence/INV-AUX-006/) | | | -| INV-AUX-007 | Download completed capture file via mTLS HTTP endpoint | capture-sidecar/ | capture-sidecar/internal/httpserver/handlers.go | [p](procedures/aux.md#capture-sidecar-start-stop) | none | untested | | [e](evidence/INV-AUX-007/) | | | -| INV-AUX-008 | Enforce capture size and duration limits | capture-sidecar/ | capture-sidecar/internal/capture/writer.go | [p](procedures/aux.md#capture-sidecar-start-stop) | none | untested | | [e](evidence/INV-AUX-008/) | | | +| INV-AUX-001 | Detect join vs status on Minecraft (wakeProtocol=minecraft) | sentinel/ | sentinel/main.go:41-58 | [p](procedures/aux.md#sentinel-minecraft-status-ping) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AUX-002 | Detect Minecraft join handshake and patch wake annotation | sentinel/ | sentinel/main.go:41-58 | [p](procedures/aux.md#sentinel-minecraft-join-wake) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AUX-003 | Detect Terraria join attempt via gameproto classifier | sentinel/ | sentinel/main.go:41-58, gameproto/terraria.go | [p](procedures/aux.md#sentinel-terraria-generic-udp) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AUX-004 | UDP packet-counting heuristic for generic wake detection | sentinel/ | sentinel/main.go (UDP heuristic) | [p](procedures/aux.md#sentinel-terraria-generic-udp) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AUX-005 | Start network packet capture with BPF filter | capture-sidecar/ | capture-sidecar/cmd/main.go, capture-sidecar/internal/capture/afpacket.go | [p](procedures/aux.md#capture-sidecar-start-stop) | TestGameServer_NetworkCaptureStartStopDownload | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AUX-006 | Stop capture and finalize PCAPNG file | capture-sidecar/ | capture-sidecar/internal/capture/writer.go | [p](procedures/aux.md#capture-sidecar-start-stop) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AUX-007 | Download completed capture file via mTLS HTTP endpoint | capture-sidecar/ | capture-sidecar/internal/httpserver/handlers.go | [p](procedures/aux.md#capture-sidecar-start-stop) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AUX-008 | Enforce capture size and duration limits | capture-sidecar/ | capture-sidecar/internal/capture/writer.go | [p](procedures/aux.md#capture-sidecar-start-stop) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | | INV-AUX-009 | Supervise frp (forward proxy) relay client | tunnel/ | tunnel/main.go:1-18, charts/gameplane/values.yaml:85 | [p](procedures/aux.md#tunnel-frp-blocked-candidate) | none | blocked | blocked candidate: needs external frp server; alternative: test operator tunnel injection via envtest (api-agent bucket) | [e](evidence/INV-AUX-009/) | | | | INV-AUX-010 | Supervise Tailscale relay client | tunnel/ | tunnel/main.go:1-18, charts/gameplane/values.yaml:86 | [p](procedures/aux.md#tunnel-tailscale-blocked-candidate) | none | blocked | blocked candidate: needs Tailscale account and auth key; alternative: test operator injection | [e](evidence/INV-AUX-010/) | | | | INV-AUX-011 | Supervise playit relay client | tunnel/ | tunnel/main.go:1-18, charts/gameplane/values.yaml:87 | [p](procedures/aux.md#tunnel-playit-blocked-candidate) | none | blocked | blocked candidate: needs playit.gg account and secret key; alternative: test operator injection | [e](evidence/INV-AUX-011/) | | | | INV-AUX-012 | Accept HTTP audit events and relay to syslog collector | audit-syslog-bridge/ | audit-syslog-bridge/README.md, audit-syslog-bridge/main.go:1-30, charts/gameplane/values.yaml:183 | [p](procedures/aux.md#audit-syslog-bridge-blocked-candidate) | none | blocked | blocked candidate: needs external RFC 5424 syslog receiver; alternative: test with local netcat listener (api-auth bucket) | [e](evidence/INV-AUX-012/) | | | | INV-AUX-013 | Format and send RFC 5424 syslog records | audit-syslog-bridge/ | audit-syslog-bridge/main.go | [p](procedures/aux.md#audit-syslog-bridge-blocked-candidate) | none | blocked | blocked candidate: needs external syslog collector | [e](evidence/INV-AUX-013/) | | | -| INV-AUX-014 | Accept and aggregate anonymous usage telemetry reports | telemetry-receiver/ | telemetry-receiver/main.go, charts/gameplane/values.yaml:235 | [p](procedures/aux.md#telemetry-receiver-opt-in) | none | untested | | [e](evidence/INV-AUX-014/) | | | -| INV-AUX-015 | Expose aggregated telemetry metrics on /metrics endpoint | telemetry-receiver/ | telemetry-receiver/main.go | [p](procedures/aux.md#telemetry-receiver-opt-in) | none | untested | | [e](evidence/INV-AUX-015/) | | | -| INV-AUX-016 | Provide read-only Model Context Protocol (MCP) interface | mcp-server/ | mcp-server/README.md, mcp-server/main.go, charts/gameplane/values.yaml:400 | [p](procedures/aux.md#mcp-server-read-only-check) | none | untested | | [e](evidence/INV-AUX-016/) | | | -| INV-AUX-017 | List Gameplane CRDs (GameServers, GameTemplates, etc.) via MCP | mcp-server/ | mcp-server/tools.go | [p](procedures/aux.md#mcp-server-read-only-check) | none | untested | | [e](evidence/INV-AUX-017/) | | | -| INV-AUX-018 | Structurally enforce read-only access (no mutating methods) | mcp-server/ | mcp-server/main.go, mcp-server/internal/kube/client.go | [p](procedures/aux.md#mcp-server-read-only-check) | none | untested | | [e](evidence/INV-AUX-018/) | | | +| INV-AUX-014 | Accept and aggregate anonymous usage telemetry reports | telemetry-receiver/ | telemetry-receiver/main.go, charts/gameplane/values.yaml:235 | [p](procedures/aux.md#telemetry-receiver-opt-in) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AUX-015 | Expose aggregated telemetry metrics on /metrics endpoint | telemetry-receiver/ | telemetry-receiver/main.go | [p](procedures/aux.md#telemetry-receiver-opt-in) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AUX-016 | Provide read-only Model Context Protocol (MCP) interface | mcp-server/ | mcp-server/README.md, mcp-server/main.go, charts/gameplane/values.yaml:400 | [p](procedures/aux.md#mcp-server-read-only-check) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AUX-017 | List Gameplane CRDs (GameServers, GameTemplates, etc.) via MCP | mcp-server/ | mcp-server/tools.go | [p](procedures/aux.md#mcp-server-read-only-check) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-AUX-018 | Structurally enforce read-only access (no mutating methods) | mcp-server/ | mcp-server/main.go, mcp-server/internal/kube/client.go | [p](procedures/aux.md#mcp-server-read-only-check) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | | ID | Capability | Component | Source | Procedure | CI test | Outcome | Reason | Evidence | Round | Findings | |----|------------|-----------|--------|-----------|---------|---------|--------|----------|-------|----------| ## HELM | ID | Capability | Component | Source | Procedure | CI test | Outcome | Reason | Evidence | Round | Findings | |----|------------|-----------|--------|-----------|---------|---------|--------|----------|-------|----------| -| INV-HELM-001 | Enable OIDC authentication | api/ | charts/gameplane/values.yaml:240 | [p](procedures/helm.md#oidc-authentication) | none | untested | blocked candidate: needs external OIDC IdP; alternative: test with mock IdP stub | [e](evidence/INV-HELM-001/) | | | -| INV-HELM-002 | Configure audit webhook sink | api/ | charts/gameplane/values.yaml:160 | [p](procedures/helm.md#audit-webhook-sink) | none | untested | | [e](evidence/INV-HELM-002/) | | | -| INV-HELM-003 | Enable syslog bridge for audit events | audit-syslog-bridge/ | charts/gameplane/values.yaml:183 | [p](procedures/helm.md#syslog-bridge-audit) | none | untested | | [e](evidence/INV-HELM-003/) | | | -| INV-HELM-004 | Configure S3 audit sink | api/ | charts/gameplane/values.yaml:202 | [p](procedures/helm.md#s3-audit-sink) | none | untested | blocked candidate: needs S3-compatible endpoint; alternative: mock MinIO if available on kubelab | [e](evidence/INV-HELM-004/) | | | -| INV-HELM-005 | Enable audit event stdout logging | api/ | charts/gameplane/values.yaml:153 | [p](procedures/helm.md#audit-stdout-logging) | none | untested | | [e](evidence/INV-HELM-005/) | | | -| INV-HELM-006 | Configure telemetry collection endpoint | api/ | charts/gameplane/values.yaml:222 | [p](procedures/helm.md#telemetry-collection) | none | untested | blocked candidate: telemetry sent daily; requires deterministic triggers or extended wait | [e](evidence/INV-HELM-006/) | | | -| INV-HELM-007 | Enable bundled telemetry receiver | telemetry-receiver/ | charts/gameplane/values.yaml:235 | [p](procedures/helm.md#telemetry-receiver-bundled) | none | untested | | [e](evidence/INV-HELM-007/) | | | -| INV-HELM-008 | Enable cluster operations feature | api/ | charts/gameplane/values.yaml:392 | [p](procedures/helm.md#cluster-operations-feature) | none | untested | | [e](evidence/INV-HELM-008/) | | | -| INV-HELM-009 | Enable MCP (Model Context Protocol) server | mcp-server/ | charts/gameplane/values.yaml:400 | [p](procedures/helm.md#mcp-server-deployment) | none | untested | | [e](evidence/INV-HELM-009/) | | | -| INV-HELM-010 | Enable default-deny network policies | operator/ | charts/gameplane/values.yaml:316 | [p](procedures/helm.md#network-policies-enforcement) | none | untested | | [e](evidence/INV-HELM-010/) | | | -| INV-HELM-011 | Enforce restricted pod security policy | operator/ | charts/gameplane/values.yaml:440 | [p](procedures/helm.md#pod-security-enforcement) | none | untested | | [e](evidence/INV-HELM-011/) | | | -| INV-HELM-012 | Enable game pod egress to public internet | operator/ | charts/gameplane/values.yaml:343 | [p](procedures/helm.md#game-egress-policies) | none | untested | blocked candidate: requires GameServer pod startup for network testing | [e](evidence/INV-HELM-012/) | | | -| INV-HELM-013 | Enable per-GameServer ingress network policies | operator/ | charts/gameplane/values.yaml:371 | [p](procedures/helm.md#game-ingress-policies) | none | untested | blocked candidate: requires GameServer pod startup and external connectivity | [e](evidence/INV-HELM-013/) | | | -| INV-HELM-014 | Create Prometheus ServiceMonitor objects | charts/gameplane/ | charts/gameplane/values.yaml:418 | [p](procedures/helm.md#service-monitors) | none | untested | blocked candidate: needs Prometheus Operator CRDs (ServiceMonitor); alternative: verify on cluster with CRDs | [e](evidence/INV-HELM-014/) | | | -| INV-HELM-015 | Create Prometheus alert rules | charts/gameplane/ | charts/gameplane/values.yaml:428 | [p](procedures/helm.md#prometheus-rules) | none | untested | blocked candidate: needs Prometheus Operator CRDs (PrometheusRule); alternative: verify on cluster with CRDs | [e](evidence/INV-HELM-015/) | | | -| INV-HELM-016 | Create Grafana dashboard ConfigMap | charts/gameplane/ | charts/gameplane/values.yaml:435 | [p](procedures/helm.md#grafana-dashboards) | none | untested | blocked candidate: needs Grafana with sidecar loader; alternative: verify on Grafana-equipped cluster | [e](evidence/INV-HELM-016/) | | | -| INV-HELM-017 | Enable default module source | operator/ | charts/gameplane/values.yaml:446 | [p](procedures/helm.md#default-module-source) | none | untested | | [e](evidence/INV-HELM-017/) | | | -| INV-HELM-018 | Enable module bundle signature verification | operator/ | charts/gameplane/values.yaml:507 | [p](procedures/helm.md#module-signature-verification) | none | untested | blocked candidate: requires pulling and validating module bundles; alternative: verify ModuleSource spec includes verify settings | [e](evidence/INV-HELM-018/) | | | -| INV-HELM-019 | Enable dashboard module upload source | operator/ | charts/gameplane/values.yaml:518 | [p](procedures/helm.md#upload-module-source) | none | untested | | [e](evidence/INV-HELM-019/) | | | -| INV-HELM-020 | Enable packet capture sidecar for GameServers | agent/ | charts/gameplane/values.yaml:527 | [p](procedures/helm.md#packet-capture-sidecar) | none | untested | blocked candidate: requires GameServer creation and sidecar injection verification | [e](evidence/INV-HELM-020/) | | | -| INV-HELM-021 | Enable/disable web dashboard UI | web/ | charts/gameplane/values.yaml:289 | [p](procedures/helm.md#web-dashboard-ui) | none | untested | | [e](evidence/INV-HELM-021/) | | | -| INV-HELM-022 | Configure dashboard ingress | charts/gameplane/ | charts/gameplane/values.yaml:296 | [p](procedures/helm.md#ingress-configuration) | none | untested | | [e](evidence/INV-HELM-022/) | | | -| INV-HELM-023 | Use existing storage claim for API database | api/ | charts/gameplane/values.yaml:142 | [p](procedures/helm.md#existing-storage-claim) | none | untested | | [e](evidence/INV-HELM-023/) | | | -| INV-HELM-024 | Configure default storage class for GameServer data | operator/ | charts/gameplane/values.yaml:109 | [p](procedures/helm.md#game-storage-class) | none | untested | blocked candidate: requires GameServer creation and PVC provisioning | [e](evidence/INV-HELM-024/) | | | -| INV-HELM-025 | Enable automatic CRD upgrade hook | charts/gameplane/ | charts/gameplane/values.yaml:34 | [p](procedures/helm.md#crd-auto-apply-hook) | none | untested | | [e](evidence/INV-HELM-025/) | | | -| INV-HELM-026 | Override container image registry | charts/gameplane/ | charts/gameplane/values.yaml:17 | [p](procedures/helm.md#image-registry-override) | none | untested | blocked candidate: needs alternative registry accessible from cluster | [e](evidence/INV-HELM-026/) | | | -| INV-HELM-027 | Override container image tag | charts/gameplane/ | charts/gameplane/values.yaml:20 | [p](procedures/helm.md#image-tag-override) | none | untested | | [e](evidence/INV-HELM-027/) | | | -| INV-HELM-028 | Enable operator leader election (HA) | operator/ | charts/gameplane/values.yaml:53 | [p](procedures/helm.md#operator-leader-election) | none | untested | | [e](evidence/INV-HELM-028/) | | | +| INV-HELM-001 | Enable OIDC authentication | api/ | charts/gameplane/values.yaml:240 | [p](procedures/helm.md#oidc-authentication) | none | pass | blocked candidate: needs external OIDC IdP; alternative: test with mock IdP stub | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-HELM-002 | Configure audit webhook sink | api/ | charts/gameplane/values.yaml:160 | [p](procedures/helm.md#audit-webhook-sink) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-HELM-003 | Enable syslog bridge for audit events | audit-syslog-bridge/ | charts/gameplane/values.yaml:183 | [p](procedures/helm.md#syslog-bridge-audit) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-HELM-004 | Configure S3 audit sink | api/ | charts/gameplane/values.yaml:202 | [p](procedures/helm.md#s3-audit-sink) | none | pass | blocked candidate: needs S3-compatible endpoint; alternative: mock MinIO if available on kubelab | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-HELM-005 | Enable audit event stdout logging | api/ | charts/gameplane/values.yaml:153 | [p](procedures/helm.md#audit-stdout-logging) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-HELM-006 | Configure telemetry collection endpoint | api/ | charts/gameplane/values.yaml:222 | [p](procedures/helm.md#telemetry-collection) | none | pass | blocked candidate: telemetry sent daily; requires deterministic triggers or extended wait | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-HELM-007 | Enable bundled telemetry receiver | telemetry-receiver/ | charts/gameplane/values.yaml:235 | [p](procedures/helm.md#telemetry-receiver-bundled) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-HELM-008 | Enable cluster operations feature | api/ | charts/gameplane/values.yaml:392 | [p](procedures/helm.md#cluster-operations-feature) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-HELM-009 | Enable MCP (Model Context Protocol) server | mcp-server/ | charts/gameplane/values.yaml:400 | [p](procedures/helm.md#mcp-server-deployment) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-HELM-010 | Enable default-deny network policies | operator/ | charts/gameplane/values.yaml:316 | [p](procedures/helm.md#network-policies-enforcement) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-HELM-011 | Enforce restricted pod security policy | operator/ | charts/gameplane/values.yaml:440 | [p](procedures/helm.md#pod-security-enforcement) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-HELM-012 | Enable game pod egress to public internet | operator/ | charts/gameplane/values.yaml:343 | [p](procedures/helm.md#game-egress-policies) | none | pass | blocked candidate: requires GameServer pod startup for network testing | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-HELM-013 | Enable per-GameServer ingress network policies | operator/ | charts/gameplane/values.yaml:371 | [p](procedures/helm.md#game-ingress-policies) | none | pass | blocked candidate: requires GameServer pod startup and external connectivity | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-HELM-014 | Create Prometheus ServiceMonitor objects | charts/gameplane/ | charts/gameplane/values.yaml:418 | [p](procedures/helm.md#service-monitors) | none | pass | blocked candidate: needs Prometheus Operator CRDs (ServiceMonitor); alternative: verify on cluster with CRDs | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-HELM-015 | Create Prometheus alert rules | charts/gameplane/ | charts/gameplane/values.yaml:428 | [p](procedures/helm.md#prometheus-rules) | none | pass | blocked candidate: needs Prometheus Operator CRDs (PrometheusRule); alternative: verify on cluster with CRDs | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-HELM-016 | Create Grafana dashboard ConfigMap | charts/gameplane/ | charts/gameplane/values.yaml:435 | [p](procedures/helm.md#grafana-dashboards) | none | pass | blocked candidate: needs Grafana with sidecar loader; alternative: verify on Grafana-equipped cluster | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-HELM-017 | Enable default module source | operator/ | charts/gameplane/values.yaml:446 | [p](procedures/helm.md#default-module-source) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-HELM-018 | Enable module bundle signature verification | operator/ | charts/gameplane/values.yaml:507 | [p](procedures/helm.md#module-signature-verification) | none | pass | blocked candidate: requires pulling and validating module bundles; alternative: verify ModuleSource spec includes verify settings | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-HELM-019 | Enable dashboard module upload source | operator/ | charts/gameplane/values.yaml:518 | [p](procedures/helm.md#upload-module-source) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-HELM-020 | Enable packet capture sidecar for GameServers | agent/ | charts/gameplane/values.yaml:527 | [p](procedures/helm.md#packet-capture-sidecar) | none | pass | blocked candidate: requires GameServer creation and sidecar injection verification | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-HELM-021 | Enable/disable web dashboard UI | web/ | charts/gameplane/values.yaml:289 | [p](procedures/helm.md#web-dashboard-ui) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-HELM-022 | Configure dashboard ingress | charts/gameplane/ | charts/gameplane/values.yaml:296 | [p](procedures/helm.md#ingress-configuration) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-HELM-023 | Use existing storage claim for API database | api/ | charts/gameplane/values.yaml:142 | [p](procedures/helm.md#existing-storage-claim) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-HELM-024 | Configure default storage class for GameServer data | operator/ | charts/gameplane/values.yaml:109 | [p](procedures/helm.md#game-storage-class) | none | pass | blocked candidate: requires GameServer creation and PVC provisioning | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-HELM-025 | Enable automatic CRD upgrade hook | charts/gameplane/ | charts/gameplane/values.yaml:34 | [p](procedures/helm.md#crd-auto-apply-hook) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-HELM-026 | Override container image registry | charts/gameplane/ | charts/gameplane/values.yaml:17 | [p](procedures/helm.md#image-registry-override) | none | pass | blocked candidate: needs alternative registry accessible from cluster | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-HELM-027 | Override container image tag | charts/gameplane/ | charts/gameplane/values.yaml:20 | [p](procedures/helm.md#image-tag-override) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-HELM-028 | Enable operator leader election (HA) | operator/ | charts/gameplane/values.yaml:53 | [p](procedures/helm.md#operator-leader-election) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | | ID | Capability | Component | Source | Procedure | CI test | Outcome | Reason | Evidence | Round | Findings | |----|------------|-----------|--------|-----------|---------|---------|--------|----------|-------|----------| ## MOD | ID | Capability | Component | Source | Procedure | CI test | Outcome | Reason | Evidence | Round | Findings | |----|------------|-----------|--------|-----------|---------|---------|--------|----------|-------|----------| -| INV-MOD-001 | Create and start Gmod server from template | modules/ | audit/evidence/rc.0/module-categories.md:48 | [p](procedures/modules.md#garrys-mod) | none | untested | | [e](evidence/INV-MOD-001/) | | | -| INV-MOD-002 | Join Gmod server via A2S query | modules/ | audit/evidence/rc.0/module-categories.md:48 | [p](procedures/modules.md#garrys-mod) | none | untested | | [e](evidence/INV-MOD-002/) | | | -| INV-MOD-003 | Gmod server console unavailable (none family) | modules/ | audit/evidence/rc.0/module-categories.md:48 | [p](procedures/modules.md#garrys-mod) | none | untested | | [e](evidence/INV-MOD-003/) | | | -| INV-MOD-004 | Backup and restore Gmod server | modules/ | audit/evidence/rc.0/module-categories.md:48 | [p](procedures/modules.md#garrys-mod) | none | untested | | [e](evidence/INV-MOD-004/) | | | -| INV-MOD-005 | Create and start Farming Simulator 25 server from template | modules/ | audit/evidence/rc.0/module-categories.md:49 | [p](procedures/modules.md#farming-simulator-25) | none | untested | | [e](evidence/INV-MOD-005/) | | | -| INV-MOD-006 | Join Farming Simulator 25 server via HTTP REST | modules/ | audit/evidence/rc.0/module-categories.md:49 | [p](procedures/modules.md#farming-simulator-25) | none | untested | | [e](evidence/INV-MOD-006/) | | | -| INV-MOD-007 | Farming Simulator 25 server REST console query | modules/ | audit/evidence/rc.0/module-categories.md:49 | [p](procedures/modules.md#farming-simulator-25) | none | untested | | [e](evidence/INV-MOD-007/) | | | -| INV-MOD-008 | Backup and restore Farming Simulator 25 server | modules/ | audit/evidence/rc.0/module-categories.md:49 | [p](procedures/modules.md#farming-simulator-25) | none | untested | | [e](evidence/INV-MOD-008/) | | | -| INV-MOD-009 | Create and start BeamMP server from template | modules/ | audit/evidence/rc.0/module-categories.md:50 | [p](procedures/modules.md#beammp) | none | untested | | [e](evidence/INV-MOD-009/) | | | -| INV-MOD-010 | Join BeamMP server via TCP | modules/ | audit/evidence/rc.0/module-categories.md:50 | [p](procedures/modules.md#beammp) | none | untested | | [e](evidence/INV-MOD-010/) | | | -| INV-MOD-011 | BeamMP server PTY console access | modules/ | audit/evidence/rc.0/module-categories.md:50 | [p](procedures/modules.md#beammp) | none | untested | | [e](evidence/INV-MOD-011/) | | | -| INV-MOD-012 | Backup and restore BeamMP server | modules/ | audit/evidence/rc.0/module-categories.md:50 | [p](procedures/modules.md#beammp) | none | untested | | [e](evidence/INV-MOD-012/) | | | -| INV-MOD-013 | Create and start Valheim server from template | modules/ | audit/evidence/rc.0/module-categories.md:51 | [p](procedures/modules.md#valheim) | none | untested | | [e](evidence/INV-MOD-013/) | | | -| INV-MOD-014 | Join Valheim server via HTTP REST | modules/ | audit/evidence/rc.0/module-categories.md:51 | [p](procedures/modules.md#valheim) | none | untested | | [e](evidence/INV-MOD-014/) | | | -| INV-MOD-015 | Valheim server PTY console access | modules/ | audit/evidence/rc.0/module-categories.md:51 | [p](procedures/modules.md#valheim) | none | untested | | [e](evidence/INV-MOD-015/) | | | -| INV-MOD-016 | Backup and restore Valheim server | modules/ | audit/evidence/rc.0/module-categories.md:51 | [p](procedures/modules.md#valheim) | none | untested | | [e](evidence/INV-MOD-016/) | | | -| INV-MOD-017 | Create and start Don't Starve Together server from template | modules/ | audit/evidence/rc.0/module-categories.md:52 | [p](procedures/modules.md#dont-starve-together) | none | untested | | [e](evidence/INV-MOD-017/) | | | -| INV-MOD-018 | Join Don't Starve Together server via A2S query | modules/ | audit/evidence/rc.0/module-categories.md:52 | [p](procedures/modules.md#dont-starve-together) | none | untested | | [e](evidence/INV-MOD-018/) | | | -| INV-MOD-019 | Don't Starve Together server PTY console access | modules/ | audit/evidence/rc.0/module-categories.md:52 | [p](procedures/modules.md#dont-starve-together) | none | untested | | [e](evidence/INV-MOD-019/) | | | -| INV-MOD-020 | Backup and restore Don't Starve Together server | modules/ | audit/evidence/rc.0/module-categories.md:52 | [p](procedures/modules.md#dont-starve-together) | none | untested | | [e](evidence/INV-MOD-020/) | | | -| INV-MOD-021 | Create and start tModLoader server from template | modules/ | audit/evidence/rc.0/module-categories.md:53 | [p](procedures/modules.md#tmodloader) | none | untested | | [e](evidence/INV-MOD-021/) | | | -| INV-MOD-022 | Join tModLoader server via Terraria TCP probe | modules/ | audit/evidence/rc.0/module-categories.md:53 | [p](procedures/modules.md#tmodloader) | none | untested | | [e](evidence/INV-MOD-022/) | | | -| INV-MOD-023 | tModLoader server PTY console access | modules/ | audit/evidence/rc.0/module-categories.md:53 | [p](procedures/modules.md#tmodloader) | none | untested | | [e](evidence/INV-MOD-023/) | | | -| INV-MOD-024 | Backup and restore tModLoader server | modules/ | audit/evidence/rc.0/module-categories.md:53 | [p](procedures/modules.md#tmodloader) | none | untested | | [e](evidence/INV-MOD-024/) | | | -| INV-MOD-025 | Create and start Terraria server from template | modules/ | audit/evidence/rc.0/module-categories.md:54 | [p](procedures/modules.md#terraria) | none | untested | | [e](evidence/INV-MOD-025/) | | | -| INV-MOD-026 | Join Terraria server via gameproto wire protocol | modules/ | audit/evidence/rc.0/module-categories.md:54 | [p](procedures/modules.md#terraria) | none | untested | | [e](evidence/INV-MOD-026/) | | | -| INV-MOD-027 | Terraria server PTY console access | modules/ | audit/evidence/rc.0/module-categories.md:54 | [p](procedures/modules.md#terraria) | none | untested | | [e](evidence/INV-MOD-027/) | | | -| INV-MOD-028 | Backup and restore Terraria server | modules/ | audit/evidence/rc.0/module-categories.md:54 | [p](procedures/modules.md#terraria) | none | untested | | [e](evidence/INV-MOD-028/) | | | -| INV-MOD-029 | Create and start Factorio server from template | modules/ | audit/evidence/rc.0/module-categories.md:55 | [p](procedures/modules.md#factorio) | none | untested | | [e](evidence/INV-MOD-029/) | | | -| INV-MOD-030 | Join Factorio server via TCP | modules/ | audit/evidence/rc.0/module-categories.md:55 | [p](procedures/modules.md#factorio) | none | untested | | [e](evidence/INV-MOD-030/) | | | -| INV-MOD-031 | Factorio server PTY + Source RCON console | modules/ | audit/evidence/rc.0/module-categories.md:55 | [p](procedures/modules.md#factorio) | none | untested | | [e](evidence/INV-MOD-031/) | | | -| INV-MOD-032 | Backup and restore Factorio server | modules/ | audit/evidence/rc.0/module-categories.md:55 | [p](procedures/modules.md#factorio) | none | untested | | [e](evidence/INV-MOD-032/) | | | +| INV-MOD-001 | Create and start Gmod server from template | modules/ | audit/evidence/rc.0/module-categories.md:48 | [p](procedures/modules.md#garrys-mod) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-002 | Join Gmod server via A2S query | modules/ | audit/evidence/rc.0/module-categories.md:48 | [p](procedures/modules.md#garrys-mod) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-003 | Gmod server console unavailable (none family) | modules/ | audit/evidence/rc.0/module-categories.md:48 | [p](procedures/modules.md#garrys-mod) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-004 | Backup and restore Gmod server | modules/ | audit/evidence/rc.0/module-categories.md:48 | [p](procedures/modules.md#garrys-mod) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-005 | Create and start Farming Simulator 25 server from template | modules/ | audit/evidence/rc.0/module-categories.md:49 | [p](procedures/modules.md#farming-simulator-25) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-006 | Join Farming Simulator 25 server via HTTP REST | modules/ | audit/evidence/rc.0/module-categories.md:49 | [p](procedures/modules.md#farming-simulator-25) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-007 | Farming Simulator 25 server REST console query | modules/ | audit/evidence/rc.0/module-categories.md:49 | [p](procedures/modules.md#farming-simulator-25) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-008 | Backup and restore Farming Simulator 25 server | modules/ | audit/evidence/rc.0/module-categories.md:49 | [p](procedures/modules.md#farming-simulator-25) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-009 | Create and start BeamMP server from template | modules/ | audit/evidence/rc.0/module-categories.md:50 | [p](procedures/modules.md#beammp) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-010 | Join BeamMP server via TCP | modules/ | audit/evidence/rc.0/module-categories.md:50 | [p](procedures/modules.md#beammp) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-011 | BeamMP server PTY console access | modules/ | audit/evidence/rc.0/module-categories.md:50 | [p](procedures/modules.md#beammp) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-012 | Backup and restore BeamMP server | modules/ | audit/evidence/rc.0/module-categories.md:50 | [p](procedures/modules.md#beammp) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-013 | Create and start Valheim server from template | modules/ | audit/evidence/rc.0/module-categories.md:51 | [p](procedures/modules.md#valheim) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-014 | Join Valheim server via HTTP REST | modules/ | audit/evidence/rc.0/module-categories.md:51 | [p](procedures/modules.md#valheim) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-015 | Valheim server PTY console access | modules/ | audit/evidence/rc.0/module-categories.md:51 | [p](procedures/modules.md#valheim) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-016 | Backup and restore Valheim server | modules/ | audit/evidence/rc.0/module-categories.md:51 | [p](procedures/modules.md#valheim) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-017 | Create and start Don't Starve Together server from template | modules/ | audit/evidence/rc.0/module-categories.md:52 | [p](procedures/modules.md#dont-starve-together) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-018 | Join Don't Starve Together server via A2S query | modules/ | audit/evidence/rc.0/module-categories.md:52 | [p](procedures/modules.md#dont-starve-together) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-019 | Don't Starve Together server PTY console access | modules/ | audit/evidence/rc.0/module-categories.md:52 | [p](procedures/modules.md#dont-starve-together) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-020 | Backup and restore Don't Starve Together server | modules/ | audit/evidence/rc.0/module-categories.md:52 | [p](procedures/modules.md#dont-starve-together) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-021 | Create and start tModLoader server from template | modules/ | audit/evidence/rc.0/module-categories.md:53 | [p](procedures/modules.md#tmodloader) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-022 | Join tModLoader server via Terraria TCP probe | modules/ | audit/evidence/rc.0/module-categories.md:53 | [p](procedures/modules.md#tmodloader) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-023 | tModLoader server PTY console access | modules/ | audit/evidence/rc.0/module-categories.md:53 | [p](procedures/modules.md#tmodloader) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-024 | Backup and restore tModLoader server | modules/ | audit/evidence/rc.0/module-categories.md:53 | [p](procedures/modules.md#tmodloader) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-025 | Create and start Terraria server from template | modules/ | audit/evidence/rc.0/module-categories.md:54 | [p](procedures/modules.md#terraria) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-026 | Join Terraria server via gameproto wire protocol | modules/ | audit/evidence/rc.0/module-categories.md:54 | [p](procedures/modules.md#terraria) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-027 | Terraria server PTY console access | modules/ | audit/evidence/rc.0/module-categories.md:54 | [p](procedures/modules.md#terraria) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-028 | Backup and restore Terraria server | modules/ | audit/evidence/rc.0/module-categories.md:54 | [p](procedures/modules.md#terraria) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-029 | Create and start Factorio server from template | modules/ | audit/evidence/rc.0/module-categories.md:55 | [p](procedures/modules.md#factorio) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-030 | Join Factorio server via TCP | modules/ | audit/evidence/rc.0/module-categories.md:55 | [p](procedures/modules.md#factorio) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-031 | Factorio server PTY + Source RCON console | modules/ | audit/evidence/rc.0/module-categories.md:55 | [p](procedures/modules.md#factorio) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-032 | Backup and restore Factorio server | modules/ | audit/evidence/rc.0/module-categories.md:55 | [p](procedures/modules.md#factorio) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | | INV-MOD-033 | Create and start DayZ server from template | modules/ | audit/evidence/rc.0/module-categories.md:56 | [p](procedures/modules.md#dayz) | none | blocked | blocked candidate: needs node memory ≥6Gi per pod; no lighter alternative available in rcon/battleye category (DayZ is the only module) | [e](evidence/INV-MOD-033/) | | | | INV-MOD-034 | Join DayZ server via A2S query | modules/ | audit/evidence/rc.0/module-categories.md:56 | [p](procedures/modules.md#dayz) | none | blocked | blocked candidate: needs node memory ≥6Gi per pod; no lighter alternative available in rcon/battleye category (DayZ is the only module) | [e](evidence/INV-MOD-034/) | | | | INV-MOD-035 | DayZ server BattlEye RCON console | modules/ | audit/evidence/rc.0/module-categories.md:56 | [p](procedures/modules.md#dayz) | none | blocked | blocked candidate: needs node memory ≥6Gi per pod; no lighter alternative available in rcon/battleye category (DayZ is the only module) | [e](evidence/INV-MOD-035/) | | | | INV-MOD-036 | Backup and restore DayZ server | modules/ | audit/evidence/rc.0/module-categories.md:56 | [p](procedures/modules.md#dayz) | none | blocked | blocked candidate: needs node memory ≥6Gi per pod; no lighter alternative available in rcon/battleye category (DayZ is the only module) | [e](evidence/INV-MOD-036/) | | | -| INV-MOD-037 | Create and start Nuclear Option server from template | modules/ | audit/evidence/rc.0/module-categories.md:57 | [p](procedures/modules.md#nuclear-option) | none | untested | | [e](evidence/INV-MOD-037/) | | | -| INV-MOD-038 | Join Nuclear Option server via UDP (manual verification) | modules/ | audit/evidence/rc.0/module-categories.md:57 | [p](procedures/modules.md#nuclear-option) | none | untested | join probe not automated; manual verification required | [e](evidence/INV-MOD-038/) | | | -| INV-MOD-039 | Nuclear Option server nuclearoption RCON console | modules/ | audit/evidence/rc.0/module-categories.md:57 | [p](procedures/modules.md#nuclear-option) | none | untested | | [e](evidence/INV-MOD-039/) | | | -| INV-MOD-040 | Backup and restore Nuclear Option server | modules/ | audit/evidence/rc.0/module-categories.md:57 | [p](procedures/modules.md#nuclear-option) | none | untested | | [e](evidence/INV-MOD-040/) | | | -| INV-MOD-041 | Create and start Palworld server from template | modules/ | audit/evidence/rc.0/module-categories.md:58 | [p](procedures/modules.md#palworld) | none | untested | | [e](evidence/INV-MOD-041/) | | | -| INV-MOD-042 | Join Palworld server via A2S query | modules/ | audit/evidence/rc.0/module-categories.md:58 | [p](procedures/modules.md#palworld) | none | untested | | [e](evidence/INV-MOD-042/) | | | -| INV-MOD-043 | Palworld server palworld RCON REST API console | modules/ | audit/evidence/rc.0/module-categories.md:58 | [p](procedures/modules.md#palworld) | none | untested | | [e](evidence/INV-MOD-043/) | | | -| INV-MOD-044 | Backup and restore Palworld server | modules/ | audit/evidence/rc.0/module-categories.md:58 | [p](procedures/modules.md#palworld) | none | untested | | [e](evidence/INV-MOD-044/) | | | -| INV-MOD-045 | Create and start FiveM server from template | modules/ | audit/evidence/rc.0/module-categories.md:59 | [p](procedures/modules.md#fivem) | none | untested | | [e](evidence/INV-MOD-045/) | | | -| INV-MOD-046 | Join FiveM server via HTTP REST | modules/ | audit/evidence/rc.0/module-categories.md:59 | [p](procedures/modules.md#fivem) | none | untested | | [e](evidence/INV-MOD-046/) | | | -| INV-MOD-047 | FiveM server REST RCON console | modules/ | audit/evidence/rc.0/module-categories.md:59 | [p](procedures/modules.md#fivem) | none | untested | | [e](evidence/INV-MOD-047/) | | | -| INV-MOD-048 | Backup and restore FiveM server | modules/ | audit/evidence/rc.0/module-categories.md:59 | [p](procedures/modules.md#fivem) | none | untested | | [e](evidence/INV-MOD-048/) | | | +| INV-MOD-037 | Create and start Nuclear Option server from template | modules/ | audit/evidence/rc.0/module-categories.md:57 | [p](procedures/modules.md#nuclear-option) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-038 | Join Nuclear Option server via UDP (manual verification) | modules/ | audit/evidence/rc.0/module-categories.md:57 | [p](procedures/modules.md#nuclear-option) | none | pass | join probe not automated; manual verification required | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-039 | Nuclear Option server nuclearoption RCON console | modules/ | audit/evidence/rc.0/module-categories.md:57 | [p](procedures/modules.md#nuclear-option) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-040 | Backup and restore Nuclear Option server | modules/ | audit/evidence/rc.0/module-categories.md:57 | [p](procedures/modules.md#nuclear-option) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-041 | Create and start Palworld server from template | modules/ | audit/evidence/rc.0/module-categories.md:58 | [p](procedures/modules.md#palworld) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-042 | Join Palworld server via A2S query | modules/ | audit/evidence/rc.0/module-categories.md:58 | [p](procedures/modules.md#palworld) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-043 | Palworld server palworld RCON REST API console | modules/ | audit/evidence/rc.0/module-categories.md:58 | [p](procedures/modules.md#palworld) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-044 | Backup and restore Palworld server | modules/ | audit/evidence/rc.0/module-categories.md:58 | [p](procedures/modules.md#palworld) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-045 | Create and start FiveM server from template | modules/ | audit/evidence/rc.0/module-categories.md:59 | [p](procedures/modules.md#fivem) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-046 | Join FiveM server via HTTP REST | modules/ | audit/evidence/rc.0/module-categories.md:59 | [p](procedures/modules.md#fivem) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-047 | FiveM server REST RCON console | modules/ | audit/evidence/rc.0/module-categories.md:59 | [p](procedures/modules.md#fivem) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-048 | Backup and restore FiveM server | modules/ | audit/evidence/rc.0/module-categories.md:59 | [p](procedures/modules.md#fivem) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | | INV-MOD-049 | Create and start Satisfactory server from template | modules/ | audit/evidence/rc.0/module-categories.md:60 | [p](procedures/modules.md#satisfactory) | none | blocked | blocked candidate: needs node memory ≥6Gi per pod; alternative: FiveM (rcon/rest + HTTP REST probe, 4Gi) | [e](evidence/INV-MOD-049/) | | | | INV-MOD-050 | Join Satisfactory server via HTTP REST | modules/ | audit/evidence/rc.0/module-categories.md:60 | [p](procedures/modules.md#satisfactory) | none | blocked | blocked candidate: needs node memory ≥6Gi per pod; alternative: FiveM (rcon/rest + HTTP REST probe, 4Gi) | [e](evidence/INV-MOD-050/) | | | | INV-MOD-051 | Satisfactory server satisfactory RCON console | modules/ | audit/evidence/rc.0/module-categories.md:60 | [p](procedures/modules.md#satisfactory) | none | blocked | blocked candidate: needs node memory ≥6Gi per pod; alternative: FiveM (rcon/rest + HTTP REST probe, 4Gi) | [e](evidence/INV-MOD-051/) | | | @@ -507,18 +507,18 @@ Enumerated from code (research R2). Columns and allowed values are fixed by [con | INV-MOD-054 | Join Ark Survival Ascended server via TCP RCON probe | modules/ | audit/evidence/rc.0/module-categories.md:61 | [p](procedures/modules.md#ark-survival-ascended) | none | blocked | blocked candidate: needs node memory ≥10Gi per pod; alternative: CS2 (rcon/source + Steam A2S probe, 2Gi) | [e](evidence/INV-MOD-054/) | | | | INV-MOD-055 | Ark Survival Ascended server Source RCON console | modules/ | audit/evidence/rc.0/module-categories.md:61 | [p](procedures/modules.md#ark-survival-ascended) | none | blocked | blocked candidate: needs node memory ≥10Gi per pod; alternative: CS2 (rcon/source + Steam A2S probe, 2Gi) | [e](evidence/INV-MOD-055/) | | | | INV-MOD-056 | Backup and restore Ark Survival Ascended server | modules/ | audit/evidence/rc.0/module-categories.md:61 | [p](procedures/modules.md#ark-survival-ascended) | none | blocked | blocked candidate: needs node memory ≥10Gi per pod; alternative: CS2 (rcon/source + Steam A2S probe, 2Gi) | [e](evidence/INV-MOD-056/) | | | -| INV-MOD-057 | Create and start CS2 server from template | modules/ | audit/evidence/rc.0/module-categories.md:62 | [p](procedures/modules.md#cs2) | none | untested | | [e](evidence/INV-MOD-057/) | | | -| INV-MOD-058 | Join CS2 server via A2S query | modules/ | audit/evidence/rc.0/module-categories.md:62 | [p](procedures/modules.md#cs2) | none | untested | | [e](evidence/INV-MOD-058/) | | | -| INV-MOD-059 | CS2 server Source RCON console | modules/ | audit/evidence/rc.0/module-categories.md:62 | [p](procedures/modules.md#cs2) | none | untested | | [e](evidence/INV-MOD-059/) | | | -| INV-MOD-060 | Backup and restore CS2 server | modules/ | audit/evidence/rc.0/module-categories.md:62 | [p](procedures/modules.md#cs2) | none | untested | | [e](evidence/INV-MOD-060/) | | | -| INV-MOD-061 | Create and start Minecraft Java server from template | modules/ | audit/evidence/rc.0/module-categories.md:63 | [p](procedures/modules.md#minecraft-java) | none | untested | | [e](evidence/INV-MOD-061/) | | | -| INV-MOD-062 | Join Minecraft Java server via gameproto wire protocol | modules/ | audit/evidence/rc.0/module-categories.md:63 | [p](procedures/modules.md#minecraft-java) | none | untested | | [e](evidence/INV-MOD-062/) | | | -| INV-MOD-063 | Minecraft Java server Source RCON console | modules/ | audit/evidence/rc.0/module-categories.md:63 | [p](procedures/modules.md#minecraft-java) | none | untested | | [e](evidence/INV-MOD-063/) | | | -| INV-MOD-064 | Backup and restore Minecraft Java server | modules/ | audit/evidence/rc.0/module-categories.md:63 | [p](procedures/modules.md#minecraft-java) | none | untested | | [e](evidence/INV-MOD-064/) | | | -| INV-MOD-065 | Create and start Rust server from template | modules/ | audit/evidence/rc.0/module-categories.md:64 | [p](procedures/modules.md#rust) | none | untested | | [e](evidence/INV-MOD-065/) | | | -| INV-MOD-066 | Join Rust server via A2S query | modules/ | audit/evidence/rc.0/module-categories.md:64 | [p](procedures/modules.md#rust) | none | untested | | [e](evidence/INV-MOD-066/) | | | -| INV-MOD-067 | Rust server WebSocket RCON console | modules/ | audit/evidence/rc.0/module-categories.md:64 | [p](procedures/modules.md#rust) | none | untested | | [e](evidence/INV-MOD-067/) | | | -| INV-MOD-068 | Backup and restore Rust server | modules/ | audit/evidence/rc.0/module-categories.md:64 | [p](procedures/modules.md#rust) | none | untested | | [e](evidence/INV-MOD-068/) | | | +| INV-MOD-057 | Create and start CS2 server from template | modules/ | audit/evidence/rc.0/module-categories.md:62 | [p](procedures/modules.md#cs2) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-058 | Join CS2 server via A2S query | modules/ | audit/evidence/rc.0/module-categories.md:62 | [p](procedures/modules.md#cs2) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-059 | CS2 server Source RCON console | modules/ | audit/evidence/rc.0/module-categories.md:62 | [p](procedures/modules.md#cs2) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-060 | Backup and restore CS2 server | modules/ | audit/evidence/rc.0/module-categories.md:62 | [p](procedures/modules.md#cs2) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-061 | Create and start Minecraft Java server from template | modules/ | audit/evidence/rc.0/module-categories.md:63 | [p](procedures/modules.md#minecraft-java) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-062 | Join Minecraft Java server via gameproto wire protocol | modules/ | audit/evidence/rc.0/module-categories.md:63 | [p](procedures/modules.md#minecraft-java) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-063 | Minecraft Java server Source RCON console | modules/ | audit/evidence/rc.0/module-categories.md:63 | [p](procedures/modules.md#minecraft-java) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-064 | Backup and restore Minecraft Java server | modules/ | audit/evidence/rc.0/module-categories.md:63 | [p](procedures/modules.md#minecraft-java) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-065 | Create and start Rust server from template | modules/ | audit/evidence/rc.0/module-categories.md:64 | [p](procedures/modules.md#rust) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-066 | Join Rust server via A2S query | modules/ | audit/evidence/rc.0/module-categories.md:64 | [p](procedures/modules.md#rust) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-067 | Rust server WebSocket RCON console | modules/ | audit/evidence/rc.0/module-categories.md:64 | [p](procedures/modules.md#rust) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | +| INV-MOD-068 | Backup and restore Rust server | modules/ | audit/evidence/rc.0/module-categories.md:64 | [p](procedures/modules.md#rust) | none | pass | | [maintainer attestation](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05) | live-sweep 2026-10-04 | | ## UPG | ID | Capability | Component | Source | Procedure | CI test | Outcome | Reason | Evidence | Round | Findings | diff --git a/specs/018-v0-3-release-readiness/audit/release-criteria.md b/specs/018-v0-3-release-readiness/audit/release-criteria.md index 3f20a154a..d39dc964a 100644 --- a/specs/018-v0-3-release-readiness/audit/release-criteria.md +++ b/specs/018-v0-3-release-readiness/audit/release-criteria.md @@ -17,3 +17,4 @@ Written before round 0 (FR-015). Columns are fixed by [contracts/audit-records.m - 2026-09-24: RC-03 now also counts `imported` findings as blocking, matching data-model.md's blocking statuses. Maintainer decision, OD-010 in [../OPEN-DECISIONS.md](../OPEN-DECISIONS.md#od-010-rc-03-leaves-out-the-imported-status--resolved-2026-09-24). - 2026-10-05: `Met` filled at the go/no-go decision (T070, maintainer valgulnecron: go, with Not met criteria accepted as known risk; see [report.md#decision](report.md#decision)). Criteria themselves unchanged. +- 2026-10-05: RC-01 `Met` unchanged (`not met (accepted risk, T070)`) after OD-030: the maintainer attested that all screens and features were tested live on kubelab on 2026-10-04, and the 459 `untested` WEB/API/CRD/AGT/AUX/HELM/MOD rows are recorded as `pass`, but 8 `UPG`/`NODE` rows and the 16 `INV-SEC-*` rows are still `untested`, so not every row has an outcome. The criterion text is unchanged. Maintainer decision, OD-030 in [../OPEN-DECISIONS.md](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05). diff --git a/specs/018-v0-3-release-readiness/audit/report.md b/specs/018-v0-3-release-readiness/audit/report.md index 2c368ab9d..f00640e86 100644 --- a/specs/018-v0-3-release-readiness/audit/report.md +++ b/specs/018-v0-3-release-readiness/audit/report.md @@ -2,7 +2,7 @@ Built from the audit records at the end of the audit (T066). Readable cold in under 15 minutes (SC-008). -**State of this report (2026-10-05, master `c79715a6`): the audit is not finished.** It is a snapshot of what the records say, not a go case. 1 of 8 release criteria is Met. The formal live round did not run (OD-029), the upgrade and node rounds have not run, and no finding is `verified` (T058 has not run). `v0.3.0-rc.2` **has not been tagged or pushed**: RC-TAG-2 in [OPEN-DECISIONS.md](../OPEN-DECISIONS.md#rc-tag-2-publish-v030-rc2--pending) still reads PENDING, and its tag target is the #496 merge commit `6750ba87`: `gh api repos/ValgulNecron/Gameplane/git/refs/tags/v0.3.0-rc.2` returns 404 on 2026-10-05, and only `v0.3.0-rc.1` exists (never installable, see [rounds.md](rounds.md#rc1)). +**State of this report (2026-10-05, master `c79715a6`): the audit is not finished.** It is a snapshot of what the records say, not a go case. 1 of 8 release criteria is Met (RC-01 stays Not met: 8 `UPG`/`NODE` rows and the 16 `INV-SEC-*` rows are still `untested`; the other 459 rows are `pass` on a maintainer attestation, OD-030). The formal live round did not run (OD-029), the upgrade and node rounds have not run, and no finding is `verified` (T058 has not run). `v0.3.0-rc.2` **has not been tagged or pushed**: RC-TAG-2 in [OPEN-DECISIONS.md](../OPEN-DECISIONS.md#rc-tag-2-publish-v030-rc2--pending) still reads PENDING, and its tag target is the #496 merge commit `6750ba87`: `gh api repos/ValgulNecron/Gameplane/git/refs/tags/v0.3.0-rc.2` returns 404 on 2026-10-05, and only `v0.3.0-rc.1` exists (never installable, see [rounds.md](rounds.md#rc1)). ## Decision @@ -19,7 +19,7 @@ Evidence as of 2026-10-05. `Met` here is filled only from the records; the maint | ID | Criterion | Source | Met | Reason | |---|---|---|---|---| -| RC-01 | Every inventory row has an outcome, zero rows `fail`, and every `blocked` row names its prerequisite and is listed as not live-verified | SC-001 | **Not met** | 467 of 486 rows are `untested` and no row is `pass`; no row is `fail`. 19 rows are `blocked`, each names its prerequisite, and they are listed under Not live-verified. The criterion needs an outcome on every row. | +| RC-01 | Every inventory row has an outcome, zero rows `fail`, and every `blocked` row names its prerequisite and is listed as not live-verified | SC-001 | **Not met** | 8 of 486 rows are still `untested` (5 `UPG`, 3 `NODE`; 24 of 502 with the 16 `INV-SEC-*` rows), and `untested` is not an outcome (data-model.md), so the criterion is not met; no row is `fail`. 459 rows are `pass` on the maintainer's attestation that all screens and features were tested live on kubelab on 2026-10-04 ([OD-030](../OPEN-DECISIONS.md#od-030-screen-and-feature-rows-recorded-as-pass-from-the-live-sweep--resolved-2026-10-05)); this is an attestation, not per-row evidence. 19 rows are `blocked`, each names its prerequisite, and they are listed under Not live-verified. The attestation does not cover the `UPG`, `NODE` or `SEC` rows. | | RC-02 | Every component has a `complete` review record | SC-002 | **Met** | `audit/coverage.md` has 27 component rows, all `complete`. The 15 `go.work` entries, `web/`, `charts/gameplane/`, `deploy/`, `hack/`, `.github/workflows/`, `.github/actions/`, `images/`, `docs/`, root docs, `design-export/`, `modules/` and `website/` are all there. The records say a review happened; findings from them are counted under RC-03. | | RC-03 | Zero findings in `imported`, `open`, `fixing` or `fixed-unverified` | SC-003, SC-004 | **Not met** | 291 findings are in a blocking status: 25 `imported`, 37 `open`, 0 `fixing`, 229 `fixed-unverified`. None is `verified`. | | RC-04 | Each FR-008 boundary has at least one active violation attempt recorded | SC-007 | **Not met** | The 16 `INV-SEC-*` rows (in `audit/held/inventory-SEC.md`, OD-019) are all `untested`, so no violation attempt is recorded for any FR-008 boundary. | @@ -46,13 +46,13 @@ How each number was produced: findings from the `| F-NNN |` rows of `audit/findi | Outcome | `inventory.md` (486) | With `INV-SEC-*` (502) | |---|---|---| -| pass | 0 | 0 | +| pass | 459 | 459 | | fail | 0 | 0 | | blocked | 19 | 19 | | n/a | 0 | 0 | -| untested | 467 | 483 | +| untested | 8 | 24 | -No row is `pass`. The formal per-row round did not run (OD-029), so most rows stay `untested`; they are reported as such. +The 459 `pass` rows (WEB, API, CRD, AGT, AUX, HELM, MOD) are recorded from a maintainer attestation (OD-030), not per-row evidence: the formal per-row round did not run (OD-029). The `UPG`, `NODE` and `SEC` rows stay `untested`; the 19 `blocked` rows stay `blocked`. ### Coverage @@ -64,7 +64,7 @@ No row is `pass`. The formal per-row round did not run (OD-029), so most rows st |---|---| | rc.0 | pre-RC review and inventory enumeration; 0 rows run | | rc.1 | `v0.3.0-rc.1` tagged 2026-09-24, release run cancelled (F-257), never installable; 0 rows run | -| live-sweep 2026-10-04 | informal sweep of `master` on kubelab; F-273 to F-293; per-row outcomes not recorded (OD-029) | +| live-sweep 2026-10-04 | informal sweep of `master` on kubelab; F-273 to F-293; per-row outcomes not recorded (OD-029); 459 rows recorded as `pass` from the maintainer attestation (OD-030) | | rc.2 | RC-TAG-2 PENDING; tag target `6750ba87` (#496 merge commit), **not tagged or pushed** | | upgrade, node (T061, T062, T065) | not run | | re-verification of fixed-unverified findings (T058) | not run | @@ -171,7 +171,7 @@ Rows are not live-verified if they are `blocked` (listed below, with the prerequ ### Untested rows -- **467 of 486 inventory rows in `audit/inventory.md` are still `untested`** (WEB 145, API 146, CRD 35, AGT 36, AUX 13, HELM 28, MOD 56, UPG 5, NODE 3). The formal per-row live round did not run (OD-029): the 2026-10-04 informal live sweep on `master` stands in for it, and it did not record per-row outcomes, so no row is marked `pass`. +- **8 of 486 inventory rows in `audit/inventory.md` are still `untested`** (UPG 5, NODE 3); 24 of 502 with the `INV-SEC-*` rows. 459 rows (WEB 145, API 146, CRD 35, AGT 36, AUX 13, HELM 28, MOD 56) are `pass` on the strength of a maintainer attestation, not per-row evidence: the formal per-row live round did not run (OD-029) and the 2026-10-04 informal live sweep on `master` did not record per-row outcomes, so on 2026-10-05 the maintainer attested that "all screen and feature where tested live in a cluster" (OD-030). The attestation does not cover `UPG`, `NODE`, `SEC` or the 19 `blocked` rows. - The 16 security-control rows (`INV-SEC-001` to `INV-SEC-016`) are kept in `audit/held/inventory-SEC.md`, not in `audit/inventory.md` (OD-019; that file has been in git since 8249db80) and are all `untested` there, so no active violation attempt is recorded for them. - No upgrade or node round has run (T061, T062, T065): the beta.8 to RC upgrade (`UPG`, 5 rows) and the node behaviour rows (`NODE`, 3 rows) are `untested`. - 229 findings are `fixed-unverified`: their fixes merged but have not been re-verified on a release candidate (T058 has not run). @@ -218,17 +218,17 @@ Inventory outcomes by area code, from `audit/inventory.md` (awk on the ID prefix | Area | Rows | untested | blocked | pass | fail | n/a | |---|---|---|---|---|---|---| -| WEB | 145 | 145 | 0 | 0 | 0 | 0 | -| API | 146 | 146 | 0 | 0 | 0 | 0 | -| CRD | 37 | 35 | 2 | 0 | 0 | 0 | -| AGT | 36 | 36 | 0 | 0 | 0 | 0 | -| AUX | 18 | 13 | 5 | 0 | 0 | 0 | -| HELM | 28 | 28 | 0 | 0 | 0 | 0 | -| MOD | 68 | 56 | 12 | 0 | 0 | 0 | +| WEB | 145 | 0 | 0 | 145 | 0 | 0 | +| API | 146 | 0 | 0 | 146 | 0 | 0 | +| CRD | 37 | 0 | 2 | 35 | 0 | 0 | +| AGT | 36 | 0 | 0 | 36 | 0 | 0 | +| AUX | 18 | 0 | 5 | 13 | 0 | 0 | +| HELM | 28 | 0 | 0 | 28 | 0 | 0 | +| MOD | 68 | 0 | 12 | 56 | 0 | 0 | | UPG | 5 | 5 | 0 | 0 | 0 | 0 | | NODE | 3 | 3 | 0 | 0 | 0 | 0 | | SEC (`held/inventory-SEC.md`) | 16 | 16 | 0 | 0 | 0 | 0 | -| **Total** | 502 | 483 | 19 | 0 | 0 | 0 | +| **Total** | 502 | 24 | 19 | 459 | 0 | 0 | ## Proposed E2E additions From 7ce875053f0b24dc2ae11e2755f761e1479102ea Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 23:20:49 +0000 Subject: [PATCH 4/4] docs(specs): 018 report and release-notes review fixes - release notes: say the one-time pod restart interrupts active player sessions - release notes: pre-v1 caveat subsections are h3 under their h2 - report RC-07: base Partially on the F-289..F-293 deferrals (SC-009) Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01UshpSigdLccuYZi7oFJX9y Signed-off-by: Claude --- .../audit/evidence/release-notes-v0.3.0.md | 5 +++-- specs/018-v0-3-release-readiness/audit/report.md | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/specs/018-v0-3-release-readiness/audit/evidence/release-notes-v0.3.0.md b/specs/018-v0-3-release-readiness/audit/evidence/release-notes-v0.3.0.md index acd49fde3..0e10bf3cd 100644 --- a/specs/018-v0-3-release-readiness/audit/evidence/release-notes-v0.3.0.md +++ b/specs/018-v0-3-release-readiness/audit/evidence/release-notes-v0.3.0.md @@ -37,6 +37,7 @@ Draft for the maintainer (T068). Not published and not final: v0.3.0 has no go d - **Every existing GameServer pod restarts once on upgrade** due to the network capture feature adding an emptyDir volume; plan your upgrade window accordingly. + This interrupts active player sessions. - **User theme customization:** presets (Modern Pink, Legacy Orange) + custom accent/surface colors with WCAG AA contrast guarantee, custom CSS overlay, and safe-mode suspension on demand. Accessed via Settings → Theme & Appearance. @@ -100,7 +101,7 @@ Rows are not live-verified if they are `blocked` (listed below, with the prerequ This is a pre-v1 release. These items are wanted for v1 and are not blocking v0.3.0: -#### Production-readiness hardening (planned) +### Production-readiness hardening (planned) - A documented backup/restore **drill** — a runbook an operator can follow. The *coverage* half of this item is already done and was stale here: @@ -110,7 +111,7 @@ This is a pre-v1 release. These items are wanted for v1 and are not blocking v0. provisions. What is missing is the human-facing runbook, not the test. - Resource-limit guidance sized from real workloads rather than defaults. -#### Postgres driver: production readiness (experimental) +### Postgres driver: production readiness (experimental) SQLite is the only production-tested driver. The Postgres driver (build tag `-tags postgres`) now works end to end (#518): migrations 001–012 have diff --git a/specs/018-v0-3-release-readiness/audit/report.md b/specs/018-v0-3-release-readiness/audit/report.md index f00640e86..2526cc8e2 100644 --- a/specs/018-v0-3-release-readiness/audit/report.md +++ b/specs/018-v0-3-release-readiness/audit/report.md @@ -25,7 +25,7 @@ Evidence as of 2026-10-05. `Met` here is filled only from the records; the maint | RC-04 | Each FR-008 boundary has at least one active violation attempt recorded | SC-007 | **Not met** | The 16 `INV-SEC-*` rows (in `audit/held/inventory-SEC.md`, OD-019) are all `untested`, so no violation attempt is recorded for any FR-008 boundary. | | RC-05 | Live beta.8 → RC upgrade with zero data loss and zero lost accounts | SC-005, OD-005 | **Not met** | The upgrade round has not run (T061, T065). The 5 `UPG` rows are `untested`. CI `e2e-upgrade` from beta.8 exists but is not the live upgrade this criterion asks for. | | RC-06 | The baseline snapshot matches the post-cleanup snapshot, with zero `audit018-` resources remaining | SC-006 | **Not met** | No post-cleanup snapshot comparison is recorded. The `audit018-admin` test account is still `pending` removal in [rounds.md](rounds.md), the live sweep's test resources are `not recorded`, and T034 (cleanup) is open. | -| RC-07 | Every `not-a-defect` and `out-of-scope` closure is justified, and each out-of-scope one cites a roadmap line | SC-009 | **Partially** | Both closures that exist are accounted for: F-276 (`not-a-defect`) carries a Justification citing `web/src/lib/servers.ts:15-16`, and F-181 (`closed-already-fixed`) cites #467. No finding is `out-of-scope`, so no roadmap line is needed yet. Not complete: the open findings have not been triaged, so more closures are expected. | +| RC-07 | Every `not-a-defect` and `out-of-scope` closure is justified, and each out-of-scope one cites a roadmap line | SC-009 | **Partially** | Both closures that exist are accounted for: F-276 (`not-a-defect`) carries a Justification citing `web/src/lib/servers.ts:15-16`, and F-181 (`closed-already-fixed`) cites #467. No finding is `out-of-scope`, so no roadmap line is needed yet. Not complete: F-289..F-293 are deferred by #549 (F-289 needs a separate `gameplane-module` PR; F-290..F-293 are design-first items awaiting a Pencil design PR) without an `out-of-scope` closure citing a roadmap line, which SC-009 requires for any deferral. | | RC-08 | CI is green on the tagged commit | FR-017 | **Not met** | No `v0.3.0` tag exists. `v0.3.0-rc.2` is not tagged (RC-TAG-2 is PENDING), so there is no tagged commit with a green CI run. `v0.3.0-rc.1` was tagged but its release run was cancelled. | ## Totals