docs(modules): record the Pterodactyl client key and its empty-server-list problem

The token file now carries both keys. The client key authenticates as the
admin owner and then lists zero servers, on every listing type and for both
the short identifier and the full UUID, so tier 2 of R21's deployment loop is
not usable yet. Reinstall and SFTP are unaffected.

Records the diagnosis rather than only the symptom, including one trap worth
not repeating: includes are independently broken on this panel, so
servers?include=user returns an empty list where the same route without the
include returns six. Nothing built on an include is evidence about ownership.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016wDDVXWMDz82WqE1i969r4
This commit is contained in:
2026-09-15 21:08:15 -05:00
parent 5890da633f
commit a29cdf0fae

View File

@@ -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 converting the Oxide rig would start out holding the Oxide rig's state, and would prove less than a
fresh one. fresh one.
**The access, and the one thing it cannot do.** The panel's application API token is at **The access, and the two kinds of key it takes.** `RunicGateway/pterodactyl_claude_api_token` holds
`RunicGateway/pterodactyl_claude_api_token` (`ptla_…`). It creates and configures servers, both, one per line: an **application** key (`ptla_…`), which creates and configures servers,
allocations and users, and reads eggs. **It cannot touch files, power or console** — Pterodactyl puts allocations and users and reads eggs but **cannot touch files, power or console**; and a **client**
those on the *client* API, which rejects an application key outright. So the deployment loop is three key (`ptlc_…`), which is where Pterodactyl puts exactly those. An application key is rejected
tiers, matched to what each is for: 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 | | 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** | | **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 | | **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 **The client key now exists beside the application one**the token file holds both, as
application key cannot be widened into one, so the org lead generates it from the account page. Until `application:` and `user:` lines — but at the time of writing it authenticates and then sees **no
it exists, iteration is reinstall-only — correct, and slow enough that nobody would choose it twice. servers**, so tier 2 is not yet usable. §3 has the diagnosis. Until it is, iteration is
The push script itself lives in **`Rust-Plugins`**, mirroring where `deploy.ps1` lives for ServUO. 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 ## 3. Open questions
**None — but one outstanding request.** R21's iteration loop needs a Pterodactyl **client** API key **None — but one thing is unresolved on the panel.** R21's iteration loop needs a Pterodactyl
(`ptlc_…`); the application key already on disk cannot be widened into one, and only the account **client** API key, and one now exists (`ptlc_…`, alongside the application key, both in
holder can mint it. Not a question and not a decision: until it exists, pushing a file to a rig means `RunicGateway/pterodactyl_claude_api_token`). It authenticates correctly —
a panel reinstall. Everything else in this section was closed on 2026-09-15. `/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 *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 reading: complementary, not in conflict — the plugin is installed for alliances and clan chat, the