poker-mcp 1.5.0 → 1.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,13 +4,96 @@ YAML-based input file management tool for radiation-shielding calculation code P
4
4
 
5
5
  ## 📋 クイック情報
6
6
 
7
- - **バージョン**: 1.5.0
7
+ - **バージョン**: 1.6.0
8
8
  - **プロトコル**: MCP (Model Context Protocol) 1.0.0 完全準拠
9
9
  - **メインサーバー**: `src/mcp_server_stdio_v4.js`
10
10
  - **データ保存**: `~/.poker-mcp/`(`POKER_MCP_HOME`環境変数で変更可)
11
11
  - **核種データ**: `${POKER_INSTALL_PATH}/LIB/ICRP-07.NDX` を直接参照
12
12
  - **実行方式**: STDIO通信(MCPプロトコル標準)
13
13
 
14
+ ## 🆕 バージョン1.7.0〜1.7.2の新機能
15
+
16
+ ### 📉 サマリー出力量の制御(ThinnedIndices 操作系 3メソッド)
17
+ `thinnedindices` ノードを MCP から設定できます。`.paths` の生成では全ての
18
+ 線源分割点と検出器評価点が必要ですが、既定では間引かれるため手で書き足す
19
+ 必要がありました。
20
+
21
+ ```javascript
22
+ poker_updateThinnedIndices({ fit_for_paths: true })
23
+ // → 入力の分割定義と検出器グリッドから必要数を計算して設定
24
+ ```
25
+
26
+ 既定値は poker_mcp 側で持ちません。省略しても `.summary` には全 7 キーが
27
+ 値付きで出力されるので、そちらを正とします。
28
+
29
+ ### 🔄 保留中の変更が `get` で見えるように
30
+ `propose` の直後に `get` を呼ぶと変更が見えず、「反映されていない」と誤解する
31
+ 余地がありました。確定値とは別に `pending` として示します。
32
+
33
+ ```javascript
34
+ poker_proposeThinnedIndices({ sourcepoint: 100 })
35
+ poker_getThinnedIndices()
36
+ // → { thinnedindices: null, pending: { sourcepoint: 100 }, pending_count: 1 }
37
+ ```
38
+
39
+ ### 🛡️ `.paths` の座標照合
40
+ 件数だけでなく座標も YAML と突き合わせます。検出器を動かして `.paths` を
41
+ 再生成し忘れると、件数は変わらないため従来は通り抜け、**静かに誤った線量**が
42
+ 出ていました。
43
+
44
+
45
+ ## 🆕 バージョン1.6.0の新機能
46
+
47
+ ### 🧱 カスタム材料をライブラリ追加だけで使えるように
48
+ 材料の一覧・密度範囲・ビルドアップ可用性をコード側に持たず、すべて
49
+ `%POKER_INSTALL_PATH%/LIB/` から読み込むようにしました。**カスタム材料を
50
+ `lib_material.dat` に追記すれば、コード変更なしにサーバ再起動だけで
51
+ ゾーン定義・密度検証・等価材料の自動選定すべてに反映されます。**
52
+
53
+ 標準材料を追加する場合は `lib_material.dat` と `lib_setting.dat` の
54
+ `buildup_material` の両方に登録します(片方だけなら警告が出ます)。
55
+
56
+ ### 🔀 ビルドアップ等価材料の選定を実データ方式へ
57
+ 従来の光子実効Z最近傍は暫定実装でした。ビルドアップを支配するのは散乱と吸収の
58
+ 競合であることから、POKER の減衰係数ファイルから
59
+ `μ_incoherent / (μ_total − μ_incoherent)` を求め、0.1〜3 MeV の11点で
60
+ 最も一致する標準材料を選びます。
61
+
62
+ 一致度スコアを応答に付けるようにしました。0.30 を超える場合は「標準材料に
63
+ 近いものが無い」ことを意味し、候補上位3件とともに警告を出します。黙って粗い
64
+ 代用材を当てるより、どの程度粗いかを見せる方が判断材料になります。
65
+
66
+ この変更で `Source_Dry` の等価材料は `Lead` から `Tungsten` に変わります。
67
+
68
+ ### 🐛 `poker_updateBuildupFactor` が equivalent を更新できない問題を修正
69
+ ツールスキーマと `DataManager` の双方に `equivalent` が無く、`TaskManager`
70
+ だけが素通しする三層不整合でした。変更・解除(空文字指定)に対応し、
71
+ 標準材料への指定や非標準材料の指定を拒否する検証も追加しています。
72
+
73
+ ### 📡 CAD連携レイトレース
74
+ FreeCAD のソリッドモデルを、STEP のような中間フォーマットを介さず、CSG で
75
+ 表現し直す作業も無しに遮蔽体系として扱えます。線源点→検出器の直線を FreeCAD 側で
76
+ 追跡し、通過した材質と厚さを `.paths` ファイルで POKER に渡します。
77
+
78
+ ```bash
79
+ poker_cui model.yaml -p -t # 分割点を出力
80
+ freecadcmd -c "... gen_paths.main('spec.json')" # CAD をトレース
81
+ poker_cui model.yaml --path-input model.paths -t # 計算
82
+ ```
83
+
84
+ POKER 側の `--path-input` も実装され、CSG 経由と一致することを平板・円筒・球の
85
+ 5 体系で確認済みです。フィレットや自由曲面のように CSG で表現できない形状も
86
+ 扱えます。**複数線源・グリッド検出器・スラント補正に対応**。
87
+
88
+ 他の CAD で作ったモデルも、STEP で FreeCAD に読み込めば同じパイプラインに
89
+ 乗ります。副産物として、POKER の改造なしで使える**簡易化の監査ツール**
90
+ (ある形状を省略してよいかを定量化する)もあります。
91
+
92
+ 詳細は [CAD_RAYTRACE.md](./docs/manuals/CAD_RAYTRACE.md)、フォーマットは
93
+ [PATHS_FORMAT.md](./docs/manuals/PATHS_FORMAT.md)。
94
+
95
+ 詳細は [CHANGELOG.md](./CHANGELOG.md) を参照。
96
+
14
97
  ## 🆕 バージョン1.5.0の新機能
