Commit Graph
14 Commits
Author SHA1 Message Date
joywayerandClaude Opus 5 f8a154ff7a 二七王:result.chupai 移出 GameState,本墩结果改走 EQW_TRICK_END 事件载荷
谁最大、这墩闲家得几分是【一次性表现】(收牌动画、得分飘字),任何 deskinfo 都不下发它,
写进 GameState 就多出一处「只活在前端、服务端不知道」的对局态——出牌中途断线重连即归零,
违反红线「丢弃 this.data、仅凭最近一次服务端快照重画,界面必须一致」。

三处一起改,缺一不可:
- PlayHandler chupai3:删 result.chupai 写入,改随 EQW_TRICK_END 下发 {seat,cards,maxseat?,grade?};
  aset.grade 的累加保留(它有服务端来源 PushCards.grade / chupai3.grade,是镜像量)
- ResultHandler:_apply 的 map 删掉 chupai。收尾墩不发 chupai3、整包换成 jiesuan,
  不改这里则删 EXCLUDE 后必转红。收尾墩改为与 chupai3 走同一对事件、同一份载荷字段
  (补 emit EQW_TRICK_END 并带上 grade),否则最后一墩的得分没有出口
- GameState:删掉 result.chupai 字段本身(声明 + reset),不留永远为 null 的死字段

test_consistency 的 EXCLUDE 随之删到只剩 table.ancard3s 一条,27 checks 仍全绿;
该条改注释标明「当前夹具(65 分坐庄、单局)无法触发,此条未经验证」,不假装它在守什么。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 22:06:41 +08:00
joywayerandClaude Opus 5 8b2cfdaf27 二七王:前端删掉 9 处阶段/控制权推导,一律读服务端包字段
I-3 前端不再持有对局状态机(配合服务端上一提交的下发面补齐):
- 删掉 5 处按 rpc 名硬编码的 aset.step(Deal=1 / Call=2 / Main=3 / Bury=5 / Result=6),
  一律改 _apply 读包里的 step
- 删掉 4 处 turn.seat = aset.banker(CallHandler / MainHandler / ResyncHandler×2),
  增量路径读 nextseat、重连路径读分组里的 seat;同一条规则不再有 4 个写入处

I-2 ResyncHandler._applyBalance 由只接 aset 扩为接 aset/bottom/account,
结算面板开着时重连/硬刷新不再丢抠底明细与末局大结算。
一致性测试 EXCLUDE 随之从 4 条收缩为 2 条(去掉 result.bottom / result.account,
只留一次性事件 table.ancard3s 与归下一轮的 result.chupai),未新增任何豁免条目。

夹具按新包结构重跑(种子不变,牌局不变):diff 纯为 67 行新增字段、0 行删除;
test_fixture 补上 step/nextseat/Balance 同源断言(68→82 checks)。
export_packets.js 里关于 playproc/seatlist 活引用的注释已过时,更正为仍存在的
Balance.readystate 与三份结算快照。

各 handler 单测补齐新字段并新增守卫用例:刻意构造 nextseat != banker、
step 为非预期值的包,使「退回硬编码/banker 反推」的写法必然转红(11/11 已验证)。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 21:31:20 +08:00
joywayerandClaude Opus 5 dac4a94b38 二七王:夹具补甩牌样本,重连恢复 baozhu
导出脚本原来全出单张,单张一手无所谓顺序,服务端两个顺序口径的分岔
在夹具里永远测不出来。改出牌策略(种子不变):首家优先合法甩牌 → 领
最大的一对 → 最小单张;跟家凑合法跟牌;提交时刻意反转成升序,模拟真实
客户端的点击顺序,把「下发顺序是否被请求顺序污染」暴露出来。
中段 step5 快照锚点从 1 个加到 5 个——开局那三张快照的 pushlist 还是空的,
只有打到一半的快照才真的比对到出牌历史。

重导结果:51 手出牌,一手多张 30 手、合法甩牌 4 手,deskinfo 快照 18 张,
仍覆盖 step 1/2/3/5/6;连跑两次逐字节相同。
该样本在修复前使 test_consistency 5 个比对点转红,修复后全绿。

前端 ResyncHandler 补上 PushCards.baozhu 的映射(服务端已补发),
test_resync 加正反两条断言。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 20:12:24 +08:00
joywayerandClaude Opus 5 5689ceab6f 二七王:重新生成夹具、BuryHandler 接住 maipai.playproc,修正甩错断言的错误映射
配合上一个 commit 服务端补发的 maipai.playproc,重新生成真包夹具(diff 只新增
三家 maipai 包各一份 round-1 初值 playproc,无其他变化)后跑一致性测试,暴露出
前端还有一处对应缺口:BuryHandler.js 组 table.playproc 时没有接 data.playproc
(PlayHandler.js 早已对 chupai1/2/3 做了同样的原样拷贝),于是「埋牌完成→庄家
首出」窗口增量路径的 table.playproc 停在上一阶段的 null。现补上,并在
test_handlers_bury.js 新增一条用例守住、用「退回修复必转红」反向验证。

