Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .spec/knowledge/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ metadata:
|------|--------|
| [`features/_TEMPLATE.md`](features/_TEMPLATE.md) | 新功能文档模板——新增功能记录时照此建,放对 领域 / 模块 |
| [`features/gameplay/chat-component.md`](features/gameplay/chat-component.md) | ChatComponent 字段声明与 SetMessage——查 persist-only last-message、下一 Tick 提交与有界输入 reject |
| [`features/gameplay/entity-chat-harness.md`](features/gameplay/entity-chat-harness.md) | 101-entity C# MVP acceptance harness——查 mvp-host/rust 11 场景活 traces、nent census 与 Bot 启动 |
| [`features/gameplay/entity-chat-harness.md`](features/gameplay/entity-chat-harness.md) | 101-entity rust-host acceptance harness——查 lumio-entity-chat-replay 11 场景、客户端 chat.event 与落盘 |

## lessons(经验教训 · 复发问题暂存区)

Expand Down
2 changes: 1 addition & 1 deletion .spec/knowledge/features/gameplay/chat-component.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ metadata:
## 待解决

- 接入 GameRuntime `EcsWorld` / Ingress 13 相(本切片用 Room 内权威宿主,不阻塞平行开发)。
- 101-entity SUCCESS 路径是 sibling `lumio-mvp-host`(或 rust `lumio-entity-chat-replay`上 11 场景全部 `ok: true`;`GameRoomHost` 只作单元 double。见 [`entity-chat-harness.md`](./entity-chat-harness.md)。
- 101-entity SUCCESS 路径是 sibling `lumio-entity-chat-replay` 上 11 场景全部 `ok: true`;`GameRoomHost` 与 `lumio-mvp-host` 不是 SUCCESS 路径。见 [`entity-chat-harness.md`](./entity-chat-harness.md)。

## 相关

Expand Down
24 changes: 12 additions & 12 deletions .spec/knowledge/features/gameplay/entity-chat-harness.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,36 @@
---
name: entity-chat-harness
description: 101-entity C# MVP acceptance harness——查 mvp-host/rust 11 场景活 traces、nent census 与 Bot 启动
description: 101-entity rust-host acceptance harness——查 lumio-entity-chat-replay 11 场景、客户端 chat.event 与落盘
metadata:
type: doc
status: 已交付
---

# Entity-chat 101-entity harness

简介:LumioGame 集成验收面。Bot 启动器循环 `Bot01`–`Bot100`,经独立 Account Server login-or-register 进入同一 Room,加上一个 Browser PlayerEntity,构成 101 个 Game ECS Entity
简介:LumioGame 集成验收面。Bot01Bot100 加 Browser PlayerEntity 共 101 个实体,在 `lumio-entity-chat-replay` 上跑 11 场景;证据来自客户端收到的 `chat.event` 与落盘快照

## 背景 / 目标

- 消费冻结契约 C-1/C-2/C-3/C-4,不扩展 hello-wire-v1,不改归档 Hello 对象。
- 证明账号、绑定、查询、ChatComponent、重连/过期、隔离与 last-message 快照,并跑两轮对比
- 证明账号、绑定、查询、ChatComponent、重连/过期、隔离与 last-message 快照,并跑两轮、两包对比

## 设计

- **Gameplay 宿主**:sibling `lumio-mvp-host` 或 `lumio-entity-chat-replay`(同一 11 场景套件)。`GameRoomHost` 只作单元测试 double,不是 SUCCESS 路径。单元 double 只接受 C-3 已验证准入载荷,从不收用户名/口令;其 Chat 上行必须是冻结 `InputCommand`(`mappingId=chat.input` + LumioBinV1 `payload` + `payloadSha256`),解码后再交给 text-only `ChatInput`
- **Bot 启动器**:`Lumio.Game.EntityChat.Suite` 可对 Account Server 发 `123456` 测试口令与工具凭证;启动器主路径先对 mvp-host 做 101 路活升级,再经 loopback `test-control` 跑 S4–S11
- **证据**:census 必须来自 bindings + 17-key host-audit 的 `netEntityId`(`nent_*`);Browser 必须有 Playwright 实跑且 `injected:false`;无历史快照必须有可含历史的材料
- **BLOCKED**:容量 503 / Admission 未入 FullGraph / origin/main dll 缺失时写 `blocked.json`(`FullGraphComposition.cs` MaxConnections/MaxSessions + 实测错误),退出码 1,不回退 r-00344,不伪造 SUCCESS
- **census**:必须来自 `GET /test-control/bindings` 与 17-key audit 的 `nent_*`,不是 `hs.sessionId`、不是 login `accountId`、不是 launcher 循环下标 `"1"`..`"101"`。不得要求发明 `entity_admitted`,也不得接受无列表的 `{total:101}`
- **S8 reconnect**:重连重绑 Entity A 当且仅当两侧都有宿主 `NetEntityId`(`nent_*` / `nent-*`)且相等。`sessionId` 相等不是 rebind;Account-Server login `accountId` 单独也不是(那是 S9 Entity B)。不得把 `sessionId` 写成 `netEntityId`,也不得把 login `accountId` 塞进 host binding。诚实 `ok: false` 不得标 SUCCESS。Handshake 缺 session / SessionMismatch 时重试一次
- **S5–S11**:必须在 mvp-host test-control(bindings/query/chat/tick/expire/snapshot/restore/room-admit)或 rust replay 上留下独立 traces,且 1–11 全部 `ok: true`。sibling-gap / S8 nent-gap 的 `ok: false` 使证据包 FAIL。S5 `ok: true` 且带 unauthorized/invisible/stale 真查询 traces 不是 GameRoomHost suite-double。S6 `timerManagerInvoked` 仅当 tick 走宿主 timer / `POST /test-control/tick`,禁止 for-loop
- **Gameplay 宿主**:只能是 sibling `lumio-entity-chat-replay`。`GameRoomHost` 与 `lumio-mvp-host` 都不是 SUCCESS 路径
- **浏览器**:Playwright 页面必须接 Room 网线;`__lumioChat.window.lines` 由收到的 `chat.event` 填充。`receivedFromNetwork` 表示至少收到一条 `chat.event`,不是账号服登录成功
- **证据**:`eventOrder` / `appliedTicks` 来自 Node 客户端与 Playwright 实际收到的 `chat.event`;`restoredWindow` / `windowBeforeSnapshot` 是实测窗口长度。禁止由发送计数或字面量合成。`verify-evidence.mjs` 自身 sha256 写入 `evidence.oracleSha256`
- **S6**:Client Timer Manager 触发,`tickSource` 必须为 `native-kernel/tickFrame`,Client trace 含 Tick 5,10,15;窗口 101 条且 `roomSequence` 严格递增
- **S7**:宿主进程 A 落盘 → 进程 B 读回;`lastMessageText` 逐实体相等;`historyCount` 0;聊天窗不回填
- **S8**:旧连接先收到 `ConnectionSuperseded`,再重绑同一 Runtime `NetEntityId`
- **BLOCKED**:缺 `lumio-entity-chat-replay` / Account Server / Playwright / NativeCore 时写 `blocked.json`,退出码 1,不得把 not-ok 标 SUCCESS

## 待解决

- FullGraph `MaxConnections = 128` / `MaxSessions = 128` 可承载 101 路活连接(Server origin/main / `LUMIO_SERVER_ROOT`)。
- Playwright Chromium 缺失时 Browser 场景必须失败,不得注入事件后标 ok。
- 客户端 Timer Manager 与跨进程快照读回依赖 sibling Client/Runtime/Server 产物;缺失时 BLOCKED。

## 相关

- 代码:`modules/server-gameplay/src/Lumio.Game.EntityChat.Suite/`、`integration/entity-chat/`
- 代码:`integration/entity-chat/`
- 组件:[`chat-component.md`](./chat-component.md)
4 changes: 2 additions & 2 deletions .spec/knowledge/standards/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ dotnet test --project modules/server-gameplay/tests/Lumio.Game.ServerGameplay.Te
101-entity 端到端(显式触发,不进默认收口):

```text
node --test integration/entity-chat/verify-evidence.mjs
node --test integration/entity-chat/verify-evidence.mjs integration/entity-chat/scenarios.mjs integration/entity-chat/web/chat-window.test.mjs
node integration/entity-chat/launcher.mjs --out <evidenceDir>
```

两轮对比实体数 / event order / applied Tick。SUCCESS 仅当 sibling `lumio-mvp-host` 或 `lumio-entity-chat-replay` 实际准入 101 路活连接、census 来自 bindings + 17-key audit 的 `nent_*`,且场景 1–11 全部 `ok: true`、两轮 traces 一致。诚实 `ok: false`(含 sibling-gap / S8 nent-gap)使证据包 FAIL。容量 503、Admission 未入 FullGraph、origin/main Account Server / mvp-host 产物缺失必须记 BLOCKED(`blocked.json` + 文件:行 + 实测错误),不得回退 r-00344,不得用 `GameRoomHost` 伪造 SUCCESS。FullGraph 生产常量是 `MaxConnections = 128` / `MaxSessions = 128`
两轮、两包对比实体数 / event order / applied Tick。SUCCESS 仅当 sibling `lumio-entity-chat-replay` 实际准入 101 路活连接、census 来自 rust host-audit 的 `nent_*`,场景 1–11 全部 `ok: true`,且 `eventOrder` / `appliedTicks` / `restoredWindow` 来自客户端收到的 `chat.event` 或实测窗口。`lumio-mvp-host` 与 `GameRoomHost` 不是 SUCCESS 路径。缺 replay 二进制 / Playwright / 落盘材料必须记 BLOCKED,不得合成字段

公共契约变更必须在架构源 `LumioGameEngineArchitecture` 通过其契约闸门(见 `AGENTS.md`「收口门槛」);本仓只消费冻结 JSON,不另写协议。Scenario/Headless 与 formatter 命令随后续模块补进收口门槛。

Expand Down
71 changes: 22 additions & 49 deletions integration/entity-chat/README.md
Original file line number Diff line number Diff line change
@@ -1,73 +1,46 @@
# R-00354 101-Entity entity-chat 集成启动器
# R-00376 101-Entity entity-chat 集成启动器

Formal ECS entity-chat 端到端验收:Account Server + C# MVP Game host,100 Bot + 1 Browser,两轮确定性对比。契约真值在架构仓 `engine/wire/`(C-1..C-4),本目录不复制协议语义,只实现执行与对账。
Formal ECS entity-chat 端到端验收Account Server + `lumio-entity-chat-replay`,100 Bot + 1 Browser,两包两轮确定性对比。契约真值在架构仓 `engine/wire/`C-1..C-4)。本目录不复制协议语义只实现执行与对账。