15
98
 
16
99
  ### 🖥️ POKER GUI を閉じずに表示を切り替え
@@ -33,8 +116,6 @@ YAML-based input file management tool for radiation-shielding calculation code P
33
116
  乱数で「正常」を出力する監視スクリプトなど、実態と乖離した記述を削除し、
34
117
  検証可能な手順のみに整理しています。
35
118
 
36
- 詳細は [CHANGELOG.md](./CHANGELOG.md) を参照。
37
-
38
119
  ## 🆕 バージョン1.4.0の新機能
39
120
 
40
121
  ### ☢️ 子孫核種の自動管理
@@ -255,7 +336,7 @@ Claude Desktopで以下のようにテストできます:
255
336
  ## 🏆 主要機能
256
337
 
257
338
  ### ✅ **MCP完全対応**
258
- - **30メソッド完全実装**: 全ての放射線遮蔽計算入力管理機能
339
+ - **33メソッド完全実装**: 全ての放射線遮蔽計算入力管理機能
259
340
  - **JSON-RPC 2.0準拠**: 標準プロトコル完全対応
260
341
  - **STDIO通信**: MCPクライアントとの標準通信方式
261
342
  - **自動バックアップ・ロールバック**: 企業品質のデータ保護
@@ -274,7 +355,7 @@ Claude Desktopで以下のようにテストできます:
274
355
 
275
356
  ## 🎯 API構成
276
357
 
277
- ### 🔧 **30メソッド完全実装**
358
+ ### 🔧 **33メソッド完全実装**
278
359
 
279
360
  | **カテゴリ** | **メソッド数** | **機能** | **主要操作** |
