Skip to content

Commit e4b3908

Browse files
committed
docs: document client-version loading slice
1 parent a035f85 commit e4b3908

8 files changed

Lines changed: 182 additions & 5 deletions

File tree

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Current scope of the project:
1515
- A stub-compatible binary smoke path that reaches `GAME` with the current public bootstrap flows.
1616
- A deterministic single-character `MOVE` round-trip wired through the current bootstrap runtime.
1717
- A deterministic selected-character `SYNC_POSITION` reconciliation path wired through the current bootstrap runtime.
18+
- A tolerant `CLIENT_VERSION` metadata path accepted during `LOADING` before `ENTERGAME`.
1819
- A first visible-world bootstrap that inserts the selected character into the game world after `ENTERGAME`.
1920
- A first self-only `CHARACTER_UPDATE` refresh emitted immediately after the visible-world insert.
2021
- A first self-only `PLAYER_POINT_CHANGE` refresh emitted immediately after the selected-character update.
@@ -113,6 +114,7 @@ Legend:
113114
- `spec/protocol/auth-login.md`
114115
- `spec/protocol/login-selection.md`
115116
- `spec/protocol/select-world-entry.md`
117+
- `spec/protocol/client-version-loading.md`
116118
- `spec/protocol/visible-world-bootstrap.md`
117119
- `spec/protocol/character-update-bootstrap.md`
118120
- `spec/protocol/player-point-change-bootstrap.md`
@@ -190,7 +192,7 @@ Current stub bootstrap credentials:
190192

191193
Current minimal runtime path exposed by the shipped binaries:
192194
- `authd`: `HANDSHAKE -> AUTH -> LOGIN3 -> AUTH_SUCCESS`
193-
- `gamed`: `HANDSHAKE -> LOGIN -> SELECT -> EMPIRE_SELECT? -> CHARACTER_CREATE? -> CHARACTER_SELECT -> LOADING -> GAME -> CHARACTER_ADD -> CHAR_ADDITIONAL_INFO -> CHARACTER_UPDATE -> PLAYER_POINT_CHANGE -> MOVE/SYNC_POSITION`
195+
- `gamed`: `HANDSHAKE -> LOGIN -> SELECT -> EMPIRE_SELECT? -> CHARACTER_CREATE? -> CHARACTER_SELECT -> LOADING -> CLIENT_VERSION? -> ENTERGAME -> GAME -> CHARACTER_ADD -> CHAR_ADDITIONAL_INFO -> CHARACTER_UPDATE -> PLAYER_POINT_CHANGE -> MOVE/SYNC_POSITION`
194196

195197
This is still a bootstrap runtime, not full gameplay.
196198
What exists today:
@@ -201,6 +203,7 @@ What exists today:
201203
- deterministic selected-character `SYNC_POSITION` reconciliation in `GAME`
202204
- bootstrap movement updates character coordinates and persists them across fresh auth/game sessions
203205
- empty-account bootstrap flow can select empire before first character creation, and that choice persists across fresh auth/game sessions
206+
- tolerant `CLIENT_VERSION` acceptance in `LOADING` with no phase transition and no server response
204207
- the selected character is inserted into the visible world after `ENTERGAME` via minimal `CHARACTER_ADD` + `CHAR_ADDITIONAL_INFO` + `CHARACTER_UPDATE` + `PLAYER_POINT_CHANGE`
205208

