diff --git a/modules/rust/PLAN.md b/modules/rust/PLAN.md index 7228836..88878eb 100644 --- a/modules/rust/PLAN.md +++ b/modules/rust/PLAN.md @@ -797,11 +797,12 @@ first boot — it copies config, data, lang and permission files across. A Carbo converting the Oxide rig would start out holding the Oxide rig's state, and would prove less than a fresh one. -**The access, and the one thing it cannot do.** The panel's application API token is at -`RunicGateway/pterodactyl_claude_api_token` (`ptla_…`). It creates and configures servers, -allocations and users, and reads eggs. **It cannot touch files, power or console** — Pterodactyl puts -those on the *client* API, which rejects an application key outright. So the deployment loop is three -tiers, matched to what each is for: +**The access, and the two kinds of key it takes.** `RunicGateway/pterodactyl_claude_api_token` holds +both, one per line: an **application** key (`ptla_…`), which creates and configures servers, +allocations and users and reads eggs but **cannot touch files, power or console**; and a **client** +key (`ptlc_…`), which is where Pterodactyl puts exactly those. An application key is rejected +outright by `/api/client/**` and cannot be widened — they are two credentials, not two scopes of +one. So the deployment loop is three tiers, matched to what each is for: | What | How | Why that one | |---|---|---| @@ -809,17 +810,39 @@ tiers, matched to what each is for: | **Working-tree iteration** — an uncommitted `.cs` under test | A **client** API key (`ptlc_…`): `files/write`, then `command` to reload | The Pterodactyl analogue of `servuo-plugins/deploy.ps1`, and it carries the same caveat: **if something only works when the push script copies it, it does not ship** | | **Bulk or binary** — sidecar builds, world files | SFTP on the node, port 2022 | Where the client API's per-file write is the wrong shape | -**The client key is the one thing outstanding**, and it is a request rather than a decision: an -application key cannot be widened into one, so the org lead generates it from the account page. Until -it exists, iteration is reinstall-only — correct, and slow enough that nobody would choose it twice. -The push script itself lives in **`Rust-Plugins`**, mirroring where `deploy.ps1` lives for ServUO. +**The client key now exists beside the application one** — the token file holds both, as +`application:` and `user:` lines — but at the time of writing it authenticates and then sees **no +servers**, so tier 2 is not yet usable. §3 has the diagnosis. Until it is, iteration is +reinstall-only: correct, and slow enough that nobody would choose it twice. The push script itself +lives in **`Rust-Plugins`**, mirroring where `deploy.ps1` lives for ServUO. ## 3. Open questions -**None — but one outstanding request.** R21's iteration loop needs a Pterodactyl **client** API key -(`ptlc_…`); the application key already on disk cannot be widened into one, and only the account -holder can mint it. Not a question and not a decision: until it exists, pushing a file to a rig means -a panel reinstall. Everything else in this section was closed on 2026-09-15. +**None — but one thing is unresolved on the panel.** R21's iteration loop needs a Pterodactyl +**client** API key, and one now exists (`ptlc_…`, alongside the application key, both in +`RunicGateway/pterodactyl_claude_api_token`). It authenticates correctly — +`/api/client/account` returns user 1 `whitlocktech`, `root_admin: true`, the owner of every server on +the node — **and then lists zero servers.** `/api/client` is `total: 0` for the default listing and +for `type=admin` and `type=admin-all` alike, and every `/api/client/servers/{id}/…` route 404s for +both the short identifier and the full UUID. + +That is a panel-side condition, not a token-shape problem, and it is **not blocking the plan** — it +blocks tier 2 of R21's deployment loop, leaving reinstall and SFTP working. Diagnosis so far, so that +whoever picks it up does not repeat it: + +- The key is **not** mis-scoped: `/api/client/account` and `/api/client/permissions` both answer 200. +- The account is **not** missing ownership: `/api/application/servers` lists six servers, and server 7 + carries `"user": 1`. +- **Includes are broken on this panel independently**, which is worth knowing before trusting a + diagnosis built on them: `/api/application/servers?include=user` returns an *empty* list where the + same route without the include returns six, and `/api/application/users/1?include=servers` reports + zero servers owned. Neither is evidence of anything about ownership. + +The remaining candidates are a stale panel cache and the key's allowed-IP field. Worth noting that +`gitea.whitlocktech.com` was returning 502 and Cloudflare 530 during the same window, so "something +is wrong with that host right now" is a live hypothesis rather than a coincidence to dismiss. + +Everything else in this section was closed on 2026-09-15. *Clans in the base set while the Team provider reads first-party* was confirmed as the intended reading: complementary, not in conflict — the plugin is installed for alliances and clan chat, the