mystery-reasoning-connector v0.1

STEP: 1538 / Test: 43/43 PASS / 姉妹: puzzle-verifier (STEP 1536) / Type: 推理探偵コネクタ (端子/チップ/回路/マシン)

藤本さん directive (2026-08-29):
「推理、探偵のコネクタ用ツール、端子、チップ、回路、マシンはどうでしょうか? これは作る価値があると思います。ゲーミフィケーションと違って、推理は形式化できるからです。」

パズル側 (STEP 1536) と姉妹、 回路の向きが逆: puzzle は生成器が解を先に持ち fields を hide、 mystery は事実 → 結論への推論連鎖そのものが回路。 生成器 (マシン) は犯人を先に決め、 逆算で手掛かりを配置。

検証器 2 条件: (a) uniqueness = 犯人一意 (fair-play も同時に拾う) / (b) necessity = 冗長な手掛かりが無い (推理が骨抜きにならない)。 両方満たしたものだけ 「well-posed」 として出題可能。

narrative layer を必ず挟む (藤本さん warning への直接応答): raw chip output は味気ないので、 「火災の14分前に通報した人物がいた」 型の物語断片に prose 化。 renderNarrative(report) で 事件初期提示 → 推理展開 → 結論の 3 節を Markdown で出力。

anti-repetition (Jaccard): 直前 N 事件の chip 組合せと Jaccard 類似度を計算、 threshold 超えは 「またこのパターンか」 予防のため 別 chip set に振り直す指標を返す。

4 component 対応

藤本さん指定本 module役割
端子 (terminal)Fact { type: FactType }時刻 / 人物 / 場所 / 証言 / 記録 の 5 型
チップ (chip)ReasoningChip (5 個)contradiction / timeline / alibi / elimination / common_feature
回路 (circuit)runCircuit(spec)初期 fact から犯人確定への推論連鎖 (chip の順次適用)
マシン (event generator)generateMystery(suspects, truth, chips)真相を先に決め 逆算で fact を配置、 冗長 fact を iterative trim
検証器verifyMystery(spec)uniqueness (犯人一意) + necessity (冗長ゼロ) の 2 条件検証
narrative layerrenderNarrative(report)回路 → 物語断片への prose 化 (味気ない chip output 対策)

検証器 uniqueness 4 outcome

outcome意味診断
UNIQUE_CORRECTちょうど 1 人残り、 expectedCulprit と一致well-posed 候補 (necessity 次第)
UNIQUE_WRONG1 人残るが expected と不一致生成器バグ (逆算式が誤り)
MULTIPLE>1 人残る手掛かり不足 or fair-play violation (後出しがなければ絞れる想定が崩れた)
NONE全員消去事実が矛盾しているか消去法が過剰

必要性検査 (necessity) の骨

for (const f of providedFacts) {
  const trimmed = { ...spec, providedFacts: providedFacts.filter(x => x.id !== f.id) };
  const report = verifyMystery(trimmed);
  if (report.uniqueness.outcome === 'UNIQUE_CORRECT') {
    redundantFactIds.push(f.id);  // この fact なしでも一意 → 冗長
  }
}

各 fact を一つずつ抜いて全体を再検証。 抜いても一意性が保たれる fact は「無くても解ける」 = 冗長。 藤本さん指摘 「余分な手掛かりが無いか」 の機械的判定。

使用例

const suspects = [
  { id: 'A', name: '田中', attributes: { leftHanded: false, mustHaveBeenAt: 'bar', mustHaveBeenTime: 14 } },
  { id: 'B', name: '佐藤', attributes: { leftHanded: true } },
  { id: 'C', name: '木村', attributes: { leftHanded: true, mustHaveBeenAt: 'station', mustHaveBeenTime: 14 } },
];

const spec = {
  suspects,
  providedFacts: [
    { id: 'f1', type: 'person', subject: 'CULPRIT', predicate: 'has_attribute',
      value: { attribute: 'leftHanded', polarity: true } },       // 田中を消去 (右利き)
    { id: 'f2', type: 'record', subject: 'station', predicate: 'captured_at',
      value: { medium: '監視カメラ', captured: 'C', time: 14 } }, // 木村のアリバイ成立
  ],
  expectedCulprit: 'B',
  chips: ['alibi', 'elimination'],
  title: '書斎の事件',
};

const report = verifyMystery(spec);
// report.uniqueness.outcome === 'UNIQUE_CORRECT'
// report.necessity.outcome  === 'ALL_NECESSARY'
// report.wellPosed          === true

console.log(renderNarrative(report));

renderNarrative 出力例

# 書斎の事件

## 事件の初期提示
- 犯人 は 左利きである。
- station の 監視カメラ に 14 時点で C が記録されていた。

## 推理の展開
- 木村 は 14 時に station にいたことが 監視カメラ に映っており、 アリバイが成立し容疑から外れる。
- 犯人は左利きのはずだが、 田中 は該当しないため除外される。

## 結論
犯人は **佐藤** で確定した。
すべての手掛かりが結論に不可欠であり、 冗長な情報は無い。

マシン (backward generator)

const truth = {
  culpritId: 'B',
  time: 14,
  crimeScene: 'study',
  distinguishingAttributes: [{ attribute: 'leftHanded', polarity: true }],
};

const { spec, report, repetitionScore } = generateMystery(
  suspects, truth, ['alibi', 'elimination'],
  { recentChipSets: [['alibi', 'elimination'], ['contradiction', 'timeline']] },
);
// report.wellPosed === true (by construction, iterative trim 適用済み)
// repetitionScore = max Jaccard against recentChipSets → 1.0 (完全一致 = 別 chip set 推奨)

Test 43/43

SectionTestAssertions
1Basic 3-suspect well-posed4
2MULTIPLE — fair-play violation (missing clue)3
3REDUNDANT_FACTS — 冗長 fact 検出4
4NONE — over-elimination2
5UNIQUE_WRONG — 生成器バグ検出2
6narrative fragments (renderNarrative)5
7Backward machine (well-posed by construction)4
8Anti-repetition (Jaccard)3
9contradiction chip narrative-only (no elimination in v0.1)4
10common_feature AND-summary narrative2
11runCircuit direct API2
12Single-suspect edge case2
13Invalid: expectedCulprit not in suspects1
14fair-play condition (missing key fact detected)2
15Narrative fallback (no fragments)1
16Chip ordering independence2

puzzle-verifier (STEP 1536) との比較

次元puzzle-verifiermystery-reasoning-connector (本)
回路の向き解 → hide → solver enumerate事実 → chip → 結論 (forward reasoning)
生成器tool + partial input + hidden fields真相 (culprit + attributes) → 逆算 fact 配置
検証器 (a)UNIQUE (hidden field の完成が一意)UNIQUE_CORRECT (残 suspect が犯人と一致)
検証器 (b)ALL_NECESSARY (各 fact を抜くと一意崩れる)
narrative layer回路 → 物語断片 (5 chip × 名詞句 template)
anti-repetitionJaccard against recentChipSets

藤本さん warning への応答

Honest scope