From 8f8f17bd8fb4996ed913d04778180895507900db Mon Sep 17 00:00:00 2001 From: gahusb Date: Sat, 27 Jun 2026 02:44:06 +0900 Subject: [PATCH] =?UTF-8?q?fix(deck):=20=EB=B2=84=EB=A6=AC=EA=B8=B0-?= =?UTF-8?q?=EB=BD=91=EA=B8=B0=20=EC=B9=B4=EB=93=9C=EC=9D=98=20=EB=AF=B8?= =?UTF-8?q?=EC=84=A0=EC=96=B8=20prop=20=EC=B6=94=EA=B0=80=20(no=20such=20f?= =?UTF-8?q?ield=20=ED=81=AC=EB=9E=98=EC=8B=9C)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `DiscardPostDraw`·`DiscardDrawPerPick`가 hand.mjs(BeginDiscardSelection· AutoDiscardHand·FinishDiscardSelection·SelectDiscardSlot)에서 대입되는데 gen-slaydeck.mjs prop 목록에 선언되지 않아 런타임 "cannot set DiscardPostDraw, no such field"로 BeginDiscardSelection이 중단됨. 그 직전 DiscardSelectRemaining/ Total이 이미 set되어 게임이 버리기-선택 모드에 갇혀, 이후 모든 카드(공중제비 포함) 클릭이 버리기 픽으로 처리됨("2장 버린다 표시 + 동작 없음"). 근본 원인: 형제 prop DiscardPostShiv·DiscardShivPerPick는 선언됐으나 draw 변형 2개가 누락. 선언만 추가(병렬 패턴). 신규 가드 tools/verify/cbprops.mjs: cb의 `self.X =` 대입 ↔ 선언 prop 대조, 미선언 = no such field 후보 검출. 수정 전 2개 누락→후 0. 검증: cbprops 0·cbgap GAP 0·테스트 93/93. 산출물(codeblock) 재생성 포함. Co-Authored-By: Claude Opus 4.8 (1M context) --- RootDesk/MyDesk/SlayDeckController.codeblock | 14 ++++++++ tools/deck/gen-slaydeck.mjs | 2 ++ tools/verify/cbprops.mjs | 34 ++++++++++++++++++++ 3 files changed, 50 insertions(+) create mode 100644 tools/verify/cbprops.mjs diff --git a/RootDesk/MyDesk/SlayDeckController.codeblock b/RootDesk/MyDesk/SlayDeckController.codeblock index 952c981..4e43acf 100644 --- a/RootDesk/MyDesk/SlayDeckController.codeblock +++ b/RootDesk/MyDesk/SlayDeckController.codeblock @@ -932,6 +932,20 @@ "Attributes": [], "Name": "DiscardShivPerPick" }, + { + "Type": "number", + "DefaultValue": "0", + "SyncDirection": 0, + "Attributes": [], + "Name": "DiscardPostDraw" + }, + { + "Type": "number", + "DefaultValue": "0", + "SyncDirection": 0, + "Attributes": [], + "Name": "DiscardDrawPerPick" + }, { "Type": "boolean", "DefaultValue": "false", diff --git a/tools/deck/gen-slaydeck.mjs b/tools/deck/gen-slaydeck.mjs index 4c3ceac..b93ad87 100644 --- a/tools/deck/gen-slaydeck.mjs +++ b/tools/deck/gen-slaydeck.mjs @@ -152,6 +152,8 @@ function writeCodeblocks() { prop('number', 'DiscardSelectTotal', '0'), prop('number', 'DiscardPostShiv', '0'), prop('number', 'DiscardShivPerPick', '0'), + prop('number', 'DiscardPostDraw', '0'), + prop('number', 'DiscardDrawPerPick', '0'), prop('boolean', 'RetainSelectActive', 'false'), prop('boolean', 'ReserveSelectActive', 'false'), prop('number', 'NextTurnBlock', '0'), diff --git a/tools/verify/cbprops.mjs b/tools/verify/cbprops.mjs new file mode 100644 index 0000000..f9463e8 --- /dev/null +++ b/tools/verify/cbprops.mjs @@ -0,0 +1,34 @@ +// cb/*.mjs의 `self. = ` 대입 ↔ gen-slaydeck.mjs 선언 prop 대조. +// 미선언 prop에 대입하면 MSW 런타임 "cannot set X, no such field" → 그 후보를 정적 검출. +// 사용: node tools/verify/cbprops.mjs +import { readFileSync, readdirSync } from 'node:fs'; + +const orch = readFileSync('tools/deck/gen-slaydeck.mjs', 'utf8'); +const declared = new Set(); +for (const m of orch.matchAll(/prop\(\s*'[^']*'\s*,\s*'([^']+)'/g)) declared.add(m[1]); + +// MSW 빌트인/설정으로 대입 가능한 self 필드(프롭 아님) — 오탐 제외 화이트리스트. +const BUILTIN = new Set(['Entity']); + +const dir = 'tools/deck/cb'; +const files = readdirSync(dir).filter((f) => f.endsWith('.mjs')); +const assigns = new Map(); // name -> Set(files) +for (const f of files) { + const src = readFileSync(`${dir}/${f}`, 'utf8'); + // self.Name = (단, == / ~= / .Y= / [..]= 는 제외) + for (const m of src.matchAll(/self\.([A-Za-z_]\w*)\s*=(?!=)/g)) { + const name = m[1]; + if (!assigns.has(name)) assigns.set(name, new Set()); + assigns.get(name).add(f); + } +} + +const missing = [...assigns.keys()] + .filter((n) => !declared.has(n) && !BUILTIN.has(n)) + .sort(); + +console.log(`선언 prop: ${declared.size} | 대입된 self.X distinct: ${assigns.size}`); +console.log(`미선언 대입 (no such field 후보): ${missing.length}`); +for (const n of missing) console.log(` - ${n} [${[...assigns.get(n)].join(', ')}]`); +console.log(missing.length ? 'RESULT: MISSING PROPS ABOVE' : 'RESULT: 모든 self 대입이 선언됨 ✓'); +process.exit(missing.length ? 1 : 0); -- 2.49.1