Commit Graph
41 Commits
Author SHA1 Message Date
joywayerandClaude Opus 5 84525359fc 二七王:服务端下发面四处缺陷修复(增量路径与重连路径对齐)
前端一致性测试(同一局真包:逐包增量回放 vs 一次性 deskinfo 重连)暴露的四处
服务端缺陷,均属「同一份数据两条路径给的不一样 / 有一条根本没给」:

① chupai1/2/3 补发 playproc(本轮进行态)
   与 deskinfo.PushCards 共用新增的 get_playproc() 快照函数,结构取值完全一致。
   playproc 是全程复用的活对象(new_playround 就地重置),故快照做逐字段深拷贝,
   避免已发出的包被后续出牌回改。可见性:全部字段由桌面公开信息推出,
   与既有 PushCards.playproc 一样三家无差别下发。

② deskinfo ChooseMain(step2)/BuryCards(step3) 补发 curmultiple
   与 shangzhuang 推送同源同值;此刻一张牌未出、捡分恒 0,必为 +3(大光)。
   原先重连重建为 0,顶部「抓分」角标掉档。

③ maipai 补发 seatlist
   与 chupai/PushCards 同一张表、同一道查牌模式门控;埋牌完成时为初始化空表。

④ bottomcards / burycards 收敛到单一权威源(SSOT)
   - burycards:maipai 原样回显了客户端请求包里 cards 的顺序,改取 get_burycard()
     权威快照,与 PushCards.burycards 同一函数。请求包只承载「意图」,其顺序不可信。
   - bottomcards:get_bottomcards 按「调用时的 flower」排序,导致上庄推送(flower=-1)
     与重连 BuryCards(flower 已定) 两种顺序。底牌是选主【之前】就翻给玩家看的、
     发牌结束即固定的快照,故改为发牌时算一次并冻结,get_bottomcards 返回其副本
     (order_cards 是原地排序,交出本体会被调用方就地重排)。三个调用点无需改动。

协议文档同步 7 处(新增 playproc/seatlist/curmultiple 字段说明与两处排序口径)。
新增 test_rpc.js「下发面一致性」用例组 21 checks,含 28 轮真实牌局逐包逐座位比对
(249 次、0 不一致)与深拷贝守卫;每条均已用「退回修复必转红」反向验证。
既有 649 checks 未改一条断言,全绿(17 脚本 / 670 checks)。未涉及 shared/。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 19:17:09 +08:00
joywayerandClaude Opus 5 f04bff4e9f 二七王:S-8 curmultiple 改为带符号
问题:S-1 实现时取了绝对值,而判定的正负号恰恰是「谁赢」的区分——
3 大光 vs -3 升3级、2 小光 vs -2 升2级、1 过庄 vs -1 升1级,取绝对值后
三对完全撞在一起,D-8 的过程中判定动画无从分辨该播哪个。

改法:get_curmultiple 直接返回 get_upgrade 原值,与结算包 aset.upgrade
完全同口径(3/2/1 庄家大光/小光/过庄,-N 闲家升N级,0 叫分未定)。
顶部「抓分」角标只关心大小,取 Math.abs 即可;判定动画靠符号分辨,
前端一套映射通吃「过程中」与「结算前」两条路径。

协议 4 处 curmultiple 说明同步(shangzhuang / chupai1 / chupai2·3 /
PushCards)。

测试(hint 33 → 46 checks):
- 钉住三对「绝对值相同、判定相反」的组合可区分,以及符号语义
  (>0 庄赢 / <0 闲赢 / ==0 叫分未定)。
- 新增一组【直接调 get_curmultiple 本身】覆盖负数分支,含爬坡 Q 分段。

补上一个测试盲点:第一次反向验证(把实现退回取绝对值)竟然全绿——因为
原有断言里算法层的 cm() 走的是 A.get_upgrade、绕过了 get_curmultiple,
而端到端那局恰好是大光(正数),取不取绝对值都一样。补齐直接调用的用例后
再验,4 条断言立刻失败。

至此 §7.5 服务端待补 8 条全部完成,服务端侧无遗留;D-8 只差动画设计稿
与触发细节。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 12:42:29 +08:00
joywayerandClaude Opus 5 796503153d 二七王:S-7 明牌条件按手册定案,服务端无需改动
结论:按 design §9.3——任一玩家报无主后,三家都显示「明牌」按钮,
且整个出牌阶段随时可查、不限次数。判定依据是「场上有人报无主」而非
「自己报无主」,报无主那位和另外两位一样能看。

此前我把前端条件收紧成「自己是无主玩家」,比手册严格,反而与服务端
have_baofu() 的受理条件对不上。现改回:

- 前端清单 §1.7 D-6、§2.6 底栏按钮、§0.0 对照表、baozhu 字段说明统一为
  「可查牌 + 出牌阶段 + baozhu==1 → 三家都显示」。
- design §9.3 第 3 条补一句消歧:明确「为这三个人都出现」、判定依据是
  场上有人报无主、且不限次数随时可查。原文靠「同时」承接上一条的
  「为全体三人」,容易读漏。
- protocol 的术语表与 mingpai 受理条件说明同步加注。

服务端与协议本来就是手册口径,无代码改动。此前记的「有主牌玩家伪造请求
也能拿到明牌数据」这一泄露担忧不成立——按手册他本就有权查看,服务端受理
是正确行为。

验收清单增至 18 条,新增一条专门钉住「三家都显示,不是只给自己无主那家」。
至此 §7.5 服务端待补项 7 条全部处理完毕,服务端侧无遗留。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 08:03:08 +08:00
joywayerandClaude Opus 5 76e82405e1 二七王:S-6 大局结算按 基础分/冲关分/傍王分 三项分解
问题:大局结算面板要分项显示,而 account 只有「累积得分 + 每局得分数组」。
傍王分尤其拆不出来——N = 冲关奖数 + 傍王王数,两个来源【求和之后】才代入
grade_aw = X×(2Ni−Nj−Nk),事后无法反推各自占比。

解法:在算钱时就拆。把 N 分成 N_冲关(只计庄家)与 N_傍王(勾选后庄闲都算),
分别代入同一公式各算一次。公式对 N 线性,故恒有
  grade_cg + grade_bw == grade_aw
这条恒等式正好当回归断言用。

服务端:
- class.paiju.js 抽出 award_pay(n) 复用同一公式,新增 grade_cg / grade_bw;
  desk.seatlist 追加三个累计位(基础/冲关/傍王)。
- class.desk.js seatlist 初始化为 5 元素;account 下发改为【对象数组】
  { score, grades, grade_jf_total, grade_cg_total, grade_bw_total }。
  原二元数组下标语义不清,且前端未开工,此时改代价最小(同 S-4 的判断)。

协议:aset.seatlist 增补 grade_cg / grade_bw;account 结构与恒等式
  grade_jf_total + grade_cg_total + grade_bw_total == score 写明;
  并记录这次结构变更的时间与理由。

