diff --git a/docs/superpowers/plans/2026-09-05-local-platform-login.md b/docs/superpowers/plans/2026-09-05-local-platform-login.md index 5cbfae0..b47302b 100644 --- a/docs/superpowers/plans/2026-09-05-local-platform-login.md +++ b/docs/superpowers/plans/2026-09-05-local-platform-login.md @@ -1,6 +1,6 @@ # Local Platform Login Implementation Plan -> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development to implement this plan task-by-task. Steps use checkbox (`- [x]`) syntax for tracking. **Goal:** 在主 checkout 的联调分支中完成启动、真实资源加载、游客登录与本地服务器响应展示的验收。 **Architecture:** 复用 Runtime/Controller/WireClient 与 local sources,开发目录内组合严格 Transport、范围包装、诊断 GameEntry 和 Cocos 端口。无新 Store/Router。 @@ -11,7 +11,7 @@ - 服务器、远程配置服务、settings/WVJB 契约零改动。默认 prod、BUILD_IDENTITY 及原生配置优先级保持不变。 - 不修改生产 GameEntry 契约,不选择真实子游戏,不接其他业务 RPC,不替换现有 Login/Launch/MainMenu 场景,不复做 3A。 -- 代码新增只在 YouleNexus/assets/scripts/local-platform-login/,测试在 framework-tests/local-platform-login/;下文路径均相对 cocoscreator_projects/。 +- 诊断代码新增只在 YouleNexus/assets/scripts/local-platform-login/,测试在 framework-tests/local-platform-login/;下文路径均相对 cocoscreator_projects/。实际 Creator 预览发现既有 SDK 测试辅助模块的 node:assert 阻断所有脚本加载,按最小来源修复扩展三个既有文本文件:sdk/testing/game-contract-harness.ts、对应测试和 framework/README.md,改为必需的调用方断言依赖;没有额外资源改动。 - .scene/.prefab/.anim/.meta 只能由 Creator/MCP 生成或保存;写入/提交仅限 spec 第8节,其他导入副产物保留且报告。 - 按用户最新授权,在 G:/Works/YouleGamesCocosCreator 使用 codex/local-platform-login;Creator projectPath 必须为该目录下 cocoscreator_projects/YouleNexus。原有50项改动按路径/状态/哈希保护,精确暂存,不自动 stash。 - 显式枚举纯 TS 测试及两项指定 architecture 测试;禁止 npm test、run-framework-tests.mjs、test:framework。tsx ENOMEM 精确升级运行,不改业务代码。 @@ -22,7 +22,7 @@ **Files:** Create YouleNexus/assets/scripts/local-platform-login/local-login-transport.ts; Test framework-tests/local-platform-login/transport.test.ts。 **Interfaces:** export LocalLoginEvidence = {kind:string; data:unknown}; export EvidenceSink=(event:LocalLoginEvidence)=>void。export LocalLoginTransport implements Transport;constructor options {context:LocalStartupContext; createSocket:(url:string)=>WebSocket; onFault:(error:unknown)=>void; record:EvidenceSink}。注入真实浏览器构造器仅在组件根完成。 -- [ ] 写 RED 测试,FakeSocket 实现标准 open/message/close/error 回调与 readyState/send/close。导入缺失模块必须是语义 RED。 +- [x] 写 RED 测试,FakeSocket 实现标准 open/message/close/error 回调与 readyState/send/close。导入缺失模块必须是语义 RED。 ```ts assert.throws(() => transport.send('{}'), /open/i); transport.connect(context.config.servers[0]!); @@ -30,7 +30,7 @@ socket.readyState = 1; socket.onopen?.({} as Event); transport.send('frame'); assert.deepEqual(socket.sent, ['frame']); ``` -- [ ] 实现每次 connect 前 assertLocalConnectionTarget;构造器/校验失败先 onFault 再抛出。close 显式停止后回调失效;回调捕获 socket 实例,只交付当前连接。 +- [x] 实现每次 connect 前 assertLocalConnectionTarget;构造器/校验失败先 onFault 再抛出。close 显式停止后回调失效;回调捕获 socket 实例,只交付当前连接。 ```ts const socket = options.createSocket(url); this.socket = socket; @@ -41,28 +41,28 @@ socket.onmessage = event => { }; ``` 以上注释分支必须实现:非文本构造 TypeError→关闭/失效→报告,文本记录成功后交付;record 抛错按显式故障清理,不吞掉。 -- [ ] RED/GREEN:远程 URL 不构造;构造错误 cause/原对象保留;OPEN 前 send 失败;非文本失败不交付;error/close 单次 close 通知;自然 close 允许 Wire 重连;显式 close 无重连回调;旧实例事件无效;关闭抛错可定位。入站握手在 codec 前被 record 捕获,发送证据只记录成功 send。 -- [ ] `node --import tsx --test framework-tests/local-platform-login/transport.test.ts`、`node node_modules/typescript/bin/tsc -p tsconfig.framework.json --noEmit`、`node scripts/check-import-boundaries.mjs`、git diff --check。审查后只提交 source/test,无 meta。 +- [x] RED/GREEN:远程 URL 不构造;构造错误 cause/原对象保留;OPEN 前 send 失败;非文本失败不交付;error/close 单次 close 通知;自然 close 允许 Wire 重连;显式 close 无重连回调;旧实例事件无效;关闭抛错可定位。入站握手在 codec 前被 record 捕获,发送证据只记录成功 send。 +- [x] `node --import tsx --test framework-tests/local-platform-login/transport.test.ts`、`node node_modules/typescript/bin/tsc -p tsconfig.framework.json --noEmit`、`node scripts/check-import-boundaries.mjs`、git diff --check。审查后只提交 source/test,无 meta。 ## Task 2: 诊断 GameEntry 与 Wire 范围边界 **Files:** Create local-login-game-entry.ts、local-login-wire.ts 于上述脚本目录;Test framework-tests/local-platform-login/game-entry.test.ts、wire.test.ts。 **Interfaces:** createDiagnosticGameEntry(gameId:string|number,record:EvidenceSink):GameEntry;createLocalLoginWire({context,transportFactory,onFault,record}):PlatformWireClient,transportFactory:()=>Transport。只包装一个 new WireClient({servers:context.config.servers,transportFactory})。 -- [ ] RED:真实 new GameSessionHost(entry) 会创建/释放诊断对象;entry.resolveSeatCount([]) 必须抛错,module.attach/restore/events 均抛出操作名。dispose 状态转换记录一次,重复释放安全;key/route 为 local-platform-login,不是协议平台 route。 +- [x] RED:真实 new GameSessionHost(entry) 会创建/释放诊断对象;entry.resolveSeatCount([]) 必须抛错,module.attach/restore/events 均抛出操作名。dispose 状态转换记录一次,重复释放安全;key/route 为 local-platform-login,不是协议平台 route。 ```ts const host = new GameSessionHost(createDiagnosticGameEntry(context.config.identity.gameid, record)); assert.equal(host.state, 'idle'); assert.throws(() => entry.resolveSeatCount([]), /resolveSeatCount/); ``` -- [ ] RED/GREEN 工厂实现:模块实例编号递增,created→disposed,所有游戏行为 record violation 后 throw。不得返回座位数、空处理结果或真实子游戏模块。 -- [ ] Wire RED:真实 WireClient 配合 fake Transport 输入完整 login fixture;成功大厅原 event 引用交付;合法房间恢复在 Runtime 前终止;损坏响应保留解析错误;拒绝非 agent/player_login 出站且无 send。 +- [x] RED/GREEN 工厂实现:模块实例编号递增,created→disposed,所有游戏行为 record violation 后 throw。不得返回座位数、空处理结果或真实子游戏模块。 +- [x] Wire RED:真实 WireClient 配合 fake Transport 输入完整 login fixture;成功大厅原 event 引用交付;合法房间恢复在 Runtime 前终止;损坏响应保留解析错误;拒绝非 agent/player_login 出站且无 send。 ```ts const parsed = parseLoginResponse(event.message.data); if (parsed.state === 0 && parsed.room !== null) failScope('login room recovery'); ``` -- [ ] 实现 subscribe 返回注销函数,单个内部订阅转发;所有切服、room/子游戏 message 终止;agent/platform 普通推送原样交付。kick/非零登录回包先交付现有处理链,再通知宿主停止本次验收,以保留原始失败显示。故障单次锁存,先释放底层订阅与 Wire,后通知宿主,清理错误不能丢弃。实现 stop 幂等;生命周期 start/stop 不假装已经连接。 -- [ ] `node --import tsx --test framework-tests/local-platform-login/game-entry.test.ts framework-tests/local-platform-login/wire.test.ts`,覆盖范围禁止后零继续交付/零重连、正常重连同一信封。类型/导入/diff 检查,审查与 scoped commit。 +- [x] 实现 subscribe 返回注销函数,单个内部订阅转发;所有切服、room/子游戏 message 终止;agent/platform 普通推送原样交付。kick/非零登录回包先交付现有处理链,再通知宿主停止本次验收,以保留原始失败显示。故障单次锁存,先释放底层订阅与 Wire,后通知宿主,清理错误不能丢弃。实现 stop 幂等;生命周期 start/stop 不假装已经连接。 +- [x] `node --import tsx --test framework-tests/local-platform-login/game-entry.test.ts framework-tests/local-platform-login/wire.test.ts`,覆盖范围禁止后零继续交付/零重连、正常重连同一信封。类型/导入/diff 检查,审查与 scoped commit。 ## Task 3: 纯 TS 宿主组合与启动操作 @@ -70,41 +70,41 @@ if (parsed.state === 0 && parsed.room !== null) failScope('login room recovery') **Interfaces:** createLocalLoginHost(options): {start():Promise;login():Promise;stop():void;getSnapshot():{state:PlatformState|null;ready:boolean;busy:boolean}}。 options: configOptions:ResolveRuntimeConfigOptions、storage:LocalStoragePort、random:()=>number、now:()=>number、sampleHost:()=>LocalHostSnapshot、view:PlatformViewPort、scheduler:FrameScheduler、loadResources:()=>Promise、waitForMinimumDisplay:()=>Promise、createSocket:(url:string)=>WebSocket、record:EvidenceSink、onBusy:(busy:boolean)=>void、onFailure:(error:unknown)=>void;所有依赖必需。 -- [ ] 写真实 Runtime+Controller 联合 RED:控制 resources/minimum/socket 三个未完成输入,任何一个未就绪禁止 login;configOptions fetcher 计数为零,配置解析仅一次(从 record/身份解析输入探针确认)。首个 config 解析在 Runtime 构造前完成以提供诊断 gameId,场景 shell 显示此阶段。 -- [ ] 构造一次 local startup Promise,context→entry、sources、wire 工厂。Controller.connect(runtime)→runtime.start();Runtime 选项 resolveRuntimeConfig 返回已解析同一 config。 +- [x] 写真实 Runtime+Controller 联合 RED:控制 resources/minimum/socket 三个未完成输入,任何一个未就绪禁止 login;configOptions fetcher 计数为零,配置解析仅一次(从 record/身份解析输入探针确认)。首个 config 解析在 Runtime 构造前完成以提供诊断 gameId,场景 shell 显示此阶段。 +- [x] 构造一次 local startup Promise,context→entry、sources、wire 工厂。Controller.connect(runtime)→runtime.start();Runtime 选项 resolveRuntimeConfig 返回已解析同一 config。 ```ts const context = await resolveLocalStartup(options.configOptions); const entry = createDiagnosticGameEntry(context.config.identity.gameid, options.record); // createLocalLoginSources uses live closure for active login state. // Runtime creation and Controller.connect occur only once after context validation. ``` -- [ ] login 合并忙碌调用,prepare 成功才 controller.login;响应前保持 busy,onBusy 与 View 的登录遮罩一致。销毁期间异步 prepare/config 完成不能创建连接或发送;通过 generation/terminal 标记拒绝迟到结果,不新增业务状态机。失败先禁用输入再停止各所有者,onFailure 最后呈现错误;stop 保留已经绘制的成功/失败结果。 -- [ ] RED/GREEN:正常 player_login fixture→Store logged-in/outside→lobby model;state非零/kick 原错误;房间恢复无写入 Store;重复点击单 send;缓存损坏无 send;stop during prepare/config/resources 无后续渲染/连接;observer/清理错误保留;invalid query/native 零账号写入与连接。 -- [ ] `node --import tsx --test framework-tests/local-platform-login/host.test.ts`、类型/导入/diff 检查、任务审查提交。此步不真实联网,不实现空资源端口的生产入口。 +- [x] login 合并忙碌调用,prepare 成功才 controller.login;响应前保持 busy,onBusy 与 View 的登录遮罩一致。销毁期间异步 prepare/config 完成不能创建连接或发送;通过 generation/terminal 标记拒绝迟到结果,不新增业务状态机。失败先禁用输入再停止各所有者,onFailure 最后呈现错误;stop 保留已经绘制的成功/失败结果。 +- [x] RED/GREEN:正常 player_login fixture→Store logged-in/outside→lobby model;state非零/kick 原错误;房间恢复无写入 Store;重复点击单 send;缓存损坏无 send;stop during prepare/config/resources 无后续渲染/连接;observer/清理错误保留;invalid query/native 零账号写入与连接。 +- [x] `node --import tsx --test framework-tests/local-platform-login/host.test.ts`、类型/导入/diff 检查、任务审查提交。此步不真实联网,不实现空资源端口的生产入口。 ## Task 4: Cocos View、组件与授权场景 **Files:** Create local-login-view.ts、LocalPlatformLogin.ts;Test framework-tests/local-platform-login/view.test.ts(纯投影/绑定端口行为,可控 cc 模块测试注入只在测试环境);Create spec 第8节九个资源文件,由 MCP/Creator 完成。 **Interfaces:** CocosLocalLoginView implements PlatformViewPort,持有明确 roots/status/result Labels;createCocosFrameScheduler():FrameScheduler。View 提供 bindLogin(instance:Node,onLogin:()=>void)、setBusy(boolean)、showFailure(unknown)、dispose();所有必需节点缺失 throw。组件持有 Loading/Login Prefab、页面 roots、status/result Labels、StopButton 引用。 -- [ ] RED 先覆盖 view 的失败绑定、正确 PageModel→Label 显示、遮罩忙碌/终止、解绑行为;使用可控引擎端口而非在消费代码填默认 Node。必要的测试模块加载器只能位于 framework-tests,不能伪装 cc 生产实现。 -- [ ] 实现触摸绑定 group-2/游客登录;隐藏微信/手机/QQ/快速/隐藏快速入口;版本 Label 取有效 identity.version。加载节点 group-40/载入动画 用 Cocos update/tween 旋转,生命周期清理。不得持久改源 prefab。 -- [ ] 组件 DEBUG 且 sys.isNative=false 限制;500ms 仅一处定义。start 调用宿主,configOptions 使用实际 location.search 与 window,禁止 query 默认;Storage 绑定 localStorage,random/now 用 Math.random/Date.now,sampleHost 显式 location=null 及存在时的 returnCitySN。 -- [ ] loadResources 检查实际序列化 Prefab 与 SpriteFrame 依赖,实例化 Login、绑定节点与事件,等待真实 draw;minimum-display 自 Loading 首个 draw 计时剩余500ms,不能以 setTimeout 代替资源加载。帧回调使用 Cocos director 事件与真实取消。 -- [ ] 编辑器操作前用 MCP 核实固定主工程 projectPath。用户已取消 worktree 切换;在当前联调分支继续,不请求打开已清理的隔离路径,不保存未知场景。 -- [ ] MCP 创建空 LocalPlatformLogin.scene,1600×720 Canvas/Camera/Host/roots/status/result/stop,实例化 Loading Prefab,挂新组件及序列化引用;Login Prefab 由运行实例加载。保存→重新打开→核实组件与引用真实持久,检查九个资源范围,不使用 edit_prefab_json。 -- [ ] Cocos noEmit/诊断需使用实际引擎声明;不能把 cc 文件纳入无引擎 framework tsconfig。记录 engine diagnostics 与纯 TS 各自结果。MCP 预览新的场景,显式 profile=local;手工模拟点击前确认无旧 LoginFlow 活跃。 -- [ ] 任务规格/质量审查覆盖代码及 MCP 绑定证据,再提交授权文件;若工具不能持久化挂载,报告具体阻塞而非手改序列化。 +- [x] RED 先覆盖 view 的失败绑定、正确 PageModel→Label 显示、遮罩忙碌/终止、解绑行为;使用可控引擎端口而非在消费代码填默认 Node。必要的测试模块加载器只能位于 framework-tests,不能伪装 cc 生产实现。 +- [x] 实现触摸绑定 group-2/游客登录;隐藏微信/手机/QQ/快速/隐藏快速入口;版本 Label 取有效 identity.version。加载节点 group-40/载入动画 用 Cocos update/tween 旋转,生命周期清理。不得持久改源 prefab。 +- [x] 组件 DEBUG 且 sys.isNative=false 限制;500ms 仅一处定义。start 调用宿主,configOptions 使用实际 location.search 与 window,禁止 query 默认;Storage 绑定 localStorage,random/now 用 Math.random/Date.now,sampleHost 显式 location=null 及存在时的 returnCitySN。 +- [x] loadResources 检查实际序列化 Prefab 与 SpriteFrame 依赖,实例化 Login、绑定节点与事件,等待真实 draw;minimum-display 自 Loading 首个 draw 计时剩余500ms,不能以 setTimeout 代替资源加载。帧回调使用 Cocos director 事件与真实取消。 +- [x] 编辑器操作前用 MCP 核实固定主工程 projectPath。用户已取消 worktree 切换;在当前联调分支继续,不请求打开已清理的隔离路径,不保存未知场景。 +- [x] MCP 创建空 LocalPlatformLogin.scene,1600×720 Canvas/Camera/Host/roots/status/result/stop,实例化 Loading Prefab,挂新组件及序列化引用;Login Prefab 由运行实例加载。保存→重新打开→核实组件与引用真实持久,检查九个资源范围,不使用 edit_prefab_json。 +- [x] Cocos noEmit/诊断需使用实际引擎声明;不能把 cc 文件纳入无引擎 framework tsconfig。记录 engine diagnostics 与纯 TS 各自结果。MCP 预览新的场景,显式 profile=local;手工模拟点击前确认无旧 LoginFlow 活跃。 +- [x] 任务规格/质量审查覆盖代码及 MCP 绑定证据,再提交授权文件;若工具不能持久化挂载,报告具体阻塞而非手改序列化。 ## Task 5: 真实服务验收与整批回归 **Files:** Create docs/superpowers/reports/2026-09-05-local-platform-login-acceptance.md;Modify 本计划完成记录;失败时修复只能通过同任务 TDD 子代理与审查,且不得越资源授权。 **Interfaces:** 只消费已实现组件、只读证据与 MCP;不新增 RPC 或服务器接口。 -- [ ] 核实本地 gateway 进程与路由对应服务;只读定位版本/身份配置,脱敏记录来源和未证实项。不能依据历史 version=10000/41 改请求。 -- [ ] MCP 预览明确 profile=local,观察 Loading 实际旋转与≥500ms、ready四门、游客可操作;从 Transport 证据确认唯一 WS、本地 URL、握手,点击后唯一 agent/player_login。 -- [ ] 记录成功回包 state=0、Store logged-in/outside、PageModel 与结果页一致。若拒绝/无回包/房间恢复,记录事实并定位来源,不能宣告通过或去测其他 RPC。再独立预览同 origin 验证账号/机器缓存复用与登录成功;停止后无重连/监听。 -- [ ] 执行以下精确回归,所有 exit 非零即停止结果认定: +- [x] 核实本地 gateway 进程与路由对应服务;只读定位版本/身份配置,脱敏记录来源和未证实项。不能依据历史 version=10000/41 改请求。 +- [x] MCP 预览明确 profile=local,观察 Loading 实际旋转与≥500ms、ready四门、游客可操作;从 Transport 证据确认唯一 WS、本地 URL、握手,点击后唯一 agent/player_login。 +- [x] 记录成功回包 state=0、Store logged-in/outside、PageModel 与结果页一致。若拒绝/无回包/房间恢复,记录事实并定位来源,不能宣告通过或去测其他 RPC。再独立预览同 origin 验证账号/机器缓存复用与登录成功;停止后无重连/监听。 +- [x] 执行以下精确回归,所有 exit 非零即停止结果认定: ```powershell $loginTests = @(rg --files framework-tests -g '*.test.ts') if ($loginTests.Count -eq 0) { throw 'No TypeScript tests selected' } @@ -114,10 +114,14 @@ node node_modules/typescript/bin/tsc -p tsconfig.framework.json --noEmit node scripts/check-import-boundaries.mjs git diff --check ``` -- [ ] 审计基线到 HEAD 和所有未提交资源路径,主 checkout原有50项状态与哈希不变;本批真实成功与纯测试成功分开记录。报告仅提交脱敏摘要与必要截图引用,认证密钥和原始账号设备标识不提交。 -- [ ] 任务规格/质量审查、完整分支审查、完成记录;不自动合并或推送。 +- [x] 审计基线到 HEAD 和所有未提交资源路径,主 checkout原有50项状态与哈希不变;本批真实成功与纯测试成功分开记录。报告仅提交脱敏摘要与必要截图引用,认证密钥和原始账号设备标识不提交。 +- [x] 验收记录规格/质量审查与完整代码分支审查已通过;提交完成文档,不自动合并或推送。 ## 计划自审与执行 spec 1–6 对应 Tasks1–3;spec7–9 对应Task4;spec10–11对应Task5。诊断生命周期先创建再释放,不把工厂写成直接throw;最短展示从真实draw开始;View不能直接读原包。代码接口按上文导出,任务之间按依赖串行;测试存根只在测试目录。 用户已指定本会话 subagent-driven-development,无需再次选择执行方式。第8节资源授权已确认;额外资源不得暗中增加。 + +## 本批验收结果(2026-09-05) + +代码完成至4414e1b;两次独立真实预览登录state=0,账号与机器缓存复用,Store/PageModel/画面一致;实际加载旋转及修复后的501.1ms展示、忙碌反馈、停止后47秒无事件均通过。最终纯TS600/600、架构49/49、类型/导入与diff检查通过;原有50项状态/哈希不变。详细证据见../reports/2026-09-05-local-platform-login-acceptance.md。验收记录审查已通过;文档随本次收尾提交,分支保留,未合并或推送。 diff --git a/docs/superpowers/reports/2026-09-05-local-platform-login-acceptance.md b/docs/superpowers/reports/2026-09-05-local-platform-login-acceptance.md new file mode 100644 index 0000000..43d60e0 --- /dev/null +++ b/docs/superpowers/reports/2026-09-05-local-platform-login-acceptance.md @@ -0,0 +1,72 @@ +# 本地启动、加载、登录真实验收 + +日期:2026-09-05。分支:`codex/local-platform-login`。代码:`4414e1b`。状态:本批启动、真实加载和两次独立预览登录验收通过;未合并、未推送。 + +## 工作区与范围 + +仅在 `G:/Works/YouleGamesCocosCreator` 主 checkout 使用 Git 分支;Creator 固定打开其下 `cocoscreator_projects/YouleNexus`(3.8.8)。不再使用 worktree。保留原有 50 项未提交文件的状态和 SHA256;不自动 stash。 + +本批独立 `LocalPlatformLogin` 场景只验证启动、加载、游客登录及结果显示。未改生产启动场景、默认 prod、GameEntry 契约、服务器、远程配置或原生接口;未选择子游戏,未发起其他平台或房间 RPC。 + +序列化新增严格为设计第 8 节授权的九项资源,全部通过 funplay MCP/Creator 生成、绑定、保存和重开验证。源 Login/Loading Prefab 未修改。 + +## 配置与账号单源 + +- `assets/framework/config/profiles.ts`:debug/local 的直接连接目标为 `ws://127.0.0.1:3088`,跳过远程配置。 +- `assets/framework/config/sources/defaults.ts` 的 `BUILD_IDENTITY`:agentid、channelid、gameid、marketid、version 的构建来源。正式字段拼写为 `channelid`。 +- `runtime-config.ts` → `local-startup.ts`:解析真实 `location.search`,必须显式 `profile=local`;宿主只解析一次,将同一配置交给 Runtime、诊断 GameEntry 与本地账号来源。 +- `assets/framework/adapters/local/visitor-account.ts`:按身份/连接作用域读取严格缓存或生成游客;openid 为 `testopenid_<随机数>`,unionid 为 `ylgame<同一随机数>`,同时产生昵称、头像、性别和地区。 +- `assets/framework/adapters/local/login-sources.ts`:同次账号准备提供设备快照,机器标识从独立缓存读取或由时间戳与随机后缀生成;本地 location 显式为 null,其他可选输入遵循来源定义。消费方不补默认值。 +- 既有协议构造器产生唯一 `agent/player_login` 信封;未执行历史 `scripts/login-live.ts`。 + +本次真实请求使用未覆盖的 BUILD 身份,`version=1` 且类型为 number。下述 state=0 回包证明该组合被此次实际本地服务接受;不将源码配置或 TCP 可达单独当作身份匹配证据。 + +## 编辑器和运行环境 + +- 本地监听:3088,PID 20092,`G:/Works/JinXianProjects/gateway/game-gateway.exe`。只读复核,无服务端写入。 +- 场景 UUID:`67e69aac-9982-4e78-a44c-1d9c42f016ae`。1600×720,Host 仅挂新组件;九项组件引用经保存、切回原场景、重新打开验证有效。 +- Creator 返回预览端口 7456。通过 funplay MCP 创建独立 Electron Chromium 浏览器窗口,加载实际 Creator 页面 `http://127.0.0.1:7456/?profile=local`;关闭 Node integration、开启 context isolation/sandbox。未替换引擎或伪造编辑器内的浏览器 query。 +- 输入通过 MCP 向真实预览窗口发送鼠标事件。首次坐标偏移误解未命中节点,证据确认零发送;纠正为 game 面板中心偏移后命中游客按钮。 +- 原始收发仅保留于本地诊断内存。此报告不提交 openid、unionid、machineid、服务器认证/银行字段值或原始回包。 + +## 实际发现并修复的问题 + +1. Creator 的诊断工具默认选择 TypeScript 4.9.5,无法解析已有 TS 5 语法。使用仓库 TypeScript、真实 Cocos 声明及严格 ES2020 参数检查;不修改工程配置或原生桥。 +2. 首次实际预览因既有 SDK 测试辅助模块的运行时 `node:assert` 导入中断。最小 TS 范围扩展:该辅助函数改为必需的调用方断言参数,更新唯一测试调用和 README;所有原断言语义保留,无浏览器 shim。独立审查通过,MCP 刷新脚本后实际场景成功运行。 +3. 初次登录页不可见:新相机仅包含 UI_2D,原 Login Prefab 使用 DEFAULT。仅通过 MCP 修改授权新场景相机为 `UI_2D | DEFAULT`,重开和实际截图均通过;源 Prefab 不改。 +4. 第二个独立预览暴露单次浏览器计时器提前唤醒,记录 499.8ms。通过 RED/GREEN 加入每次唤醒后的单调时间阈值复核,未满 500ms 继续等待;保留取消能力。整分支审查的对应 Important 问题已复审关闭。该失败窗口未登录;修复后另开全新窗口验证为 501.1ms。 + +## 首次真实登录证据 + +- `fp_f5d718fac951802d`:Loading 首次 draw 为 861.3ms;865.9ms 与 1090.7ms 的两张真实截图均显示加载环,角度由 -47.682° 变为 -86.688°。登录页激活为 1368.3ms,实际加载展示约 507ms。 +- 本地唯一 open 目标为 `ws://127.0.0.1:3088`;资源、配置、连接和最短展示门完成后,PageModel 为 login/canLogin=true。 +- `fp_72e7cc8b8f6782a8`:一次游客点击仅发送一个 `agent/player_login`;服务器返回 `state=0`。首次业务响应耗时约 1694ms。后续 26 字节入站为非业务帧,未产生额外出站 RPC。 +- Store 为 logged-in/outside;服务器语义、Store、PageModel 的玩家 ID、昵称、豆豆一致;实际结果页显示登录成功。页面不直接用请求填充玩家结果。 +- 诊断 GameEntry 仅完成一次校验创建/释放,没有游戏 attach、restore 或消息调用。 +- `fp_e481ee99042a594f`:真实停止按钮触发后 ready=false、busy=false、pendingCount=0;观察 33.3419 秒,事件计数未变,无重连、继续渲染或浏览器异常。成功结果保留。 + +## 第二次独立预览与缓存复用 + +- `fp_9b9dc57c94603f6d`:关闭已停止的窗口,新建独立浏览器窗口 9,仍使用同一真实预览 origin 和 `profile=local`。修复后的 minimum-display-ready 为 501.1ms,login/canLogin=true,零浏览器异常。 +- `fp_ed01311f246331d4`:向实际游客按钮发送鼠标事件,35ms 后观测 busy=true、登录遮罩可见、提示“正在登录,请稍候…”,仅一个业务请求;已取得实际截图。 +- `fp_f75c9fb9806e6a5c`:服务器再次 state=0;openid、unionid、machineid 与首次请求均相同,返回相同玩家。Store logged-in/outside,Store、PageModel、回包和显示结果一致。比较在本地诊断内存完成,此处只记录布尔结论。 +- `fp_e58e3f88615487fb`:真实停止按钮后 ready=false、busy=false、pendingCount=0;观察 47.0203 秒无新增事件、重连或浏览器异常。保留成功结果供查看。 + +截图位于工程 `temp/mcp-captures/`(本地证据,不提交):`local-login-loading-first.png`、`local-login-loading-rotated.png`、`local-login-visible-ready.png`、`local-login-success-first.png`、`local-login-busy-second.png`、`local-login-success-second.png`。 + +## 回归与审查 + +在 `cocoscreator_projects` 执行显式枚举全部 `framework-tests/**/*.test.ts` 的 `node --import tsx --test --test-concurrency=1`:最终 600/600,通过,exit 0,对应 `4414e1b`。计时修复前为 599/599,新增早醒回归后为 600。 + +指定 `architecture/import-boundaries.test.mjs` 和 `architecture/presentation-boundaries.test.mjs`:49/49,通过。框架类型、导入边界检查通过。未使用 npm test、test:framework 或旧资源生成器。 + +全量输出含既有 `ui/store-binder.test.ts` 故意触发的 StoreBinder/reactive `boom` 日志;测试未失败,不宣称全量日志无噪声。 + +各实现任务与修复均完成独立规格/质量审查。整分支审查完成至 `73d7826`,计时修复 `4414e1b` 复审通过;没有未关闭的 Critical/Important 代码问题。 + +## 最终范围复核 + +- `4414e1b` 后复核原有 50 项文件的 porcelain 状态和 SHA256,全部不变。两项历史删除 meta 和用户 scene-2d 均保留。 +- 分支资源差异严格为九项授权新增文件。测试辅助模块兼容修复只修改三个既有文本文件,未增加资源授权范围。 +- `git diff --check` 通过。仅主 checkout;没有 worktree,未自动 stash、合并或推送。 +- 本结论仅为本批平台启动、加载、游客登录通过;不代表大厅其他 RPC、房间、真实子游戏、生产 profile 或原生 App 验收。 diff --git a/docs/superpowers/specs/2026-09-05-local-platform-login-design.md b/docs/superpowers/specs/2026-09-05-local-platform-login-design.md index 9b9a796..efff17d 100644 --- a/docs/superpowers/specs/2026-09-05-local-platform-login-design.md +++ b/docs/superpowers/specs/2026-09-05-local-platform-login-design.md @@ -1,7 +1,7 @@ # 本地真实启动、加载与登录联调设计 日期:2026-09-05。代码基线:master@66246c8。 -状态:用户已确认本文及第8节九项资源写入清单(2026-09-05),进入实施;实际验收尚未完成。 +状态:用户已确认本文及第8节九项资源写入清单(2026-09-05);启动、加载和两次真实登录已验收通过,详见 ../reports/2026-09-05-local-platform-login-acceptance.md。下文“已核实的基础”为设计时记录。 ## 1. 本批交付