206209
What still does not exist yet:
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Client-Version Loading Slice Implementation Plan
2+
3+
> For Hermes: use test-driven-development. Keep slices tiny and push one commit at a time.
4+
5+
Goal: accept `CLIENT_VERSION` during `LOADING` as tolerant client metadata so a TMP4 client can send it before `ENTERGAME` without desynchronizing the session.
6+
7+
Architecture: freeze a small control-plane codec for `CLIENT_VERSION`, extend world-entry and boot tests to cover the loading-time no-op path, then document the exact packet layout and phase behavior.
8+
9+
Tech stack: Go 1.26, existing frame/session/control/world-entry packages, current authd/gamed bootstrap runtime.
10+
11+
---
12+
13+
## Task 1: Freeze the `CLIENT_VERSION` packet codec
14+
Objective: define the fixed-width payload shape and decoding behavior.
15+
16+
Files:
17+
- Modify: `internal/proto/control/control.go`
18+
- Modify: `internal/proto/control/control_test.go`
19+
20+
Steps:
21+
1. Write failing tests for:
22+
- `CLIENT_VERSION` encode/decode round-trip
23+
- invalid payload length rejection
24+
2. Run: `go test ./internal/proto/control`
25+
3. Implement the smallest codec set to pass.
26+
4. Re-run: `go test ./internal/proto/control`
27+
5. Commit: `feat: add client-version control codec`
28+
29+
## Task 2: Accept `CLIENT_VERSION` in `LOADING`
30+
Objective: tolerate the client metadata packet without changing session state.
31+
32+
Files:
33+
- Modify: `internal/worldentry/flow.go`
34+
- Modify: `internal/worldentry/flow_test.go`
35+
36+
Steps:
37+
1. Write failing tests for:
38+
- `CLIENT_VERSION` is accepted in `LOADING`
39+
- the flow returns no frames
40+
- the session remains in `LOADING`
41+
2. Run: `go test ./internal/worldentry`
42+
3. Implement the smallest loading-phase branch to pass.
43+
4. Re-run: `go test ./internal/worldentry`
44+
5. Commit: `feat: accept client-version during loading`
45+
46+
## Task 3: Cover boot composition
47+
Objective: prove the composed boot flow and TCP harness tolerate `CLIENT_VERSION` before `ENTERGAME`.
48+
49+
Files:
50+
- Modify: `internal/boot/flow_test.go`
51+
- Modify: `internal/boot/flow_socket_test.go`
52+
53+
Steps:
54+
1. Add failing unit and socket tests that send `CLIENT_VERSION` in `LOADING` before `ENTERGAME`.
55+
2. Run: `go test ./internal/boot`
56+
3. Re-run after wiring the world-entry path.
57+
4. Commit: `test: cover client-version loading path`
58+
59+
## Task 4: Update docs
60+
Objective: document the tolerated loading-time metadata path.
61+
62+
Files:
63+
- Modify: `README.md`
64+
- Modify: `spec/protocol/README.md`
65+
- Modify: `spec/protocol/boot-path.md`
66+
- Modify: `spec/protocol/session-phases.md`
67+
- Modify: `spec/protocol/select-world-entry.md`
68+
- Modify: `spec/protocol/packet-matrix.md`
69+
- Create: `spec/protocol/client-version-loading.md`
70+
71+
Steps:
72+
1. Document packet layout and no-response behavior.
73+
2. Run: `go test ./... && go vet ./...`
74+
3. Commit: `docs: document client-version loading slice`
75+
76+
## Verification
77+
- `go test ./internal/proto/control`
78+
- `go test ./internal/worldentry`
79+
- `go test ./internal/boot`
80+
- `go test ./...`
81+
- `go vet ./...`
82+
83+
## Scope guardrails
84+
- Do not enforce version matching yet.
85+
- Do not persist the metadata yet.
86+
- Do not add a server reply packet.
87+
- Do not broaden acceptance outside `LOADING` in this slice.

spec/protocol/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ The repository targets TMP4-era client compatibility, but the protocol contract
1010
- `auth-login.md` — minimal auth-server credential exchange and login-key issuance
1111
- `login-selection.md` — minimal login-by-key and selection-surface packet layouts
1212
- `select-world-entry.md` — minimal selection, loading, and enter-game packet choreography
13+
- `client-version-loading.md` — tolerant `CLIENT_VERSION` metadata path during `LOADING`
1314
- `character-update-bootstrap.md` — first self-only state refresh after entering `GAME`
1415
- `player-point-change-bootstrap.md` — first self-only point refresh after entering `GAME`
1516
- `sync-position-bootstrap.md` — first self-only sync-position reconciliation after entering `GAME`

spec/protocol/boot-path.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,11 @@ Expected outcomes:
8989
## 7. Loading/bootstrap completes
9090
The server sends the minimum required bootstrap data for the selected character.
9191
This typically includes the main character and player points, plus any other mandatory world bootstrap packets.
92+
During this phase the client may also emit `CLIENT_VERSION` metadata before it proceeds to `ENTERGAME`.
9293

9394
Expected outcomes:
9495
- the client accepts the selected character context
96+
- the server tolerates `CLIENT_VERSION` in `LOADING` without changing phase
9597
- the client can issue the enter-game action
9698

