Documentation pass before a compact
ci / verify (push) Successful in 53s

Audited rather than appended. What had drifted, now corrected:

- ROADMAP's opening still described the project before this session: no
  word of the anti-cheat fixes, 468 tests, 23 smoke assertions, and a
  screenshot list half its current size. It now summarises the session,
  lists seven open items raised with the user and not yet decided (the
  boss-kill experience edge, the hub frame rate, aggro through corner
  cracks, the Warden-hall alcoves, one-tile arena doors, the Proving
  Grounds before release, hit feedback), and quotes current numbers.
  Its radius table still gave BULLET_INTEREST_RADIUS as the bullet cull
  at 2200; it is a 2900 ceiling over a per-bullet check.
- NETCODE described the flat bullet radius as the design, claimed the
  respawn lockout gates connected players (they are unbound on death),
  and called actor scoping "next stage". All corrected, and a new section
  covers what the handshake and server now refuse: duplicate sessions,
  reasons that now arrive, paced control messages, coalesced store
  writes, bounds-checked hot decoders.
- DECISIONS gains the audit's rules, the Proving Grounds' status, the
  tunnel and entrance rules, and the interface calls -- each flagged as
  the user's or as a judgement call.
- ARCHITECTURE's file map lacked the actor classes, the dev auth
  provider, the menu backdrop and any tools section.
- README told people to start a client with --name, which now only names
  bot characters, and its feature list predated fog, tunnels and carried
  health. CLAUDE.md gains three invariants (health on the record, one
  session per account, tools that host use scratch data); WORKFLOW gains
  the four traps this session fell into or nearly did.

Every doc was checked for unintended deletions against the session's
start, and every relative link resolves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
claudeandClaude Opus 5.5 committed 2026-10-05 18:05:56 +02:00
1 parent 94ad6b3429
commit 08f58af1a8
7 files changed
+251 -26

No files matched your search