- Node ESM;Node >= 24。Playwright 仅 Browser 场景需要(可复用 `integration/hello/node_modules`)
- `npm test` / `node --test verify-evidence.mjs` 是收口证据面;空证据包必须 FAIL。
- 不扩展 `hello-wire-v1`,不启动 R-00359
- Node ESMNode >= 24。Playwright 仅 Browser 场景需要可复用 `integration/hello/node_modules`
- `npm test` / `node --test verify-evidence.mjs` 是收口证据面空证据包必须 FAIL。
- 不扩展 `hello-wire-v1`。`GameRoomHost` 与 `lumio-mvp-host` 不是 SUCCESS 路径

## 文件

| 文件 | 职责 |
|------|------|
| `launcher.mjs` | 总指挥:启动 sibling lumio-mvp-host101 活升级 → SUCCESS 或 blocked.json |
| `verify-evidence.mjs` | 11 场景对账器(census 必须来自 mvp-host 进程 audit;suite-only GameRoomHost 必须 FAIL) |
| `bot-credential.mjs` | 按 account-server TestHarness 同形签发 Bot-tool credential(测试密钥) |
| `launcher.mjs` | 总指挥启动 sibling lumio-entity-chat-replay两包两轮 → SUCCESS 或 blocked.json |
| `verify-evidence.mjs` | 11 场景对账器census 来自 rust host-audit;oracle sha256 钉死) |
| `bot-credential.mjs` | 按 account-server TestHarness 同形签发 Bot-tool credential测试密钥 |
| `account-client.mjs` | `lumio-account-v1` login-or-register |
| `game-client.mjs` | `lumio.mvp.v0` 升级 + client Handshake;记录 FullGraph 128 连接预算 |
| `scenarios.mjs` | Bot01–Bot100 + Browser 驱动 |
| `game-client.mjs` | 遗留 mvp-host 客户端(不再是 SUCCESS 路径) |
| `scenarios.mjs` | Room 网线观察、Playwright、Bot 驱动 |
| `static-server.mjs` | web 资产静态服务 |
| `web/` | Playwright 用的 Browser 聊天页 |
| `web/` | Playwright 用的 Browser 聊天页(接 Room,填充 `__lumioChat.window.lines`) |