test_handlers_play.js:84 的 `S.table.playproc.shuaicuo` 断言的正是此前 Fix Round 2
裁决②(本手信息收进事件载荷、不进 GameState)判定为缺陷的旧映射,playproc 改为
原样拷贝服务端结构后必然读 null 硬崩。按 task-12d-report.md §8 的裁决与建议替换:
断言改为守事件载荷(EQW_CARD_PLAYED 的 shuaicuo/order/seat/cards/count/flower/
cardtype)+ playproc 原样拷贝,强度不降——原断言只守住"甩错标志被处理"这一件事,
新断言额外多守了"本手信息不得混入 playproc"一条。

client/tests/test_consistency.js 全绿(23 checks,此前 20 绿/3 红);
client/tests/run.js 全绿(20 脚本);server/games/erqiwang/test/run.js 全绿
(17 脚本/675 checks,见上一个 commit)。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 19:48:54 +08:00
joywayerandClaude Opus 5 729128aa9d 二七王:前端 handler 六处下发面漏读/错读修复(增量路径对齐重连路径)
一致性测试(同一局真包:逐包增量回放 vs 一次性 deskinfo 重连)暴露的六处前端缺陷:

① PlayHandler:table.playproc 由「字段映射错误」改为原样拷贝
   原实现把这一手的 seat/cards/count/flower/cardtype 灌进 playproc,而服务端 playproc
   是本轮进行态(round/start/currseat/.../cards),两者几乎无交集、撞名的 cards 语义还相反。
   服务端已在 chupai1/2/3 补发 playproc,前端零推导直接镜像,不自行累积 round/maxseat。

② 本手信息改走 EQW_CARD_PLAYED 事件载荷,不进 GameState
   {order, seat, cards, count?, flower?, cardtype?, shuai?, shuaicuo?},带 ? 的缺字段不兜底。
   落牌是一次性表现而非对局状态;新立 GameState 字段只会再制造一处增量/全量不一致。

③ PlayHandler:table.pushlist 逐手落盘、按轮归档(GameState.pushPlay)
   chupai1 开新的一轮、2/3 落进当前轮,任意时刻都与 deskinfo 的全量重建相等(服务端
   pushlist 含进行中的当前轮)。不读 chupai3.playproc.cards——那是下一轮的进行态(协议 §13)。
   仅可查牌模式累积,与服务端同一道门控,否则不查牌房会凭空攒出重连没有的历史。

④ ResultHandler:归档收尾轮(最后一手走 jiesuan.chupai,不发 chupai3)
   夹具实证 chupai1×28 / chupai2×28 / chupai3×27。jiesuan.chupai 只有 seat/cards/maxseat。
   归档随即被结算收敛清空(deskinfo step6 不带 PushCards),但 emit 同步,落牌表现在清空前取值。

⑤ BuryHandler:接住 maipai 新增的 seatlist(此刻为全初值,界面无差别但重连侧有)

⑥ ResyncHandler 的 ChooseMain/BuryCards 补映射 curmultiple(原重连重建为 0,抓分角标掉档);
   BuryHandler 埋牌完成后清空 my.bottomCards——底牌上庄时已并入手牌,埋牌后只剩 burycards
   有意义,deskinfo 的 PushCards 不下发 bottomcards,重连重建恒为 [](语义已逐条核实)。

一致性测试 8 红 → 3 红。剩余 3 条同源:服务端 maipai 漏发 playproc(与本次服务端补发
seatlist 是同一个窗口、同一个理由),前端无法自补且不得伪造,详见报告 §7 待裁决。
另有 test_handlers_play.js:84 断言的正是 ① 修掉的错误映射,按纪律未改测试,见报告 §8。

未触碰 server/、client/tests/(含夹具与 EXCLUDE);服务端 29 checks 全绿。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 19:41:48 +08:00
joywayerandClaude Opus 5 c4c061b0e1 二七王:修复三处前端漏读(Task 12 一致性测试 Fix Round 1 · 类别 A)
一致性测试发现的 8 处不一致中,分诊出 3 处确属"deskinfo 里有、增量 handler
没读"的前端缺陷,本次修复:

- room.playerScores:reset() 不再清空,改为跨局保留字段;ResultHandler 从
  jiesuan 的 aset.seatlist[i].score(协议 §14「累积得分」)回填,避免一局
  中段(fapai 后至 jiesuan 前)总积分持续为空。
- call.currcall/call.calls:CallHandler.handleShangzhuang(step1→2 转场)
  清回默认值——deskinfo 从 ChooseMain 起就不再带 CallRun,这两个叫分过程量
  该阶段起无意义。