测试(endgame 26 → 39 checks):
- 核心不变量:两分量之和 == grade_aw;两分量各自零和。
- 未勾傍王局:grade_bw 恒 0、grade_cg == grade_aw。
- 【新增一整局开傍王的端到端】:不开傍王时 grade_bw 恒 0,只验到平凡情形,
  必须有傍王局才算真验证了拆分。该局逐项复核两个分量的公式、naward 口径,
  并钉住「王数不全相等时 grade_bw 必有非零」防止又退化成平凡。
- 大局累计恒等式:基础+冲关+傍王 == 累积总分。

反向验证:把 _awbw 置零 → 4 条断言失败;把冲关分量误算到闲家头上 →
2 条断言失败。均已还原、全量 17 文件全绿。

另修四处测试桩:_rpc.js / test_paiju / test_rpc / test_success 里手工构造的
o_desk.seatlist 仍是 2 元素,未跟上 class.desk.js 的结构变更(脚本缺陷,
非业务缺陷)。

顺带解决小局结算「冲关分」标签的不严谨:改取 grade_cg 而非 grade_aw,
开傍王时不再把傍王贡献算进来。

遗留 T-31:参考图「基础分」与「总得分」两行数值相同且与右侧大字对不上
(30/30 vs +135),mock 不自洽。当前按 基础分=grade_jf_total、总分=score
提供。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 00:34:46 +08:00
joywayerandClaude Opus 5 50e6fd3ca4 二七王:庄家算奖统一口径为「冲关」
design §8.1 的「常规算奖」全面改称「冲关」,与服务端既有字段 chongguan、
界面「冲关分」「冲关牌型」对齐。理清三层关系并写进三份文档的术语表:

  冲关 = §8.1,只计庄家(旧称常规算奖)
  傍王 = §8.3,可选,庄闲都算
  算奖 = 上位概念 = 冲关 + 傍王 → naward(总奖数)、grade_aw(算奖得分)

「算奖」作为上位概念保留——naward / grade_aw / §8.4 的结算模型都建立在
合并概念之上,去掉它这些字段无从命名。故未做无差别替换,而是逐处甄别:
指 §8.1 的改冲关,指合计的留算奖。

design:17 处「常规算奖」→「冲关」,另修正 §7.0 第 4 层一处笔误
(「8.2 傍王」应为「8.3 傍王」,§8.2 是亮牌);§8.1 开头加改名说明。
protocol:新增 §0.0c 算奖层级表;chongguan / naward / grade_aw 注释同步。
前端清单:界面文案与精灵键名统一(算奖牌型→冲关牌型、BTN_AWARD_CARDS→
BTN_CG_CARDS、AWARD_*→CG_* 等),§0.0 补层级表。

据更新后的 小局结算.png:「算奖分」→「冲关分」、「算奖牌型」→「冲关牌型」。
参考图 算奖牌型显示.png 已随之更名为 冲关牌型显示.png,文档 6 处引用同步;
已逐一核对 16 张图的文件名在文档中都能对上。

顺带记录一处标签不严谨:小局结算的「冲关分」取的是 grade_aw,而后者是按
合计后的 N 算出来的。没开傍王时两者相等;开了傍王时该数含傍王贡献,叫
「冲关分」偏窄。根因与 S-6 同源(两分量算钱前已合并、事后拆不开),待
S-6 落地后此标签才名副其实。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 00:25:11 +08:00
joywayerandClaude Opus 5 b98f58effc 二七王:亮牌改为下发庄家全部固定主牌的具体牌面
规则变更(design §8.2):原先「只亮数量/结构,不亮具体是哪几张牌」,现改为
向两个闲家亮出【庄家手中全部固定主牌的具体牌面】。

- 固定主牌 = 双王 + 全部花色的 2 + 全部花色的 7,【不含】主花色普通牌
  A/K/Q/J/10/9/8/6/5。注意这与旧实现收集的「所有主牌」范围不同。
- 门槛不变(固定主牌总数 ≥10 / 王 ≥3 / 7 ≥6 / 2 ≥6,任一满足)。
- 不限叫分;仅可查牌模式下发;亮出的是固定的一份,不随被哪条门槛触发而增减。
- 协议 liangpai 由 {zhu,zhupair,zhutuo,wang,qi,er} 数量结构改为 {cards:[牌id...]},
  数量交由前端从 cards 自行计算。

服务端 get_liangpai() 重写(class.paiju.js);design §8.2 整节重写,术语表、
易混对照表、§9 相应更新;协议 §0.0b 与 maipai / PushCards 两处字段说明同步。

测试:
- test_paiju 亮牌用例按新规则重写(54 checks)。新增两条针对性用例:
  「只含固定主牌·主花色普通牌未混入」与「同时满足多档仍只亮同一份」——
  前者正是这次范围变更最容易写错的地方。
- test_leak 增加亮牌可见性规则。关键点:期望集合【独立于 get_liangpai 重算】,
  而不是复用被测实现——否则实现若误塞非固定主牌,审计会跟着放行、抓不住。
  反向验证证实了这一点:故意让 get_liangpai 混入主花色普通牌后,审计确实报警。

发现并修复一处假绿:原 6 局随机牌序下庄家一次都没达到亮牌门槛,即
「下发面无越权泄露」对亮牌这条路径根本没走到。现追加换牌序的 4 局(保留
原 6 局覆盖不动),并加两条覆盖断言钉住「可查牌达标 ≥1 局」「不查牌达标
≥1 局」,防止以后再退化成碰巧没触发。反向验证:去掉不查牌门控后审计立即
报出 5 张越权牌。

待定:T-34 亮牌的展示时机(出牌前一次性弹出 / 随时可查)。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-25 23:46:06 +08:00
joywayerandClaude Opus 5 dc9123da92 二七王:确立「摸底 / 开底 / 查底牌」术语,弃用有歧义的「底牌公示」
弃用原因:中文「底牌」既指发牌留桌那 8 张牌,也指"底细/实力"。我上一轮
造的「底牌公示」会被读成"公示庄家牌力",而那其实是 design §8.2 的「亮牌」
——两边撞车。改用「底」字族,与已有的「扣底」成套:

| 术语 | 含义 | 谁看得到 |
| 摸底 | 庄家坐定后把 8 张底牌摸起查看并入手牌 | 仅庄家 |
| 开底 | 70 分坐庄,摸底【之前】向全场翻开 3 秒 | 全场 |
| 查底牌 | 对局中随时回看这 8 张(前端底栏按钮) | 庄家全程;闲家仅开底过的局 |
| 扣底 | 末轮闲家用主牌赢下,翻开埋牌底牌计分(原有) | —— |

三份文档同步:design 术语表新增三条并更新易混对照、§4/§12.1/§12.3 正文
改用新词;protocol §0.0b 与 ancard3s 字段说明同步;前端清单 §0.0 补「底」
字族对照表,§1.4、§2.6 相应改写。