280
361
  |-------------|---------------|----------|-------------|
@@ -287,7 +368,7 @@ Claude Desktopで以下のようにテストできます:
287
368
  | **📏 Unit** | 5個 | 単位設定管理 | propose・get・update・validateIntegrity・analyzeConversion |
288
369
  | **⚙️ System** | 6個 | システム制御 | applyChanges・executeCalculation・resetYaml・confirmDaughterNuclides・openGui・各種検証 |
289
370
 
290
- ### 📋 **全30メソッド一覧**
371
+ ### 📋 **全33メソッド一覧**
291
372
  ```
292
373
  Body系 (3): poker_proposeBody, poker_updateBody, poker_deleteBody
293
374
  Zone系 (3): poker_proposeZone, poker_updateZone, poker_deleteZone
package/package.json CHANGED
@@ -1,55 +1,56 @@
1
- {
2
- "name": "poker-mcp",
3
- "version": "1.5.0",
4
- "description": "YAML-based input file management tool for radiation shielding calculation code POKER with MCP support - Enhanced with collision detection, daughter nuclide auto-completion, and environment variable support",
5
- "main": "src/mcp_server_stdio_v4.js",
6
- "type": "module",
7
- "bin": {
8
- "poker-mcp": "src/mcp_server_stdio_v4.js"
9
- },
10
- "scripts": {
11
- "start": "node src/mcp_server_stdio_v4.js",
12
- "dev": "nodemon src/mcp_server_stdio_v4.js",
13
- "prepare": "echo 'NPX ready: npx poker-mcp'",
14
- "check:manifest": "node scripts/check-manifest-sync.mjs"
15
- },
16
- "keywords": [
17
- "mcp",
18
- "model-context-protocol",
19
- "yaml",
20
- "radiation",
21
- "shielding",
22
- "nuclear",
23
- "radioisotope",
24
- "medical",
25
- "accelerator",
26
- "POKER",
27
- "physics",
28
- "validation",
29
- "npx",
30
- "point-kernel",
31
- "collision-detection",
32
- "daughter-nuclide"
33
- ],
34
- "author": "Yoshihiro Hirao <tora@pointkernel.com>",
35
- "license": "ISC",
36
- "repository": {
37
- "type": "git",
38
- "url": "git+https://github.com/Hirao-Y/poker_mcp.git"
39
- },
40
- "homepage": "https://github.com/Hirao-Y/poker_mcp#readme",
41
- "engines": {
42
- "node": ">=18.0.0"
43
- },
44
- "dependencies": {
45
- "@modelcontextprotocol/sdk": "^1.29.0",
46
- "js-yaml": "^4.1.0",
47
- "winston": "^3.17.0",
48
- "zod": "^3.24.2"
49
- },
50
- "files": [
51
- "src/",
52
- "README.md",
53
- ".mcp.json"
54
- ]
55
- }
1
+ {
2
+ "name": "poker-mcp",
3
+ "version": "1.7.2",
4
+ "description": "YAML-based input file management tool for radiation shielding calculation code POKER with MCP support - Enhanced with collision detection, daughter nuclide auto-completion, and environment variable support",
5
+ "main": "src/mcp_server_stdio_v4.js",
6
+ "type": "module",
7
+ "bin": {
8
+ "poker-mcp": "src/mcp_server_stdio_v4.js"
9
+ },
10
+ "scripts": {
11
+ "start": "node src/mcp_server_stdio_v4.js",
12
+ "dev": "nodemon src/mcp_server_stdio_v4.js",
13
+ "prepare": "echo 'NPX ready: npx poker-mcp'",
14
+ "check:manifest": "node scripts/check-manifest-sync.mjs",
15
+ "test:pending": "node tests/pending-view.test.mjs"
16
+ },
17
+ "keywords": [
18
+ "mcp",
19
+ "model-context-protocol",
20
+ "yaml",
21
+ "radiation",
22
+ "shielding",
23
+ "nuclear",
24
+ "radioisotope",
25
+ "medical",
26
+ "accelerator",
27
+ "POKER",
28
+ "physics",
29
+ "validation",
30
+ "npx",
31
+ "point-kernel",
32
+ "collision-detection",
33
+ "daughter-nuclide"
34
+ ],
35
+ "author": "Yoshihiro Hirao <tora@pointkernel.com>",
36
+ "license": "ISC",
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "git+https://github.com/Hirao-Y/poker_mcp.git"
40
+ },
41
+ "homepage": "https://github.com/Hirao-Y/poker_mcp#readme",
42
+ "engines": {
43
+ "node": ">=18.0.0"
44
+ },
45
+ "dependencies": {
46
+ "@modelcontextprotocol/sdk": "^1.29.0",
47
+ "js-yaml": "^4.1.0",
48
+ "winston": "^3.17.0",
49
+ "zod": "^3.24.2"
50
+ },
51
+ "files": [
52
+ "src/",
53
+ "README.md",
54
+ ".mcp.json"
55
+ ]
56
+ }
@@ -5,7 +5,8 @@ import { createTransformHandlers } from './transformHandlers.js';
5
5
  import { createBuildupFactorHandlers } from './buildupFactorHandlers.js';
6
6
  import { createSourceHandlers } from './sourceHandlers.js';
7
7
  import { createDetectorHandlers } from './detectorHandlers.js';
8
- import { createUnitHandlers } from './unitHandlers.js';
8
+ import { createUnitHandlers } from './unitHandlers.js';
9
+ import { createThinnedIndicesHandlers } from './thinnedIndicesHandlers.js';
9
10
  import { createCalculationHandlers } from './calculationHandlers.js';
10
11
  import { resetHandlers } from './resetHandlers.js';
11
12
  import { createDaughterNuclideHandler } from './daughterNuclideHandler.js';
@@ -32,7 +33,8 @@ export function createAllHandlers(taskManager) {
32
33
  ...createDetectorHandlers(taskManager),
33
34
 
34
35
  // 単位操作
35
- ...createUnitHandlers(taskManager),
36
+ ...createUnitHandlers(taskManager),
37
+ ...createThinnedIndicesHandlers(taskManager),
36
38
 
37
39
  // 計算操作
38
40
  ...createCalculationHandlers(taskManager),
@@ -1,6 +1,7 @@
1
1
  // handlers/resetHandlers.js - YAML初期化ハンドラー
2
2
  import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js';
3
3
  import { logger } from '../../utils/logger.js';
4
+ import { MaterialCatalog } from '../../utils/MaterialCatalog.js';
4
5
 
5
6
  /**
6
7
  * poker_resetYaml ハンドラー
@@ -49,12 +50,9 @@ export function createResetYamlHandler(taskManager) {
49
50
  throw new McpError(ErrorCode.InvalidParams, `reset_level は ${validResetLevels.join(', ')} のいずれかである必要があります`);
50
51
  }
51
52
 
52
- const validMaterials = [
53
- 'Carbon', 'Concrete', 'Iron', 'Lead', 'Aluminium', 'Copper', 'Tungsten',
54
- 'Air', 'Water', 'PyrexGlass', 'AcrylicResin', 'Polyethylene', 'Soil', 'VOID'
55
- ];
56
- if (!validMaterials.includes(atmosphere_material)) {
57
- throw new McpError(ErrorCode.InvalidParams, `atmosphere_material は ${validMaterials.join(', ')} のいずれかである必要があります`);
53
+ if (!MaterialCatalog.has(atmosphere_material)) {
54
+ throw new McpError(ErrorCode.InvalidParams,
55
+ `atmosphere_material は ${MaterialCatalog.allMaterials().join(', ')} のいずれかである必要があります`);
58
56
  }
59
57
 
60
58
  // VOID材料の密度指定チェック
@@ -0,0 +1,48 @@
1
+ // mcp/handlers/thinnedIndicesHandlers.js
2
+ //
3
+ // thinnedindices(サマリー出力量の制御)のハンドラ。
4
+ // 既定値は poker_mcp 側で持たず、POKER の .summary に出力される値を正とする。
5
+
6
+ import { logger } from '../../utils/logger.js';
7
+
8
+ export function createThinnedIndicesHandlers(taskManager) {
9
+ return {
10
+ async proposeThinnedIndices(args) {
11
+ const result = await taskManager.proposeThinnedIndices(args || {});
12
+ return {
13
+ content: [{
14
+ type: 'text',
15
+ text: JSON.stringify({
16
+ success: true,
17
+ message: 'thinnedindices を提案しました(applyChanges で確定)',
18
+ ...result
19
+ }, null, 2)
20
+ }]
21
+ };
22
+ },
23
+
24
+ async getThinnedIndices() {
25
+ const result = await taskManager.getThinnedIndices();
26
+ return {
27
+ content: [{
28
+ type: 'text',
29
+ text: JSON.stringify(result, null, 2)
30
+ }]
31
+ };
32
+ },
33
+
34
+ async updateThinnedIndices(args) {
35
+ const result = await taskManager.updateThinnedIndices(args || {});
36
+ const msg = (args && args.fit_for_paths)
37
+ ? 'thinnedindices を更新しました(入力の分割数・評価点数に合わせました)'
38
+ : 'thinnedindices を更新しました(applyChanges で確定)';
39
+ logger.info(msg, { indices: result.thinnedindices });
40
+ return {
41
+ content: [{
42
+ type: 'text',
43
+ text: JSON.stringify({ success: true, message: msg, ...result }, null, 2)
44
+ }]
45
+ };
46
+ }
47
+ };
48
+ }
@@ -12,7 +12,7 @@ export const buildupFactorTools = [
12
12
  },
13
13
  equivalent: {
14
14
  type: 'string',
15
- description: '非標準材料のビルドアップ等価材料(省略時は組成の光子実効Zで最近傍の標準材料を自動選択)'
15
+ description: '非標準材料のビルドアップ等価材料(標準材料名)。省略時は組成の散乱/吸収比を実用エネルギー帯域で照合して自動選択'
16
16
  },
17
17
  use_slant_correction: {
18
18
  type: 'boolean',
@@ -45,6 +45,10 @@ export const buildupFactorTools = [
45
45
  use_finite_medium_correction: {
46
46
  type: 'boolean',
47
47
  description: '新しい有限媒体補正設定'
48
+ },
49
+ equivalent: {
50
+ type: 'string',
51
+ description: '非標準材料のビルドアップ等価材料(標準材料名)。空文字を指定すると等価材料の指定を解除します'
48
52
  }
49
53
  },
50
54
  required: ['material']
@@ -6,7 +6,8 @@ import { buildupFactorTools } from './buildupFactorTools.js';
6
6
  import { sourceTools } from './sourceTools.js';
7
7
  import { detectorTools } from './detectorTools.js';
8
8
  import { commonTools } from './commonTools.js';
9
- import { unitTools } from './unitTools.js';
9
+ import { unitTools } from './unitTools.js';
10
+ import { thinnedIndicesTools } from './thinnedIndicesTools.js';
10
11
  import { calculationTools } from './calculationTools.js';
11
12
  import { resetTools } from './resetTools.js';
12
13
  import { daughterNuclideTools } from './daughterNuclideTools.js';
@@ -20,7 +21,8 @@ export const allTools = [
20
21
  ...sourceTools,
21
22
  ...detectorTools,
22
23
  ...commonTools,
23
- ...unitTools,
24
+ ...unitTools,
25
+ ...thinnedIndicesTools,
24
26
  ...calculationTools,
25
27
  ...resetTools,
26
28
  ...daughterNuclideTools,
@@ -35,7 +37,8 @@ export {
35
37
  sourceTools,
36
38
  detectorTools,
37
39
  commonTools,
38
- unitTools,
40
+ unitTools,
41
+ thinnedIndicesTools,
39
42
  calculationTools,
40
43
  resetTools,
41
44
  daughterNuclideTools,
@@ -30,11 +30,7 @@ export const resetTools = [
30
30
  },
31
31
  atmosphere_material: {
32
32
  type: 'string',
33
- description: 'ATMOSPHEREゾーンに設定する材料',
34
- enum: [
35
- 'Carbon', 'Concrete', 'Iron', 'Lead', 'Aluminium', 'Copper', 'Tungsten',
36
- 'Air', 'Water', 'PyrexGlass', 'AcrylicResin', 'Polyethylene', 'Soil', 'VOID'
37
- ],
33
+ description: 'ATMOSPHEREゾーンに設定する材料。lib_material.dat に登録された材料名(カスタム材料を含む)または VOID',
38
34
  default: 'VOID'
39
35
  },
40
36
  atmosphere_density: {
@@ -0,0 +1,78 @@
1
+ // thinnedIndicesTools.js
2
+ //
3
+ // サマリーに書き出す件数を制御する thinnedindices ノードの CRU ツール。
4
+ // D(削除)は用意しない。削除しても POKER 側の既定値に戻るだけで、
5
+ // updateThinnedIndices で既定値を指定すれば同じ結果になるため。
6
+ //
7
+ // 既定値(ノードまたはキーを省略した場合に POKER が使う値):
8
+ // sourcepoint 10 / pseudosourcepoint 10 / detectorgrid 10 /
9
+ // detectorevaluation 5 / pathtrace 5 / buildupenergy 3 / buildupmfp 3
10
+ //
11
+ // これらは poker_mcp 側では持たない。省略しても .summary には全 7 キーが
12
+ // 値付きで出力されるので、実際の適用値はそちらを見れば分かる。既定値を
13
+ // 複製すると POKER 側の変更に追随できず、静かに食い違う。
14
+
15
+ const KEY_DESC = {
16
+ sourcepoint: '入力パラメータに書き出す線源分割点の数',
17
+ pseudosourcepoint: '入力パラメータに書き出す仮想点線源の数',
18
+ detectorgrid: '入力パラメータに書き出す検出器評価点の数',
19
+ detectorevaluation: '計算結果に書き出すグリッド検出器の評価点数',
20
+ pathtrace: 'path_trace に書き出す仮想点線源の数',
21
+ buildupenergy: '多層ビルドアップ係数のエネルギー数',
22
+ buildupmfp: '各エネルギーに対する mfp 数'
23
+ };
24
+
25
+ const keyProps = (prefix) => {
26
+ const p = {};
27
+ for (const [k, d] of Object.entries(KEY_DESC)) {
28
+ p[k] = {
29
+ type: 'integer',
30
+ minimum: 1,
31
+ description: `${prefix}${d}`
32
+ };
33
+ }
34
+ return p;
35
+ };
36
+
37
+ export const thinnedIndicesTools = [
38
+ {
39
+ name: 'poker_proposeThinnedIndices',
40
+ description: 'サマリー出力量の設定(thinnedindices)を新規作成します。既に存在する場合は updateThinnedIndices を使ってください。全キー省略可で、省略したキーは POKER の既定値が使われます。',
41
+ inputSchema: {
42
+ type: 'object',
43
+ properties: keyProps(''),
44
+ required: [],
45
+ additionalProperties: false,
46
+ title: 'サマリー出力量の設定',
47
+ description: '指定したキーのみ書き出します。省略したキーは POKER の既定値(sourcepoint 10 / pseudosourcepoint 10 / detectorgrid 10 / detectorevaluation 5 / pathtrace 5 / buildupenergy 3 / buildupmfp 3)が適用されます。'
48
+ }
49
+ },
50
+ {
51
+ name: 'poker_getThinnedIndices',
52
+ description: 'サマリー出力量の設定を取得します。YAML に書かれているキーのみ返し、省略されているキーは既定値が使われることを示します。実際の適用値は計算後の .summary の「サマリに出力される情報量」セクションで確認できます。',
53
+ inputSchema: {
54
+ type: 'object',
55
+ properties: {},
56
+ required: [],
57
+ additionalProperties: false
58
+ }
59
+ },
60
+ {
61
+ name: 'poker_updateThinnedIndices',
62
+ description: 'サマリー出力量の設定を更新します(部分更新可能)。ノードが無い場合は新規作成します。fit_for_paths を指定すると、入力の線源分割数と検出器評価点数から必要な値を自動で設定します(.paths 生成で全点が必要なとき)。',
63
+ inputSchema: {
64
+ type: 'object',
65
+ properties: {
66
+ ...keyProps('新しい'),
67
+ fit_for_paths: {
68
+ type: 'boolean',
69
+ description: 'true にすると、入力の線源分割定義(r×φ×z 等)と検出器のグリッド定義から必要数を計算し、sourcepoint / detectorgrid / detectorevaluation をその値に設定します。.paths の生成には全ての線源分割点と評価点が必要なため。個別に指定したキーがあればそちらを優先します。'
70
+ }
71
+ },
72
+ required: [],
73
+ additionalProperties: false,
74
+ title: 'サマリー出力量の部分更新',
75
+ description: '指定したキーのみ変更します。省略したキーは現在の設定を維持します。'
76
+ }
77
+ }
78
+ ];
@@ -473,6 +473,13 @@ export class SafeDataManager {
473
473
  if ('use_finite_medium_correction' in data) {
474
474
  buildup.use_finite_medium_correction = data.use_finite_medium_correction;
475
475
  }
476
+ if ('equivalent' in data) {
477
+ if (data.equivalent === '' || data.equivalent === null) {
478
+ delete buildup.equivalent;
479
+ } else {
480
+ buildup.equivalent = data.equivalent;
481
+ }
482
+ }
476
483
  }
477
484
  }
478
485
  break;
@@ -646,12 +653,41 @@ export class SafeDataManager {
646
653
  await this.applyUpdateUnit(data);
647
654
  break;
648
655
 
656
+ case 'proposeThinnedIndices':
657
+ await this.applyProposeThinnedIndices(data);
658
+ break;
659
+
660
+ case 'updateThinnedIndices':
661
+ await this.applyUpdateThinnedIndices(data);
662
+ break;
663
+
649
664
  default:
650
665
  logger.warn('未知の変更アクション', { action });
651
666
  break;
652
667
  }
653
668
  }
654
669
 
670
+ //|
671
+ //| thinnedindices — サマリーに書き出す件数の制御
672
+ //| 省略したキーは POKER の既定値が使われる。既定値は持たない
673
+ //| (.summary に全 7 キーが出力されるので、そちらを正とする)。
674
+ //|
675
+ async applyProposeThinnedIndices(data) {
676
+ if (this.data.thinnedindices) {
677
+ throw new DataError('thinnedindices セクションは既に存在します',
678
+ 'THINNEDINDICES_ALREADY_EXISTS');
679
+ }
680
+ this.data.thinnedindices = { ...data };
681
+ logger.info('thinnedindices を作成しました', { data });
682
+ }
683
+
684
+ async applyUpdateThinnedIndices(data) {
685
+ // 無ければ作る(update で新規作成も許す。削除ツールが無いので、
686
+ // 既定値に戻したい場合もこのメソッドを通る)
687
+ this.data.thinnedindices = { ...(this.data.thinnedindices || {}), ...data };
688
+ logger.info('thinnedindices を更新しました', { data: this.data.thinnedindices });
689
+ }
690
+
655
691
  // Unit専用処理メソッド
656
692
  async applyProposeUnit(data) {
657
693
  try {