- ResultHandler._applyResult(jiesuan/解散共用)补齐结算清场:把 aset.*/
  turn.*/call.*/table.*/my.bottomCards/buryCards/cards 清回 reset() 默认值,
  与 deskinfo step6 只应用 Balance 分组时的重建结果对齐;顺带清掉出完最后一张
  牌的座位因 jiesuan.chupai 不带 cardsinhand 留下的幽灵手牌。

发现 3(curmultiple)、发现 6(seatlist 窗口期)判给服务端,发现 4/5
(table.playproc/pushlist)待裁决,均未改动。test_consistency.js 由 9
PASS/14 FAIL 转为 14 PASS/9 FAIL,EXCLUDE 白名单未改一字。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 18:57:54 +08:00
joywayerandClaude Opus 5 a5ca3bc5d9 二七王:重连与开局 handler,路由表注册齐全
重连即重画:断线重连与硬刷新复用同一条路径(填 GameState → emit RESYNC_ALL),
不为重连单写一套渲染。deskinfo 按 step 分组填充,重连不重放 70 分开底那类
一次性事件。StartWar 支持差异化下发,按本座位取自己那份。

路由表 12 条注册齐全,test_dispatcher 的完整性断言随之转绿——
漏接一个包就会红。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 18:15:04 +08:00
joywayerandClaude Opus 5 e8fc3a9bfa 二七王:结算与解散 handler
三种结算来源组成不同(正常出牌 / 投降 / 解散),共用一套落地逻辑:
有哪组写哪组,缺的保持 null。

解散走平台的 Game_Modify.Free 入口而非收包分发表——它的 route 是 room,
被平台分流走了。取值路径因此比协议文档少一层,且参数可能为 null
(首局发牌前解散),已覆盖。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 18:09:06 +08:00
joywayerandClaude Opus 5 070ff37db1 二七王:明牌、提示、准备 handler
明牌数据进 GameState(面板可反复开关查看);提示不进——它是一次性通知、
不是对局状态,重连也不重放,存下来只会变成幽灵数据,故只随事件带出。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 18:04:33 +08:00
joywayerandClaude Opus 5 5a77e4b132 二七王:修正出牌 handler 注释并补强 grade 累加与 nextseat 测试
审查发现简报本身两处缺陷:
1. grade 累加测试断言力不足,无法区分"累加"与"仅在字段存在时赋值"两种
   实现——补一条跨包连续收两个 grade 的用例(10 再 15,断言最终 25)钉住
   累加语义。
2. chupai3 实际也带 nextseat(服务端在 switch 前统一设置三个包),简报
   注释误写成"chupai1/2 独有";修正文件头注释,并给 chupai3 测试用例补
   上 nextseat 与对应的 turn.seat 断言,使包结构与真实下发一致。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 17:58:42 +08:00
joywayerandClaude Opus 5 5637d63c3b 二七王:出牌 handler
三个包字段不同:chupai1 带牌型信息、chupai1/2 带 nextseat 与 mustcard,
chupai3 带 maxseat 与本轮得分。

两个易错点已覆盖:cardsinhand 只有出牌者自己有,别人出牌时缺该字段不能抹掉
自己的手牌;mustcard 只对当前轮有效,没给就要清空,否则上一轮的建议会残留。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 17:51:36 +08:00
joywayerandClaude Opus 5 daf2708af9 二七王:选主与埋牌 handler
选主后主牌集合变化、手牌需重排,但重排是渲染时由 core/CardOrder 现算,
不在状态里落地——GameState 只镜像不派生。

埋牌区分 burycards(埋牌底牌)与 bottomcards(底牌),两批不同的牌;
闲家无 cards/burycards 但可能有 liangpai,缺字段一律不抹已有值。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 17:46:01 +08:00
joywayerandClaude Opus 5 081130b020 二七王:发牌与叫分 handler
fapai 是一局起点,先 reset 清上局残留(保留 mySeat 与 options)。
叫分里 0(不叫)与 null(还没叫)严格区分。上庄的 bottomcards/cards 只有庄家有,
缺字段时保持原值、不抹掉闲家已有手牌——GameState 的「缺字段不兜底」在此体现。

新增 GameState._apply 助手:按 {目标键:源键} 映射写入,源键不存在就不写。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 17:41:09 +08:00
joywayerandClaude Opus 5 01eb6c60b5 二七王:收包分发器与失败回包处理
分发器只分发不写业务。判定顺序上先看 data.success,失败包一律先分流给
FailHandler——协议规定失败回包的 rpc 与请求同名(chupai 失败回 chupai,
成功走 chupai1/2/3),不先分流则每个业务 handler 都要自己判一遍。

未知 rpc 只警告不抛错,畸形入参不崩。路由表完整性断言留待全部 handler 就位。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 17:36:15 +08:00