口诀相应更新为:「亮牌」「余主公示」是统计类,「明牌」「开底」是牌面类。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-25 23:34:18 +08:00
joywayerandClaude Opus 5 6ec6bdbbc2 二七王:确立「余主公示」「底牌公示」术语,核查「亮牌」冲突
术语决策:
- A 庄家手牌达门槛后公开数量/结构 → 仍叫「亮牌」(保持不变)
- B 有人报无主后展示各家剩余主牌数与对数 → 新术语「余主公示」
- C 70 分坐庄摸底牌前向全场亮 8 张底牌 3 秒 → 新术语「底牌公示」
- 「亮主」确认为选主界面的标题文案、不是规则术语,三份文档均注明不得
  用它指代任何规则

「亮牌」冲突核查结论:无同名不同义,但有三处字面相近而语义方向相反的
读错风险——亮牌 vs 明牌(一个给数量、一个给牌面,方向还相反)、亮牌 vs
亮主(只差一字且同在庄家阶段)、亮牌 vs「亮出底牌」。故在 design 术语表、
协议 §0.0b、前端清单 §0.0 各加一张四类「公开信息」对照表,一句话口诀:
「亮牌」「余主公示」只给数字,「明牌」「底牌公示」才给牌面。

design.md:术语表新增 亮牌 / 余主公示 / 明牌 / 底牌公示 四条定义 +
易混对照表;§4、§9、§12.1 正文启用新术语。
packet_protocol.md:新增 §0.0b 术语小节;seatlist 第 5 位、ancard3s、
baozhu 三处字段说明冠以对应术语。
前端清单:§0.0 补对照表,§2.5 改名为「自己的主牌统计 + 余主公示」。

另据新图 等待庄家选主.png 抽出一个通用部件「状态提示条」(§2.8):
深色半透条 + 居中白字,等待类(等待庄家选主…)与即时反馈类(强甩失败)
共用同一套精灵,只切位置预设与文案。原单列的 BAR_SHUAICUO 并入该部件。

新增 T-32(该图底牌仍摊着与 design §4 的先后顺序对不上,需确认)、
T-33(等待类文案清单待定)。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-25 23:04:03 +08:00
joywayerandClaude Opus 5 4aab71e6a3 二七王:实现 S-1 curmultiple 与 S-2 mustcard
S-1 当前抓分倍数(design §7.2.0):
- class.paiju.js 新增 get_curmultiple(),复用 get_qvalue + get_upgrade,
  与结算 aset.upgrade 同源同算法,差别仅在不含扣底(末轮才产生)。
- 随现有包下发、不另开推送:shangzhuang / chupai1-3 / deskinfo.PushCards。
- 三家同值,整表下发不涉及泄露(捡分本就公开);叫分未定时为 0。

S-2 跟牌必出牌(design §5.2):
- class.paiju.js 新增 get_mustcard(seat),内部复用与出牌校验完全相同的
  get_followcard,故建议与校验天然一致。
- 【只发给 nextseat 一家】:它是该玩家自己手牌的子集,整表下发会泄露
  他家手牌结构(server 红线:发全 ≠ 发多)。
- 四种情形不下发:非出牌阶段、该座位是本轮首家、首家甩牌、必出牌为空。
  甩牌一条尤其重要——甩牌跟牌走 flush_follow_ok 的逐分量匹配,与
  get_followcard 不是同一条路径,给建议会给错。

测试(新增 test/test_hint.js,33 checks):
- curmultiple:算法层逐档对齐 design §7.2.0 判定表(含爬坡 Q 分段)、
  三家同值、重连与出牌包一致、叫分未定为 0、与 get_upgrade 绝对值一致。
- mustcard:只有 nextseat 收到、另两家没有、内容确属收包者自己的牌、
  首家无、缺门有富余时无、手牌数恰等于首家张数时整手必出、甩牌不发、
  非出牌阶段不发、重连按 currseat 门控。

过程中修正的两个测试自身问题(均为脚本缺陷,非业务缺陷,业务判定经证据核实正确):
- 「缺门方无必出」原用例给闲2 只发 2 张牌,恰等于首家张数,get_followcard
  正确判定为「整手必出」;改为发 4 张才留出选择余地,并补一条对照用例
  锁住「恰等于张数则整手必出」这个正确行为。
- 「甩牌不发」「非出牌阶段不发」两条原本是假通过——桩的 startcount 仍是 -1,
  前置守卫先返回了 null,根本没测到被测因素。改为先把桩推进到跟牌态、
  每个用例只变动一个因素,并加一条「自证」用例确认推进后确实能算出必出牌。

另:mustcard 补进 test_leak.js 的 CARD_FIELDS 审计白名单(与 burycards 同理,
不加则误发不会被泄露审计发现)。反向验证:改成整表下发后,审计立刻报出
5 张越权牌;把 curmultiple 写死为 1 后,两条断言失败。均已还原、全绿。

协议文档同步 shangzhuang / chupai1-3 / PushCards 的字段说明。
至此 §7.5 服务端待补 5 条全部完成,服务端侧无遗留。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-25 20:25:32 +08:00
joywayerandClaude Opus 5 ecec44e93a 二七王:S-4 拆分 bottomcards 字段名,S-5 术语同步收口
S-4(服务端改动):底牌与埋牌底牌不再共用一个字段名。
- bottomcards = 底牌(发牌留桌 8 张)—— shangzhuang / ChooseMain / BuryCards,保持不变
- burycards   = 埋牌底牌(庄家埋下 8 张)—— maipai(mod.js)、PushCards(class.export.js)
- 结算 bottom.cards 未改名(分组名已表明是抠底相关),文档注明其语义

测试:
- test_leak.js 的 CARD_FIELDS 白名单加入 burycards。这一步是必须的——不加的话
  新字段会静默脱离下发面审计,闲家误收也发现不了。
- test_rpc.js 新增 11 条正反用例:庄家有 burycards 且为 8 张、庄家不再有
  bottomcards(抓改名漏改)、闲家两个字段皆无、重连 PushCards 同上。

验证(不止「跑过了」):
- 改动前基线 16 个文件全绿;改动后仍全绿,新增后 rpc 从 89 → 100 checks。
- 反向验证一:把 mod.js 的 burycards 改回 bottomcards → test_rpc 新用例 FAIL,
  且 test_leak 报出真实泄露(赋值改了而 delete 没改时,闲家会收到庄家埋的牌)。
- 反向验证二:删掉闲家侧的 delete msg.data.burycards → test_leak 立刻抓出
  5 张越权牌,确认 burycards 确已纳入审计白名单。
两次验证后均已还原并复跑全绿。

S-5:术语同步收口。design.md / packet_protocol.md / 代码注释均已改用
「底牌 / 埋牌底牌」;compliance 三份历史核对记录有意不改(反映当时的 design
表述,下轮核对按新 design 重做)。

另:T-9 亮牌条文案暂定「x对 x主」(取 liangpai.zhupair 与 zhu,其余档位
先不渲染、协议不变)。至此 29 项待确认规格全部有结论。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-25 18:07:17 +08:00
joywayerandClaude Opus 5 82cfc98502 二七王:design 与协议文档统一「底牌 / 埋牌底牌」术语
原命名与前端界面倒挂——界面上「底牌」按钮查看的正是发牌留桌那 8 张,
旧术语却把它叫「暗牌」,极易写反。现统一为:

- 底牌     = 发牌时没有发给玩家、扣在桌面的 8 张(原「暗牌」)
- 埋牌底牌 = 庄家埋牌时从手里扣下的 8 张(原「底牌」)

design.md:全文 38 处表述替换(术语表、§4 坐庄流程、§6.3 扣底、§7.1
70 分说明、§8 算奖快照、§12.1 流程、§12.3 阶段速览),并在术语表后补
「术语变更记录」说明改名缘由与协议字段尚未拆分的现状。

packet_protocol.md:新增 §0.0 术语小节置于全文之首,逐条列出
bottomcards 在哪些包里指底牌、哪些包里指埋牌底牌;相关字段说明同步改用
新术语,并在 maipai / PushCards 两处加同名不同义的警示。

字段名本身暂未改动(底牌保持 bottomcards、埋牌底牌拟改 burycards),
拆分计划见前端清单 §7.5 S-4;在拆分落地前收发两侧按包判断语义。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-25 17:58:18 +08:00
joywayerandClaude Opus 5 df4eefc9e2 二七王:design §4.6 修正笔误「最0号座位」→「0 号座位」,补第一局取固定座位的缘由
规则方确认轮庄规则本身无误(开局先叫分者为暂定庄家;第一局暂定庄家为座位 0;
之后庄赢原庄、庄输下家),与 §4.2/§4.6 及代码一致,无需改动逻辑。

仅修一处笔误并补上缘由:第一局此前没有打过任何牌局、不存在「上一局的庄家」,
所以取固定座位 0。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 15:13:39 +08:00
joywayerandClaude Opus 5 b924b6e864 二七王:第八轮核对(流程/牌型/玩法/算分)+ 新增阶段机迁移矩阵用例
规则方复述「开局庄家先叫分、不允许不叫分;第一局无庄家时默认座位0开始叫分」,
据此按四个维度重新取证,未发现不一致。

新增此前从未做过的取证:**阶段机迁移矩阵**。前几轮每个 handler 只测了 1~2 条
代表性失败路径,从没系统验证过「某个请求在别的阶段会不会被误放行、会不会静默
丢弃」。本轮把 8 个 RPC × 5 个阶段做成 40 格矩阵逐格驱动,全部符合:每个 RPC
只在应允阶段受理,其余一律回 STEP 失败包,无静默丢弃。

叫分起始者规则逐条取证,与规则方复述一致:
- 第一局 firstseat=0、待叫者=0
- 之后每局起始 = 暂定庄家:连打 6 局逐局比对「上局 banker + result」
- 庄赢连庄:随机对局几乎打不出 result=0,用「叫70分 + 首家出最大牌」专门构造
- 庄输/投降顺延下家
- 首家不允许「不叫」:第一局与其后每局(含连庄局)发 call=0 一律回 RULE,
  且叫分过程不变、仍轮到他自己

固化为 test/test_flow.js(7 项聚合断言,0.3s)。断言里带 cells===40,防止驱动
失败导致整行「跳过」而假绿。变异检验:去掉 chupai/maipai 的阶段校验、把 jiaofen
的阶段校验改成静默丢弃 —— 三条全部转红。

全套单测 540 → 547 项全绿。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 14:59:46 +08:00
joywayerandClaude Opus 5 31011e2eeb 二七王:改写 design §5.3(拖拉机相邻关系),消除自相矛盾表述
规则复核时提出「主牌链上位置相邻的对子即成拖拉机、不限花色」,据此发现 §5.3
首句「**同一花色内**点数相邻的两个对子构成拖拉机」与本节紧接着给出的跨花色
主牌链(正7-副7-正2-副2-主A…)自相矛盾。代码实现的一直是那条链(跨花色),
首句表述是错的。

§5.3 拆成两段重写:
- 副牌拖拉机:**必须同一花色**,链 A-K-Q-J-10-9-8-6-5(7、2 是固定主牌不入链,
  故 6 与 8 相连;3、4 不在牌堆,5 是最小档);跨花色不构成连对。
- 主牌拖拉机:只有一条完整序列,**位置相邻即成拖拉机、不限花色**——正7对+副7对、
  副7对+正2对、副2对+主A对、大王对+小王对都是合法两连对。
- 补充「同一档位的两个对子不相邻」:副7 在序列里只占一个位置,♥7对+♣7对 是两个
  平级对子而非拖拉机,副2 同理。

§1 术语表给「正2/正7」加上口语别名「主2/主7」,避免复核时来回换词。

代码无需改动(实测 14 段链全通、跨花色通、同档位不通,与改写后的表述一致)。

补 17 条用例把改写后的每条钉在**拖拉机层**——此前只测到 is_continuous(两张牌
相不相邻),没测过「这几个对子能不能真的组成拖拉机」。变异检验:主牌链改成必须
同花色 / 同档位副7对算相邻 / 副牌 8-6 去掉同花色约束,分别转红 6、2、4 条。

另:复核给出的副牌链写作「…-6-5-3」,需要牌堆保留 3;但 92 = 28×3 + 8 只有在
3、4 都剔除时才成立(保留 3 则 92÷3 除不尽、三家发不平)。经确认为笔误,维持
design §2 现状,并就地补两条断言钉住「参与发牌的牌里 3 和 4 各 0 张、共 92 张」。

全套单测 523 → 540 项全绿。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 14:41:41 +08:00
joywayerandClaude Opus 5 b5d9eece5d 二七王:第七轮核对(反方向 代码→design)+ 新增下发面泄露审计
前六轮都是「design → 代码」方向。本轮反过来:从代码出发,把每个规则决策与
常量拉出来追问 design 有无明文依据。没有发现与 design 冲突的行为,但列出 6 项
「design 未明文规定、由代码自行决定」的项(倒计时秒数、§5.4.4 降级阶梯是否
最长优先、甩牌分解的最大化合并约定、同级副7对不成连对、call 入参宽松而 cards
严格、get_chongguan 的 <28 隐式兜底),已写进 compliance 待规则设计者拍板。

同时补上一块此前完全没有测试的红线:**下发面按可见性下发**。design §4 暗牌
只有庄家可见、§9 查牌模式、§11 结束亮底牌,以及 server 红线「发全 ≠ 发多」,
此前各处门控只有逐条手工核对,从未系统验证「有没有哪个包把不该看的牌送到了
某个座位」。

新增 test/test_leak.js:跑 6 局(可查牌/不查牌 × 叫 65/70/5),对每一个
「服务器 → 某座位」的下发面(各 RPC 逐座位包 + 各阶段重连快照 + 明牌应答)
深度扫描出所有牌 id,逐个判定该座位此刻是否有权知道。结果 1814 个下发面 /
18706 次可见性判定,0 泄露。

变异检验:非 70 分把暗牌发给闲家(第三轮修过的历史缺陷)、重连把底牌发给
闲家、出牌包把剩余手牌发给所有人 —— 三条全部被抓住。

全套单测 520 → 523 项全绿。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 14:29:12 +08:00
joywayerandClaude Opus 5 9d0675fce8 二七王:第六轮核对(多局大局 + 整局带牌型模糊),未发现不一致
前五轮的端到端都只跑单局、且只出单张。本轮补两个从未被驱动过的维度:

一、多局大局(design §12.1 步骤10 / §12.2 / §4.6)
真实驱动 6 局与 12 局:跨局轮庄与「上局 banker+result」严格对应,另单独造出
result=0 的庄赢局验证连庄端到端(此前只有 do_prepare 的桩单测);每局零和、
累计分与逐局累加一致;account 只在末局出现,打满后再准备被拒;房卡只扣一次;
战绩载荷完整;中途解散按当前累计分结算、result=3。全部相符。

二、整局带牌型模糊(新增 test/test_fuzz.js)
test_endgame 的驱动器只会出单张,对子/拖拉机/甩牌/甩错在整局链路里从未跑过。
新测试用带牌型的对局补上,并对每一墩用独立参考实现重算「谁最大」与服务端
比对(不是抽查),另独立重算捡分、扣底倍数、算奖与捡分子数分配。探针阶段
跑了 160 局约 3800 墩(4 个种子)0 异常,入库版固定为 20 局约 480 墩、0.3s。

变异检验:牌的归属写给非胜者、单张毙牌不再压过副牌、算奖分配去掉 ×X、
跟牌牌面值改回未排序入参 —— 四条全部转红。

过程中修正了测试自身的三个问题(已写进 test/README 与 compliance):
- 参考实现的 rank 取了负数,而 0 是「不参与本墩」的哨兵,哨兵反而数值最大;
- 闲家捡分按 playowner 累加再与 aset.grade 比,是拿被测字段自证,playowner
  写错时两边一起错照样通过 —— 改成按独立算出的墩胜者累计;
- 扣底倍数再调 get_bottom_multiple 去比,同样是自证,倍数表改成恒返回 2 也
  通过 —— 改成按 design §6.3 独立重算。
另:该文件的覆盖下限是发牌相关的,随机发牌下扣底可能一次都不出现(实测 60
次里有 1 次),故把发牌也接到固定种子上;随机发牌的整局覆盖由 test_endgame
承担。

全套单测 511 → 519 项全绿,总耗时 < 1.7s。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 13:58:02 +08:00
joywayerandClaude Opus 5 a4361a802d 二七王:补 9 处 design 规则的正/反/边界用例(均通过变异检验)
对 design §1~§12 重做「每条规则是否三类用例齐全」的审计。此前的覆盖矩阵按
「被测函数」组织,容易漏掉跨函数才体现的规则,本轮补齐 9 处:

- G1/G2 §4.2 叫分:下限5与非首家不叫接受,负数/缺call/步进外/同分拒;
  「不叫即退出本局叫分」——反悔再叫被 SEAT 拒、callproc 不变、仍轮到下一家
- G3 §4.5 埋牌:非庄家 SEAT、step2/step5 STEP、7张/9张/空数组 PARAM
- G4 §5.1 每轮由上一轮牌面最大的一方先出(闲1赢/闲2赢两种)
- G5 §6.2 闲家赢计入台面全部分牌(含庄家自己打出的)、庄家赢作废、
  两个闲家谁赢结果一致
- G6 §8 算奖快照:庄家埋后28(已埋不在内)、闲家28、投降36、打出后不缩水
- G7 §3 对子只认同花色同点数两副:跨花色副7/副2、正副7、大小王均不成对
- G8 §6.3 赢末轮的牌不全是主牌就不扣底(副牌拖拉机/混合出牌/顺序颠倒)
- G9 §11 无超时托管守卫:对局阶段 min_ontimeout 调用次数必须为 0,
  将来有人加超时代打就会转红

每条都在副本上注入违反该规则的改动确认转红(7 组变异全部被抓住)。

顺带修一个测试自身的问题:mkBury 桩缺 do_burycard,导致「埋牌张数校验被
改松」这类变异表现为整个文件崩溃而非某条断言转红,后续断言全不执行。桩已
补完整到能走完成功路径。

全套单测 462 → 511 项全绿。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 13:36:09 +08:00
joywayerandClaude Opus 5 1b76683704 二七王:固化两组 design 差分测试(§7 全量对拍 + §5.2 穷举差分)
把第五轮复验用的取证探针固化入库。两者都不枚举「我想到的场景」,而是把
design 的规则整条转写成参考实现再与代码大面积对拍,专治手写用例覆盖不到
的欠约束分支:

- test_calc.js:§7 算子全量对拍。参考实现逐字转写自 §7.1/§7.2/§7.3 判定表,
  比对 2 种算子模式 × 14 个叫分档 × grade 0~260 共 7308 格(每格比
  base/Q/判定倍率/最终子数),另按 design 的 17 张表逐格抽查 141 个写死的
  最终子数。断言按档位分组,失败可直接定位。
- test_followdiff.js:§5.2 跟牌强制层级穷举差分。对每手牌枚举全部 C 张出牌
  组合,逐个比对参考裁定与 can_followcard,约 11 万组。

两组均通过变异检验:关掉 follow_tractor_cover_ok → followdiff 三种拖拉机
首出全红;大光倍率 3→4 / 常规55档 base 4→5 / 爬坡40·35档 Q 20→40 → calc
精确指出档位与 grade。

过程中的教训已写进 test/README 与 compliance:差分测试的强度取决于造牌器。
第一版纯随机抽牌跑 7.8 万组全绿,但关掉覆盖度校验依然全绿——「同花色三组
互不相邻的两连对」这种唯一能区分「只出零散对子」与「先凑最长拖拉机」的
12 张结构随机抽不出来;掺牌又一度把它撑过枚举上限被静默跳过。故随机源改用
固定种子 PRNG,关键结构用确定性 structHands() 钉死。

全套单测 401 → 462 项全绿,总耗时 < 1.5s。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 12:56:30 +08:00
joywayerandClaude Opus 5 e8a7b245cc 二七王:记录第五轮·复验(design 维度的穷举/差分取证,未发现不一致)
不再逐条读代码,改为按 design.md 原文另写参考实现再与代码穷举对拍:

- §7 算子:两种算子模式 × 14 个叫分档 × grade 0~260 全量对拍 14672 格
  失配 0,另抽查 design 表格里写死的最终子数 113 格失配 0
- §5.2 跟牌强制层级:按原文写参考裁定,4000 手牌枚举全部出牌组合,
  86474 组失配 0
- §5.4 甩牌最大性:按 §5.4.2 原文写参考判定,6000 例失配 0
- §2/§3/§5.3/§6/§8/§4/§9/§10/§11 逐条取证,全部符合

两次「疑似失配」经查都是探针写错(甩错最小张那一档有两副牌、闲家赢轮的
台面分含庄家自己打出的分牌),代码是对的,已在台账注明避免后续重提。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 12:45:33 +08:00
joywayerandClaude Opus 5 2fd5829551 二七王:协议文档修正解散结算的真实投递方式,补 roomtype 位串表
以 packet_protocol.md 本身为核对对象(前四轮只在改代码时顺手同步、从未反向
验证「文档写的 = 客户端实际会收到的」),查出两处:

- §14 把解散结算写成 route=erqiwang / rpc=jiesuan 的独立包,实际平台是把
  get_disbandRoom 的返回值整个塞进房间路由的 route=room / rpc=free_room 包,
  即 data.deskfree = { rpc:"jiesuan", data:{...} },比文档多一层 data 包装,
  真实取值路径是 data.deskfree.data.aset;前端照原文档写会取空。新增 §14.1
  给出真实包结构、取值要点、两层 success 的归属与 deskfree 可能缺失的情形。
- 文档多处引用「roomtype 位2/位3」,却从未给出位串定义(只存在于 compliance
  文档里),前端无法据协议拼建房串。新增 §0.5 位表 + 缺省示例 + 兜底规则 +
  局数/扣卡 4 组合对照,并指明 class.config.js parse() 为唯一解析入口。

compliance 记第五轮核对:design 维度逐条复核未发现新的不一致;新发现 4 项
(F1 跟牌入参顺序、F2/F3 协议文档、F4 解散空守卫)已全部处置,并留痕本轮
确认无误、勿再重提的三点观察。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-23 12:18:18 +08:00
joywayerandClaude Opus 5 681be60e20 二七王:design 全量复验(无新增不一致)+ 补端到端整局单测
对 E1~E3 修复后的实现做取证式复核:把 design 的判定语句做成可执行探针直接
打在代码上(§5.1/§5.2 跟牌层级、§8.1 算奖连对链、§7 算子逐档、§5.4 甩牌最大性、
§6.3 扣底、§8.4 三条支付线、§4/§9/§10/§11 流程与门控),未发现新的不一致。

新增 test/test_endgame.js:用真实发牌跑完整一局(叫分→上庄→选主→埋牌→28 轮
出牌→小局结算)并校验与牌面无关的不变量(牌张守恒 84/8/16、捡分=闲家赢得分牌
+扣底分、X 分配庄±2X/闲∓X、算奖 X×(2Ni−Nj−Nk)、零和、result 与判定一致),
另覆盖投降局与中途解散两条支线。连跑 10 次无抖动,全套单测 389 项通过。

合规文档补记「第四轮·复验」取证表。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-16 19:47:01 +08:00
joywayerandClaude Opus 5 916066ba96 二七王:修正 design 全量重核发现的 3 项不一致(亮牌快照/报无主下发面/甩牌张数上限)
- §8.2 亮牌改用埋牌后 28 张静态快照 get_seat_cards_award,不再用
  get_seat_cards(只含未出的牌)——否则闲家重连时 get_deskinfo 按庄家
  当前剩余手牌重算,亮牌统计缩水甚至变 null。
- §9 出牌包由只带出牌者一家的 info 改为整表下发三家 seatlist,与重连包
  PushCards.seatlist 同名同构;报无主后另两家的主牌数/对子数不再滞后两次出牌。
- §5.4.3 甩牌"无组合数量限制":can_playcard 去掉规则外的 14 张硬上限,
  改为结构性上界 28(单人手牌上限,牌型编码在此范围内不溢出)。

协议文档同步改写 chupai 三处 info 条目与 liangpai 口径;合规文档补记第四轮
核对(流程层无缺环,规则层 3 项已收口)。全套单测 368 项通过。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-16 19:33:06 +08:00
joywayerandClaude Opus 5 b6aeba412f 二七王:把「无超时托管」确认为规则,写入 design §11
服务端四个阶段只下发 countdown、没有任何定时器,此前被本轮核对记
为待办 D3(等规则设计者定义超时默认动作)。规则设计者已确认:
**维持现状,不需要超时动作**。

这属于规则本身如此、而非实现缺口。若不固化下来,下一轮核对会再次
把它当缺陷提出、甚至有人去补一套「超时自动出牌」,反而违背规则。
故写进 design.md 作为权威约定:

- design §11 新增一条:倒计时只作展示、不触发任何自动操作——不自
  动叫分/选主/埋牌/出牌,也不判负、不跳过;轮到谁而谁不操作,牌局
  就停在这一步等待。并加醒目说明:这是确认过的规则、不是待实现的
  缺口,牌局停住由玩家走房间解散流程收场(按当前累计分结算,
  §12.2),后续核对不要为它补超时托管。
  (解散路径已核实:平台 server_room 侧有 freeroom 解散倒计时,并
  回调子游戏 export.get_disbandRoom → get_paiju_account(2) 出解散
  结算包,与 §12.2 一致。)
- 协议文档新增 0.3「countdown 只是展示用的秒数」:说明服务端无定
  时器、归零不做任何事,并要求客户端不得在归零时做乐观界面推进
  (原 0.3 顺延为 0.4)。
- 合规 01:D3 由「🟧 中等/未修」改为「✅ 规则如此」,并说明 server
  dev-guide「服务端自动操作复用真人链路」约束的是「若要做代打就必
  须复用真人链路」,本局不做代打故不适用;「尚未处置」小节改为
  「无」,11 项全部收口。
- 合规 02:撤掉「仍无自动化覆盖」中的超时项,改为说明不需要超时用
  例,并反向标注:若将来有人给服务端加了超时代打,那才是违反
  design §11、应由核对拦下。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-16 19:05:24 +08:00
joywayerandClaude Opus 5 35affa7c20 二七王:不可查牌模式屏蔽出牌历史(design §9 消歧义 + 代码门控)
design §9 原文把可查牌模式的四项功能列成无序列表,不可查牌只写
「不提供以上任何查看 / 明牌功能」,随后展开的例子却只提了主牌数量、
对子结构、明牌按钮、亮牌统计,没提第一条「已经打出的牌可以查看」,
导致"以上"的范围有歧义。代码据此照发出牌历史,前一轮核对把它记为
待确认项(01 表 D6)。

规则设计者已确认:**不可查牌模式必须屏蔽出牌历史,只有可查牌模式
才能查看**。据此:

- design §9 改写为无歧义表述:先给出「查牌 = 回看不该随时可见的信
  息」的定义,把可查牌的四项功能编号列出(① 出牌历史 ② 报无主后的
  他家主牌数/对子数 ③ 明牌 ④ 庄家亮牌),不可查牌逐条对应说明一项
  都不提供;并补一段边界说明——**当前这一轮桌面上的牌两种模式下都
  必须可见**,否则后出的人无从跟牌、无从判断本轮谁最大,断线重连同
  理(当前轮照常恢复,往轮历史按模式开关给不给)。
- class.export.js:get_deskinfo 的 PushCards.pushlist 构建与排序整
  体移入 `if (!cfg.nocheck)`,不查牌时不带该属性;当前轮桌面牌由
  PushCards.playproc.cards 恢复,两种模式都有。
- 协议文档:pushlist 补「仅可查牌模式下有此属性」,playproc 补「两
  种模式恒有」及其原因。
- 合规文档:01 表 D6 由「待确认/未修」改为已确认并修复,从「尚未处
  置」移出;02 测试计划断言总数 357→361 并新增该维度覆盖行。