9799
## 8. Enter game succeeds
@@ -137,6 +139,7 @@ This document depends on:
137139
- `spec/protocol/session-phases.md`
138140
- `spec/protocol/frame-layout.md`
139141
- `spec/protocol/packet-matrix.md`
142+
- `spec/protocol/client-version-loading.md`
140143
- `spec/protocol/character-update-bootstrap.md`
141144
- `spec/protocol/player-point-change-bootstrap.md`
142145
- `spec/protocol/sync-position-bootstrap.md`
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Client-Version Metadata During Loading
2+
3+
This document freezes the first minimal `CLIENT_VERSION` slice for the TMP4 boot path.
4+
5+
The goal of this slice is narrow:
6+
- accept `CLIENT_VERSION` in `LOADING`
7+
- decode its fixed-width metadata payload
8+
- keep the session in `LOADING`
9+
- emit no server response
10+
11+
This slice is intentionally tolerant.
12+
It does not yet enforce any version policy.
13+
14+
## Covered packet
15+
16+
- `CLIENT_VERSION`
17+
18+
## Envelope
19+
20+
The packet uses the project-wide CG/GC frame envelope:
21+
22+
- `header``uint16`, little-endian
23+
- `length``uint16`, little-endian, total frame size including the 4-byte envelope
24+
- `payload` — packet-specific bytes
25+
26+
See `frame-layout.md` for the envelope contract.
27+
28+
## `CLIENT_VERSION`
29+
30+
Direction:
31+
- client -> server
32+
33+
Header:
34+
- `0x000D`
35+
36+
Payload layout:
37+
- `executable_name` — fixed `33` bytes (`32 + 1`)
38+
- `timestamp` — fixed `33` bytes (`32 + 1`)
39+
40+
Frame length:
41+
- `70` bytes total (`4 + 33 + 33`)
42+
43+
String rules:
44+
- strings are carried in fixed-width fields
45+
- a trailing zero byte may terminate the string early
46+
- unused bytes remain zero-filled
47+
- the server trims at the first zero byte when decoding
48+
49+
## Working flow
50+
51+
The current server-owned behavior is:
52+
53+
1. the session is already in `LOADING`
54+
2. the client may send `CLIENT_VERSION`
55+
3. the server decodes `executable_name` and `timestamp`
56+
4. the server emits no response packet
57+
5. the session remains in `LOADING`
58+
6. the client may still proceed to `ENTERGAME`
59+
60+
## Notes
61+
62+
- This packet is currently treated as metadata only.
63+
- The first implementation does not persist the values.
64+
- The first implementation does not reject by filename or timestamp.
65+
- Version gating can be layered in later once compatibility evidence is stronger.
66+
67+
## Slice scope
68+
69+
This slice freezes:
70+
- packet identity
71+
- payload layout
72+
- tolerant acceptance in `LOADING`
73+
- no-response behavior
74+
75+
It does not yet freeze:
76+
- any exact build string policy
77+
- auth/login-time handling
78+
- repeated-client-version policy beyond "accept and ignore"
79+
- logging requirements

spec/protocol/packet-matrix.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Status values:
1818
| `KEY_RESPONSE` | client -> server | `0x000A` | handshake | documented | cryptographic response path |
1919
| `KEY_CHALLENGE` | server -> client | `0x000B` | handshake | documented | challenge + server key material |
2020
| `KEY_COMPLETE` | server -> client | `0x000C` | handshake | documented | completes key exchange |
21-
| `CLIENT_VERSION` | client -> server | `0x000D` | late handshake/loading | planned | exact timing to be locked by tests |
21+
| `CLIENT_VERSION` | client -> server | `0x000D` | loading | documented | accepted as metadata in `LOADING`; no server response and no phase transition |
2222

2323
## Authentication and selection surface
2424

spec/protocol/select-world-entry.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ It does not yet freeze the full visible-world packet set.
2020
- `PLAYER_CREATE_SUCCESS`
2121
- `PLAYER_CREATE_FAILURE`
2222
- `CHARACTER_SELECT`
23+
- `CLIENT_VERSION`
2324
- `ENTERGAME`
2425
- `MAIN_CHARACTER`
2526
- `PLAYER_POINTS`
@@ -52,9 +53,10 @@ The current project-owned selection/world-entry flow is:
5253
- `PHASE(LOADING)`
5354
- `MAIN_CHARACTER`
5455
- `PLAYER_POINTS`
55-
10. the client sends `ENTERGAME`
56-
11. the server transitions to `GAME`
57-
12. the server emits:
56+
10. the client may send `CLIENT_VERSION` metadata while staying in `LOADING`
57+
11. the client sends `ENTERGAME`
58+
12. the server transitions to `GAME`
59+
13. the server emits:
5860
- `PHASE(GAME)`
5961
- `CHARACTER_ADD`
6062
- `CHAR_ADDITIONAL_INFO`

spec/protocol/session-phases.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ Purpose:
9191
Typical traffic in this phase:
9292
- main character bootstrap packet(s)
9393
- player points / stats
94+
- `CLIENT_VERSION` metadata from the client
9495
- optional time/channel/world bootstrap data
9596
- enter-game request from the client
9697

@@ -157,6 +158,7 @@ A packet decoder may still parse them, but the session layer must not process th
157158
### `LOADING`
158159
- a concrete character choice already exists
159160
- world bootstrap is in progress
161+
- `CLIENT_VERSION` metadata may be accepted here without changing phase
160162
- arbitrary in-world actions are still invalid
161163

162164
### `GAME`

0 commit comments

Comments
 (0)