+42 -7
View File
@@ -23,6 +23,23 @@ a lobby hub with dungeon runs, and an emergency escape. All of that exists, plus
the four stages that followed: characters and permadeath, inventory and loot,
upgrades, and a second boss that moves.
Since then, in one long session:
- **An anti-cheat audit, and its fixes.** Item duplication through two sessions
on one account; shots through walls from muzzle offsets (the player's and every
boss's); every firing enemy located by the flat bullet-interest radius;
unbounded store writes from small packets; the hub's escape channel; hub loot
griefing; unbounded snapshot and event decoders. Each is in DECISIONS.md under
"The anti-cheat audit".
- **Health survives a door**, the hub regenerates it at 10%/s, and experience goes
only to players within `XP_AWARD_RADIUS` of the kill.
- **Fog lit by rays**, so shadows cut through tiles ([visibility.gd](../src/view/visibility.gd)),
and **bullets fade past the edge of sight** without ever arriving unseen.
- **Tunnels 2–4 wide**, an occasional enemy group in them, nothing watching the
entrance on arrival, and arenas that keep their walls.
- **Two interface passes** — see the Interface section of DECISIONS.md.
- **The smoke flake is fixed** (below).
So there is no obvious "next ticket". What follows is the honest list of
candidates, none of which the user has chosen — **ask before starting one.**
@@ -35,6 +52,18 @@ candidates, none of which the user has chosen — **ask before starting one.**
| **Replace the two non-redistributable packs** | Bullet and FX art is local-only and non-commercial, which blocks both a public repo copy and a commercial release. | CC0 or CC BY replacements. See [ASSETS.md](ASSETS.md). |
| **Transport encryption** | `ENetMultiplayerPeer` supports DTLS. Required before a public server, not before then. | Follows the auth decision. |
And smaller things raised with the user and not yet answered or chosen:
| Open item | What is known |
| --- | --- |
| **A boss kill can pay nothing** | Both arenas are wider corner to corner (803 and 630 units) than `XP_AWARD_RADIUS` (506), so a player in the far corner when the boss dies gets no experience for the run. Suggested fix: anyone inside the boss room counts as present for a boss kill. |
| **The hub renders at ~60 fps, a dungeon at ~240** | Measured with the old fog and the new, same scene: not the fog. Cause unknown. |
| **Aggro sees through cracks the fog closes** | `MapGrid.has_line_of_sight` steps diagonally between two tiles that touch only at a corner. The fog treats that as closed, so an enemy can occasionally see and shoot you through a gap you cannot see through. |
| **Two one-tile alcoves in the Warden's hall** | Rows 4 and 8 of `Rooms.warden_hall()` are one character longer than the rest, leaving notches in the east wall. Possibly a typo; asked, not answered. |
| **Arena doors are one tile wide** | Authored in the stamps. Tunnels into them are now at least two. |
| **The Proving Grounds must not ship** | Full experience for an 8%-health boss. Remove it from `Dungeons.ORDER` and its `P` marker before a release. |
| **Hit feedback on enemies** | `Art.IMPACT` is still loaded and never played (the candidate above). |
Each stage below also carries its own **Known gaps** section — those are smaller
and more specific than the table above.
@@ -60,8 +89,8 @@ What "everything passes" currently means. Numbers move; the shape does not.
| Gate | Covers | Runtime |
| --- | --- | --- |
| `tools/check.sh` | every script parses and type-checks | ~5s |
| `tools/test.sh` | 468 GUT tests, no SceneTree | ~4s |
| `tools/smoke.sh` | 23 assertions over a real ENet socket: handshake, auth, character creation and persistence, both dungeon kinds, escape, hard kill, polite disconnect | ~40s |
| `tools/test.sh` | 576 GUT tests, no SceneTree | ~4s |
| `tools/smoke.sh` | 27 assertions over a real ENet socket: handshake, auth, character creation and persistence, all three dungeons, escape, hard kill, polite disconnect, a duplicate account refused with its reason | ~40s |
| `diag_prediction.tscn` | client-prediction gap, with injected clock drift | ~10s |
| `diag_progression.tscn` | kill → xp → level → health, death → retire → roster, swap guards | ~10s |
| `diag_loot.tscn` | drop → snapshot → pick up → persist → use → drop, and both loot visibilities on the wire | ~10s |
@@ -69,10 +98,15 @@ What "everything passes" currently means. Numbers move; the shape does not.
`tools/screenshot.tscn` is a **manual** check, not a gate: it needs a display,
and it is the only thing in the project that can tell you the interface
actually rendered. Run it after touching `src/ui/`. It captures the main menu,
the HUD, the pause menu, settings, credits and the upgrade choice — the last of
those by staging an offer, because earning one would make the shot depend on a
dungeon run.
actually rendered. Run it after touching `src/ui/` or `src/view/`. It captures
the connect screen, the hub standing on a portal, the pause menu, settings,
credits, the upgrade choice, the roster after a death, a dungeon arrival, a
tunnel (with and without F1), a staged boss fight, and the escape banner. It runs
on **its own character store and account** — it used to host on the player's
real ones — and stages what it cannot earn (an offer, a party, a death).
Timings are frame counts and frames run as fast as the display allows, so
anything tied to server ticks is captured by condition instead (see the escape
shot).
It has now caught four bugs that every other gate passed: the theme applying to
nothing, the test suite rewriting the player's settings, an invisible slider
@@ -126,7 +160,8 @@ terrain it does not have.
| `FOG_VIEW_RADIUS` | 460 | — | What the player can see. |
| `ACTOR_INTEREST_RADIUS` | 800 | fog radius | Enemies beyond it are never sent. Above the fog radius so nothing pops in at the edge of sight. |
| `MAP_STREAM_RADIUS` | 900 | fog radius | Client predicts movement and simulates bullets against terrain it cannot see. |
| `BULLET_INTEREST_RADIUS` | 2200 | longest bullet travel + fog radius | A bullet is announced once at spawn. Withhold one that later flies into view and it becomes invisible damage. `test_interest.gd` computes the floor from real content, so a faster bullet fails a test instead. |
| `BULLET_INTEREST_RADIUS` | 2900 | longest bullet travel + fog radius | **A ceiling only.** Spawns are culled per bullet — can *this* one reach visible ground (`ServerRuntime._bullet_concerns`). As a flat cull it exceeded the depth-1 map and located every firing enemy for everyone. |
| `XP_AWARD_RADIUS` | 506 | 1.1 × fog radius | Experience goes to the living players within it of the kill, undivided. |
Fog is a *rendering* rule and defends nothing on its own — a modified client
draws whatever it holds. The defence is what the server declines to send.