test_rpc 新增 4 项:不查牌房无 pushlist、可查牌房有 pushlist,且两
种模式下当前轮桌面牌 playproc.cards 都能恢复。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-16 18:55:33 +08:00
joywayerandClaude Opus 5 c4256c51db 二七王合规文档:修正"全部符合"结论并补第三轮核对
01 的「二次全量复核结论」写的是「服务端全部符合 design.md」,但该
轮核对完全按 design 章节组织,平台接入、客户端入参校验、下发面一
致性、协议红线这几类问题整类不在范围内——所以 270 项断言全绿的同
时,漏掉了 1 项阻断级(子游戏从未在 app.js 注册,运行时不可达)、
3 项严重(重复牌id 可伪造牌型、入参无类型校验、下发面 multiple 忽
略爬坡)与 data.success 红线缺失。

本次:
- 01 把结论限定为「就 design.md 的玩法规则维度而言符合」,并加警示
  「符合 design.md ≠ 实现完整正确」。
- 01 新增「第三轮核对」章节:A1/B1/B2/B3/C1/D1~D7 共 11 项的严重
  度、位置、实测现象与处置,并单列两项需外部输入的待办(D3 超时托
  管无定时器、D6 不查牌模式是否屏蔽出牌历史的规则歧义)。
- 02 测试计划更新断言总数 270→357,新增「第三轮补充:design 之外
  的可验证维度」覆盖表(入参校验/重复id/报无主刷新/success 成功包
  与失败回包/multiple 同源/甩牌下发面/pushlist 结构/相邻链花色),
  并写明两项仍无自动化覆盖的原因。
- 00 加一段说明前两轮的核对范围局限,指向 01 第三轮。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-12 04:25:15 +08:00
joywayerandClaude Opus 5 a049498f2c 二七王协议文档:补齐 success/errcode 约定并同步本轮字段变更
协议文档开头一直写着「成败判定只看推送包里的 data.success」,但下
面没有任何一个包定义过该字段,代码里也没有——文档自相矛盾且与实
现不符。本轮代码补齐后同步文档:

- 新增「0. 通用约定」:0.1 所有服务器→客户端包必带 data.success;
  0.2 失败回包(rpc 与请求同名、只回请求者、success=false+errcode)
  与 errcode 取值表,另附 cards 牌id 入参约束(非空数组、0~107 整
  数、不重复,不做类型兜底)与 tishi 成功不回执的例外;0.3 说明
  deskinfo 的 success 归平台填写。
- 6 处 multiple 描述改为 get_base_bycall(call, climb),列出爬坡与
  常规两套取值,并注明与结算包 aset.multiple 同源。
- chupai1 补 shuai 字段;cardtype 补完整取值说明与「甩牌会被压平、
  真实结构读 shuai」的告警。
- 3 处 info 描述补「有人报无主后三个座位同时刷新」。
- PushCards.pushlist 描述补「内层恒 3 个座位、按本局主牌花色排序」。
- mingpai / tishi 的「否则忽略」改为按 0.2 回对应 errcode 的失败包。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-12 04:22:53 +08:00
joywayerandClaude Opus 4.8 9456ab9319 二七王:实现 §11 闲家三提示(踩/没分/有分) + 明确副7/副2 成对语义
全面符合性再审查(4 维度独立对抗核对)结论:与计分/发牌/出牌/跟牌/甩牌
相关规则均一致,无缺陷;仅 §11 闲家三提示服务端缺失、副7/副2 异花色
成对语义存疑两项待办。本次按用户裁定落地:

1. §11 三提示(新增 mod.tishi):闲家在出牌阶段(step5)发 踩/没分/有分,
   服务端不校验真实性、只 SendPack 转发给对家(另一闲家 3-banker-seat);
   庄家无对家不参与;非法 tip/非出牌阶段/庄家发均拒。
   协议补 packet_protocol §13.7/13.8;test_rpc +11 例(正反+边界)。
2. 副7/副2 成对语义:裁定"只同花色同点数两副成对"(代码本已如此,无需改),
   在 design §3 补说明闭合该反复出现的存疑(异花色副7 不成对)。

compliance 文档同步:§11 状态转✅、首轮结论摘要加"非当前状态"说明、
计数 259→270。全套 270 项断言全绿(rpc 34→45)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 16:39:04 +08:00
joywayerandClaude Opus 4.8 5c9a78029a 二七王测试计划:同步跟牌覆盖度修复后的计数与状态
test_follow 由 35→50 例、全套 244→259 项;§5.1/5.2 覆盖状态由"❌重大
缺口"更新为✅(含混合出牌、毙牌完全缺门、降级递归 else 欠约束修复回归)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 07:19:23 +08:00
joywayerandClaude Opus 4.8 1edbe9cc24 二七王规则:新增"混合出牌"概念(副牌不够+补主牌,等效垫牌)
场景:首家出副牌、跟牌方有该花色副牌但张数不够、又无其他副牌可垫,
只能用主牌补差额,打出"副牌+主牌"混合。核对 can_followcard:混合牌
组不成纯主牌牌型,cardvalue=0,压不过首家。此前文档未成文——补入
术语表并在 §5.2 数量不足段落指向,明确它既非垫牌也非毙牌、但与垫牌
等效、不争夺出牌权。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 06:58:25 +08:00
joywayerandClaude Opus 4.8 55db22f4b1 二七王规则:明确 §5.2 同花色牌数量不足时缺口补牌规则
原第 150 行仅笼统一句"缺口部分可任意补其他牌",未针对"首家出拖拉机"
点破缺口不必成对/成拖拉机,且易与层级 4(同花色够、对子不够→补同花色
单张)混淆。按 get_followcard 数量不足分支(cantype 落单张型、只校验张数)
改写为:该花色牌全部必出,缺口用任意其他花色牌补、不强制成对/成拖拉机,
并与"完全缺门"情形分段。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 06:48:38 +08:00
joywayerandClaude Opus 4.8 83545e8b80 二七王规则:修正 §5.2 毙牌成立条件为"完全缺门"
原第 156 行写"没有该副牌花色的同长度拖拉机"即可毙,暗示手里有该
花色的牌但不成拖拉机时也能用主牌毙——与代码不符。核对
class.arith.js can_followcard:毙牌成功(cardvalue>0)仅出现在完全
缺门分支,只要手中还有首家花色的牌,get_followcard 即判为必出,
只能垫不能毙。将三条特殊情况统一收紧为"完全缺门",并补前提说明。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 06:36:57 +08:00
joywayerandClaude Opus 4.8 93449c8a92 二七王规则:按代码实际行为补全 §5.2 拖拉机跟牌的强制降级层级
design.md §5.2 原本只描述"两连对"最简情形,缺少 3 连对及以上的
强制层级。按 class.arith.js get_followcard 的实际实现补写为完整
优先级表:同长拖 > 更短拖拆凑 > 对子够 > 对子不够全出+补 > 单张补;
并修正对子行"同花不足两张必出现有同花"的措辞。§5.4.4 甩牌跟牌
加一句交叉引用,点明与正常跟牌共用同一层级原则。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 06:16:50 +08:00
joywayerandClaude Opus 4.8 0d9ea36c10 二七王测试:穷举跟牌方手牌分支,补主牌首出与拖拉机各分支
回应"是否模拟了跟牌方所有手牌与边界"的核对,补齐:
- 主牌首出的跟牌(单/对)——原仅测副牌首出
- 对子首出·同花色仅1张(必出它+补1张)
- 拖拉机首出的跟牌方分支:对子不够(出仅有的对+补)、同花无对(补同花)、
  多候选拖拉机(cantype=3xx,回归 can_followcard 曾崩溃的 D1 分支)、
  3连对首出、富余对子中必出3连拖/拆散拒