## 前置(sibling 构建产物)
## 前置sibling 构建产物

| 参数 | 来源 |
|------|------|
| `--account-exe` | LumioServer `account-server/.../lumio-account-server.exe` |
| `--host-exe` | LumioServer `mvp-host/.../lumio-mvp-host.exe` |
| `--contract-dir` | 架构仓 `engine/wire`(C-1..C-4 blob 见卡片) |
| `--out` | 证据目录(已被 gitignore:`evidence/`) |
| `LUMIO_ENTITY_CHAT_REPLAY` / `LUMIO_SERVER_ROOT` | LumioServer `lumio-entity-chat-replay` |
| `LUMIO_GAME_ROOT` | 本仓根(rust replay 调 Playwright helper) |
| `--out` | 证据目录(已被 gitignore:`evidence/`) |

密钥只走环境变量 / 本轮生成的测试密钥(`LUMIO_ACCOUNT_ADMISSION_PRIVATE_KEY_HEX`,`LUMIO_ACCOUNT_BOT_TOOL_PUBLIC_KEY_HEX`);不入库。

Account Server:

```text
lumio-account-server.exe --store-path <round>/account-store --listen 127.0.0.1:0
```

C# MVP host:

```text
lumio-mvp-host.exe --listen ws://127.0.0.1:0 --allow-insecure-loopback \
--shared-secret-file <generated> --reconnect-window-seconds 300 \
--enable-test-control --test-control-listen http://127.0.0.1:0 \
--audit-trace-file <round>/host-audit.ndjson
```
密钥只走环境变量 / 本轮生成的测试密钥;不入库。不硬编码开发机绝对路径。