- 手牌数==首出张数(全部必出)

全部单测 244 项断言全绿(test_follow 35)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 01:51:58 +08:00
joywayerandClaude Opus 4.8 c29aec140c 二七王测试:补全甩牌/跟甩牌全部情形
回应"甩牌与跟甩牌测试是否完整"的核对,补齐缺口:
- 甩牌首出(§5.4):甩错由主对分量/拖拉机分量/双对之一被压引发(原仅测单张分量);
  纯双单张、纯双对(不连)、单张+拖拉机、单+对+拖三分量混合的合法;副牌禁甩·对手非缺门
- 甩错惩罚实际执行(§5.4.5):do_playcard 收回甩牌、只强制打出最小一张、其余留手;合法甩牌整套打出
- 跟甩牌(§5.4.4):拖拉机分量退化到单张(对子也不够)、多组拖拉机分量、混合demand逐分量对位
- 集成:首出合法甩牌→跟牌方拆散主对(违反§5.4.4)→ do_playcard 拒;正确对位→接受

全部单测 226 项断言全绿(arith 101 / paiju 31 等)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 01:34:02 +08:00
joywayerandClaude Opus 4.8 339e6e99e1 二七王测试:完成 P2 用例,达成测试计划 DoD
- test_deal.js(新):§2 发牌构成——92张/去3-4共16/三家各28+底8/分值(§6.1)
- test_arith.js:§3 编码排序(order_cards 降序=设计顺序、is_continuous 相邻链逐段+反例)、
  §7 每档小光/过庄分界+升3级补齐
- test_paiju.js:§8.2 亮牌更多边界(6个7仅qi、固定主9→null、固定主10仅zhu)
- test_config.js:§10 直接调 export.get_asetcount/get_needroomcard(_joinroom)
- test_rpc.js/_rpc.js:§12 端到端(真实驱动 叫分→上庄→选主→埋牌→出牌ready)、
  §9 maipai 亮牌门控 + get_deskinfo PushCards 门控
- 02-测试计划.md/README:P2 与 DoD 标记达成

全部单测 204 项断言全绿(node server/games/erqiwang/test/run.js)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 01:24:34 +08:00
joywayerandClaude Opus 4.8 6939e70ed7 二七王测试:完成 P1 用例(L3 RPC 层 + 坐庄轮换)
- mod.js:加 module.exports 守卫,使其可被 Node require(友乐无 module 跳过)
- test/_rpc.js(新):L3 脚手架——挂类全局、mock cls_mod/min_loadJsFile 装配 mod.js、
  捕获 SendPack/sendpack_toother 下发包
- test/test_rpc.js(新):§9 明牌 mingpai(合法/不查牌·未报无主·非出牌阶段拒 + others结构)、
  §9 出牌 chupai 的 info/baozhu 查牌门控(可查有/不查无)、§4 投降 touxiang 条件(70·step2·庄家)、
  §4.2 mod.jiaofen 入参校验(>70/非5倍/首家必叫/后叫更低)、
  §4 70分上庄暗牌亮牌(真实 jiaofen 驱动到上庄,验证 bottomcards/ancard3s 门控)
- test/test_desk.js(新):§4.6 坐庄轮换 do_prepare(庄赢连庄/闲赢·投降下家)
- 02-测试计划.md/README:P1 标记完成,剩余归入 P2

全部单测 156 项断言全绿(node server/games/erqiwang/test/run.js)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 01:14:33 +08:00
joywayerandClaude Opus 4.8 0049754988 二七王测试:完成 P0 用例(正常跟牌/结算集成/叫分坐庄/扣底触发)
- test_follow.js(新):§5.1/5.2 正常跟牌/毙牌/垫牌 17 例——单张/对子/拖拉机的
  必出、缺门毙牌数量对应(副单→主单/副对→主对/副N连→主N连)、垫牌、有对/拖却出散张被拒
- test_callgrade.js(新):§4.2 叫分坐庄 do_callgrade 6 例(叫5立即/两家不叫/后叫更低)
- test_paiju.js:§7/§8 结算集成扩充(大光/过庄/升级/爬坡/傍王+算奖参与/对照)、
  §6.3 扣底触发 get_bottom_account(主对×2/两连对×4/副牌不扣/庄赢不扣)
- 02-测试计划.md/README:P0 全部标记完成

全部单测 123 项断言全绿(node server/games/erqiwang/test/run.js)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 01:03:01 +08:00
joywayerandClaude Opus 4.8 5a5165a319 二七王:制定服务端合规测试计划
- docs/compliance/02-测试计划.md:按 design 章节的"规则→用例"覆盖矩阵
  (标注被测函数/测试层L1-L3/正反边界/覆盖状态),缺口清单按优先级排序,
  以及 L2 局内集成 / L3 RPC 层所需脚手架
- test/README.md:链接测试计划

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 00:02:52 +08:00
joywayerandClaude Opus 4.8 e31bdd854d 二七王文档:记录二次全量复核结论 + §5.4.4 修复同步
- compliance/01:新增二次对抗性复核结论(服务端全部符合 design.md);
  §5.4 标记全部完成、§5.4.4 已修;修正过时的 §10.1 数组下标描述
- packet_protocol.md:playproc 补 shuai_demand 字段说明

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 23:20:09 +08:00
joywayerandClaude Opus 4.8 dcf8e09f7d 二七王文档:同步 design 流程/协议,新增合规核对
design.md
- 修正选主/埋牌顺序笔误(确认「先选主后埋牌」)
- 投降改为选主阶段与选主互斥的选择(不选主/不埋牌直接结算),算奖用庄家36张、无连对链
- 70分暗牌改为「庄家摸牌之前、向所有玩家亮3秒」
- 选主阶段前端显示每花色对数、70分并列投降按钮
- 新增 §12「完整牌局游玩流程」(含大局与阶段速览)

packet_protocol.md(随代码如实同步)
- 结算 aset/seatlist 新结构(multiple=基础子数、upgrade 判定倍率、bangwang/climb、
  chongguan/wang/naward/grade_aw);shangzhuang bottomcards 按70分门控 + ancard3s
- maipai/PushCards 亮牌 liangpai;chupai info/baozhu 按查牌门控;新增 mingpai 收发包
- step 枚举去掉废弃的投降4;删除 Surrender 重连视图

docs/compliance/(新增)
- 00 初步不一致清单、01 design 合规逐节核对(含整改进度与 roomtype 位串约定)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-04 22:34:06 +08:00
joywayer 96372d713c 规则文档理清楚,开始代码层面对比和校对 2026-07-04 09:52:49 +08:00