## 运行

101-entity SUCCESS 路径是 sibling `lumio-mvp-host` 101 路活连接。`GameRoomHost` 只作单元测试 double。FullGraph `MaxConnections=128` 不能承载 101 路时必须 BLOCKED(`blocked.json` + `FullGraphComposition.cs` + 实测错误),不得收缩场景、不得回退 `wt-server/r-00344`。

构建 sibling host(LumioServer origin/main,本仓不改 Server 仓):

```bash
dotnet build --project <LumioServer>/mvp-host/src/Lumio.Server.MvpHost.App/Lumio.Server.MvpHost.App.csproj -c Release --nologo
```

```bash
node --test verify-evidence.mjs bot-credential.mjs
node --test verify-evidence.mjs scenarios.mjs web/chat-window.test.mjs
node launcher.mjs --out <evidenceDir>
```

退出码:0 SUCCESS(仅 101 路 mvp-host 实连且 11 场景有独立 traces),1 BLOCKED/FAILED。缺 origin/main Account Server dll 且已取得 101 路时退出 2。不伪造 101 实体
退出码0 SUCCESS(仅 rust replay 实连且 11 场景有客户端观测 traces)1 BLOCKED/FAILED。缺 replay 二进制时写 `blocked.json`。不伪造 101 实体,不合成 `eventOrder` / `appliedTicks` / `restoredWindow`

## 对账

- 101 = bindings + 17-key audit 的 `nent_*`;禁止 sessionId / login accountId / launcher 循环下标 `"1"`..`"101"` 当 NetEntityId,禁止 `{total:101}` 常数,禁止 GameRoomHost census dump。禁止发明 FullGraph 不会发的 `entity_admitted`。
- SUCCESS 要求场景 1–11 `ok: true` 且有独立 traces(mvp-host test-control 或 rust replay)。sibling-gap / S8 nent-gap 的诚实 `ok: false` 使证据包 FAIL。
- census / S4 / S8 用 bindings + 17-key audit 的 `nent_*`,不是 `hs.sessionId` 或 login `accountId`。
- S6 `timerManagerInvoked` 仅当 tick 走 `POST /test-control/tick` / 宿主 timer。S3 Playwright 必跑且 `injected:false`。
- 两轮对比 entity counts、event order、applied Tick。
- 失败矩阵:unauthorized / invisible / stale_generation / tombstoned,不得 alias。
- Snapshot 只保留 last-message,不恢复聊天历史。
- 101 = rust host-audit 的 C-1 NetEntityId(Runtime 发号 u64 / 32-hex;不得把 leftover `nent_*` 当真值)。
- SUCCESS 要求场景 1–11 `ok: true`,Playwright 收到 `chat.event`,S6 `tickSource=native-kernel/tickFrame`,S7 跨进程落盘,S8 旧连接收到 `ConnectionSuperseded`。
- `verify-evidence.mjs` 自身 sha256 必须写入 `evidence.oracleSha256`。
- Snapshot 只保留 last-message,不恢复聊天历史。
Loading
Loading