Skill: greatxiaory/yi-shi-wei-jian (version 0.1.4)

--- name: yi-shi-wei-jian description: Use when the user says 请用/使用/调用 以史为鉴 skill, yi-shi-wei-jian, 借古鉴今, 历史类比, 中国历史案例, or 沙盘推演. Also use for realistic decision questions even when history is not mentioned: 判断当前是什么局、破局/布局, organization/business/team strategy, reform blocked, internal conflict, weak-vs-strong competition, unstable alliance/cooperation trust risk, control-right disputes, leadership/personnel replacement, attack-or-defense timing, and adding sourced historical cases. Output 【局面判断】【历史参照】【关键变量】【可选路径】【沙盘推演】【借鉴原则】【边界提醒】. homepage: https://github.com/GreatXiaoRY/LearnFromHistory-skill user-invocable: true metadata: {"display_name":"以史为鉴","repo_name":"LearnFromHistory-skill","slug":"yi-shi-wei-jian","language":"zh-CN","version":"0.1.4","tags":["history","chinese-history","decision-support","historical-analogy","sandbox-simulation","strategy","zh-CN"],"openclaw":{"always":false,"homepage":"https://github.com/GreatXiaoRY/LearnFromHistory-skill","skillKey":"yi-shi-wei-jian"}} --- # 以史为鉴 把现实决策问题转成“局面判断 -> 历史映射 -> 路径设计 -> 沙盘推演”的结构化分析，而不是做历史百科、哲学闲聊或宿命论判断。 本 skill 的主工作流应当是：由宿主 agent 直接阅读案例库与提示文件，按结构语义做判断。`src/main.py` 只是本地 fallback 基线，不应取代宿主 agent 的语义推理。 ## 触发条件 在下列场景优先使用本 skill： - 用户正在问“该不该推进、该先稳内部还是先上制度、该先打还是先守、该不该换人、该不该和不完全信任的合作方结盟、改革为什么推不动、资源弱势如何破局” - 用户想借历史案例理解组织管理、商业竞争、联盟博弈、内部权力冲突、改革阻力、扩张节奏 - 用户明确提到“以史为鉴”“用中国历史类比”“帮我做沙盘推演” - 用户明确要求“把这个案例加入案例库”“补充一个新历史案例”“把我刚说的这个历史经验沉淀下来供以后检索” - 用户虽然没提历史，但问题本质是在问“现在是什么局”“能借什么结构性经验”“不同路径会怎么演化” 在下列场景不要触发或只部分借用： - 用户只是要纯历史知识问答 - 用户要求命理、算命、绝对预测 - 用户要法律、医疗、投资等高风险确定性结论 ## 输入解析 先从用户问题里抽取这 7 类信息： 1. 当前目标：你到底想赢什么，守什么，改什么 2. 主要对手：比你强还是比你弱，明面冲突还是暗线制衡 3. 自身资源：钱、人、时间、组织控制力、合法性 4. 内部状态：是否统一，是否有人拖后腿，是否存在派系 5. 外部关系：盟友、股东、合作方、上级、地方势力是否稳定 6. 时间窗口：是否必须立即行动，是否可以拖延、试点、换节奏 7. 约束条件：不能公开冲突、不能失去名分、不能丢现金流、不能让核心团队失控 如果这些信息明显缺失，先问 1-3 个关键澄清问题；如果用户不想补充，就在输出中显式标注你的假设。 ## 语义分析原则 优先做“结构语义理解”，不要先做“字面关键词命中”。分析时至少先判断这些维度： - 资源强弱 - 内部摩擦 - 外部压力 - 联盟依赖程度 - 信任风险 - 变革强度 - 控制权压力 - 用人调整压力 - 时间压力 - 合法性压力 - 执行阻力 - 行动取向：更偏推进、稳局、结盟，还是调权换人 只有在宿主需要确定性兜底时，才调用本地 CLI。即使调用 CLI，也应把它看成结构化基线，而不是最终权威答案。 ## 分类规则 优先把局面归入 1 个主局面，再给 1-2 个次级局面： - `以弱对强`：资源、地位、市场份额或正式权威明显弱于对手 - `内部冲突`：团队、派系、股东、盟友之间出现分裂与掣肘 - `改革推进`：制度调整、流程重构、组织变法、利益再分配 - `联盟不稳`：合作关系短期有效，但长期目标并不一致 - `守攻抉择`：到底先守基本盘，还是主动出击创造新局面 - `权力控制`：控制权、任命权、接班、军权、组织中枢的归属 - `用人换将`：是否换人、空降、授权、剥离关键岗位 优先判断“结构相似性”，不要把“同一个词”误当成“同一个局”。 ## 检索规则 1. 先读 `data/historical_cases.json`，再合并读取 `data/user_cases.json` 2. 以 `situation_tags`、`objective`、`hidden_constraints`、`chosen_action`、`key_reasons` 的结构语义为主做匹配，`modern_analogy_keywords` 只是辅助 3. 选 2-4 个最相似案例，优先选择“结构接近但结果不同”的案例组合；若合适，至少给 1 个失败或代价过高的对照案例 4. 每个案例必须交代： - 事件 - 核心局面 - 关键决策 - 成败原因 5. 最少用一句话说明“为什么这个案例像当前问题”，尤其要指出约束条件、权力结构、资源状态、时间压力上的相似性 6. 不要只因为案例著名就选它；要优先选择与用户约束最像的 如果需要确定性基线，可运行本地 CLI： - Claude Code 路径变量：`python "${CLAUDE_SKILL_DIR}/src/main.py" --question "$ARGUMENTS"` - OpenClaw 路径变量：`python "{baseDir}/src/main.py" --question "<用户问题>"` 调用 CLI 后，不要机械复述 CLI 输出；应结合案例文本和用户上下文再做一次语义整理。 ## 案例扩充 如果用户提供了一个新的历史案例，并明确希望后续检索也能用到它，不要只在当前回答里临时引用。按下面流程处理： 1. 先判断用户是不是在要求“把新案例加入库”，而不只是临时举例 2. 如果信息不完整，先追问 1-3 个关键缺口，优先补齐： - 事件概述 - 关键决策 - 成败原因 - 可迁移原则 - 来源说明 3. 把用户的自然语言描述整理成单条 JSON，对照模板 `examples/case_submission_template.json` 4. 优先直接通过标准输入写入，而不是把责任丢回给用户手工改文件： - PowerShell：`@'<json>'@ | python scripts/add_case.py --stdin` - 或：`python scripts/add_case.py --case-json '<json>'` - 或：`python scripts/add_case.py --case-file <json 文件路径>` 5. 写入目标是 `data/user_cases.json` 6. 成功后明确告诉用户新案例的 `id`，并说明后续检索会自动加载 如果用户只给了模糊描述，先帮他补齐以下内容再入库： - 事件概述 - 核心局面 - 关键决策 - 成败原因 - 可迁移原则 - 不可直接照搬的因素 - 来源说明 最低入库质量要求： - 必须是真实历史案例，不能是虚构或模糊传说 - `id` 必须唯一 - `source_note` 不能为空 - `summary`、`chosen_action`、`key_reasons`、`transferable_principles` 不能空 - `situation_tags` 要尽量贴近本 skill 的分类体系 ## 推演规则 生成 2-4 条彼此不同的可选路径，而不是同一策略的改写版。常见路径包括： - 立即推进 - 先稳内部 - 暂避锋芒 - 联盟博弈 - 换将整队 - 试点改革 对每条路径都必须分析： - 适用条件 - 短期收益 - 短期风险 - 中期演化 - 最容易失败点 如果用户问题明显涉及“中层拖延、合作方翻脸、负责人是否要换、控制权被架空、资源比对手更弱”，优先让路径名称直接回应这些现实语句，而不是写得过泛。 推演时优先围绕这些变量： - 资源 - 内部一致性 - 对手状态 - 联盟稳定性 - 时间窗口 - 合法性 ## 输出模板 最终输出必须固定为以下结构： ```text 【局面判断】 【历史参照】 【关键变量】 【可选路径】 【沙盘推演】 【借鉴原则】 【边界提醒】 ``` 要求： - `【历史参照】` 输出 2-4 个案例 - `【可选路径】` 输出 2-4 条路径 - `【沙盘推演】` 必须逐路径展开，不能省略 - `【借鉴原则】` 提炼可复用规则，不要只复述历史 ## 安全边界 始终保留以下边界： - 历史类比 != 现实预测 - 推演 != 结果保证 - 历史人物、制度、地理与技术条件不可直接照搬 - 不给“必胜”“一定成功”“唯一正确路线”这类绝对结论 - 如果用户问题属于高风险专业场景，只能给结构化思考框架，不能冒充专业意见 - 本 skill 不需要 `always` 常驻权限；只在用户触发决策分析或明确要求补充案例时使用。写入能力仅限本 skill 目录下的 `data/user_cases.json`。 ## 附加资源 - 局面分类提示：`prompts/classify_situation.md` - 案例检索提示：`prompts/retrieve_cases.md` - 案例比较提示：`prompts/compare_cases.md` - 案例入库提示：`prompts/add_case_intake.md` - 方案综合提示：`prompts/synthesize_advice.md` - 沙盘推演提示：`prompts/sandbox_simulation.md` - 安全边界提示：`prompts/safety_boundary.md` - 可运行分析引擎：`src/main.py` - 示例：`examples/`

path: data/cases.schema.json
content: {
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "LearnFromHistoryCase",
  "type": "array",
  "minItems": 40,
  "items": {
    "type": "object",
    "required": [
      "id",
      "title",
      "dynasty",
      "era",
      "year_range",
      "main_figures",
      "summary",
      "situation_tags",
      "decision_maker",
      "objective",
      "visible_information",
      "hidden_constraints",
      "options_available",
      "chosen_action",
      "short_term_outcome",
      "long_term_outcome",
      "success_or_failure",
      "key_reasons",
      "transferable_principles",
      "non_transferable_factors",
      "modern_analogy_keywords",
      "source_note"
    ],
    "properties": {
      "id": { "type": "string", "pattern": "^[a-z0-9-]+$" },
      "title": { "type": "string", "minLength": 1 },
      "dynasty": { "type": "string", "minLength": 1 },
      "era": { "type": "string", "minLength": 1 },
      "year_range": { "type": "string", "minLength": 1 },
      "main_figures": {
        "type": "array",
        "minItems": 1,
        "items": { "type": "string" }
      },
      "summary": { "type": "string", "minLength": 1 },
      "situation_tags": {
        "type": "array",
        "minItems": 1,
        "items": { "type": "string" }
      },
      "decision_maker": { "type": "string", "minLength": 1 },
      "objective": { "type": "string", "minLength": 1 },
      "visible_information": {
        "type": "array",
        "minItems": 1,
        "items": { "type": "string" }
      },
      "hidden_constraints": {
        "type": "array",
        "minItems": 1,
        "items": { "type": "string" }
      },
      "options_available": {
        "type": "array",
        "minItems": 2,
        "items": { "type": "string" }
      },
      "chosen_action": { "type": "string", "minLength": 1 },
      "short_term_outcome": { "type": "string", "minLength": 1 },
      "long_term_outcome": { "type": "string", "minLength": 1 },
      "success_or_failure": {
        "type": "string",
        "enum": ["success", "failure", "mixed"]
      },
      "key_reasons": {
        "type": "array",
        "minItems": 1,
        "items": { "type": "string" }
      },
      "transferable_principles": {
        "type": "array",
        "minItems": 1,
        "items": { "type": "string" }
      },
      "non_transferable_factors": {
        "type": "array",
        "minItems": 1,
        "items": { "type": "string" }
      },
      "modern_analogy_keywords": {
        "type": "array",
        "minItems": 1,
        "items": { "type": "string" }
      },
      "source_note": { "type": "string", "minLength": 1 }
    },
    "additionalProperties": false
  }
}


path: data/historical_cases.json
content: [
  {
    "id": "qin-shang-yang-reform",
    "title": "秦孝公任用商鞅变法",
    "dynasty": "战国·秦",
    "era": "战国中期",
    "year_range": "前356年-前350年",
    "main_figures": ["秦孝公", "商鞅"],
    "summary": "秦国面对东方六国竞争，在相对弱势局面下，以两轮变法重塑军政与财政结构。",
    "situation_tags": ["改革推进", "以弱对强", "合法性"],
    "decision_maker": "秦孝公",
    "objective": "用制度重构提升秦国长期竞争力。",
    "visible_information": ["秦国国力弱于山东六国", "旧贵族阻力可预见", "君主支持改革"],
    "hidden_constraints": ["变法初期社会成本高", "贵族利益受损会强烈反扑", "改革必须连续执行才能见效"],
    "options_available": ["守旧缓改", "局部试点", "全面推行变法"],
    "chosen_action": "连续推行重农战、军功爵、县制等深层制度改革。",
    "short_term_outcome": "国内震荡明显，但军政效率和征发能力迅速提升。",
    "long_term_outcome": "秦国综合实力上升，为后续统一六国奠定制度基础。",
    "success_or_failure": "success",
    "key_reasons": ["获得最高决策者持续背书", "奖惩机制与国家目标强绑定", "改革不止停留在口号而是落到组织结构"],
    "transferable_principles": ["弱势组织的翻盘往往靠制度升级，而不是只靠一两次战术胜利", "改革必须把激励、纪律和执行链一起改"],
    "non_transferable_factors": ["秦国君权高度集中", "战国军事化竞争环境与现代组织不同"],
    "modern_analogy_keywords": ["改革", "制度重构", "组织变革", "奖惩机制", "弱势翻盘"],
    "source_note": "《史记·商君列传》"
  },
  {
    "id": "hongmen-banquet",
    "title": "项羽鸿门宴失机",
    "dynasty": "秦汉之际",
    "era": "楚汉相争前夜",
    "year_range": "前206年",
    "main_figures": ["项羽", "刘邦", "范增", "项伯"],
    "summary": "项羽面对先入关中的刘邦，在联盟格局尚未稳固时错失清除主要对手的窗口。",
    "situation_tags": ["权力控制", "联盟不稳", "内部冲突"],
    "decision_maker": "项羽",
    "objective": "处理刘邦的潜在威胁，并维持自己在诸侯中的主导地位。",
    "visible_information": ["刘邦先入关中", "范增主张立刻除掉刘邦", "诸侯联盟名义上仍尊项羽"],
    "hidden_constraints": ["项伯与张良私交牵制决策", "项羽统合能力不如个人威望强", "过早翻脸可能引发联盟裂痕"],
    "options_available": ["立刻诛杀刘邦", "羞辱后放回", "暂时安抚再逐步削弱"],
    "chosen_action": "在犹豫中放走刘邦，没有完成清除关键对手的动作。",
    "short_term_outcome": "表面避免了宴会现场的公开决裂。",
    "long_term_outcome": "刘邦得以回到根据地，最终在楚汉战争中击败项羽。",
    "success_or_failure": "failure",
    "key_reasons": ["在关键窗口期犹豫", "没有把威胁识别与执行动作闭环", "内部意见分裂削弱了决断"],
    "transferable_principles": ["面对决定性威胁时，犹豫本身就是一种高成本选择", "大联盟中的主导者必须把内部共识先做实，再处理外部对手"],
    "non_transferable_factors": ["楚汉之际的生死斗争环境远比现代组织更极端", "古代宴会式政治博弈带有强烈人身依附关系"],
    "modern_analogy_keywords": ["控制权", "窗口期", "关键对手", "联盟裂痕", "犹豫失机"],
    "source_note": "《史记·项羽本纪》"
  },
  {
    "id": "liubang-three-laws",
    "title": "刘邦入关约法三章",
    "dynasty": "秦汉之际",
    "era": "楚汉相争前夜",
    "year_range": "前206年",
    "main_figures": ["刘邦", "萧何", "张良"],
    "summary": "刘邦率军先入关中后，没有乘机大肆掠夺，而是以简法安民、封存府库换取政治正当性。",
    "situation_tags": ["合法性", "联盟不稳", "守攻抉择"],
    "decision_maker": "刘邦",
    "objective": "在实力未稳时先稳住关中民心与政治名分。",
    "visible_information": ["秦法苛严，关中百姓厌秦", "项羽兵力和威望更高", "刘邦兵锋已先入关"],
    "hidden_constraints": ["实力尚不足以立刻与项羽决战", "需要地方支持与后勤保障", "过度掠夺会失去正当性"],
    "options_available": ["纵兵掠夺", "沿用秦法高压统治", "简法安民并封存府库"],
    "chosen_action": "宣布约法三章，封存府库，还军霸上。",
    "short_term_outcome": "迅速收拢民心，减少关中抵触情绪。",
    "long_term_outcome": "为刘邦后续争取关中基础与政治合法性提供重要条件。",
    "success_or_failure": "success",
    "key_reasons": ["先争合法性而不是先抢战利品", "懂得在弱势阶段控制贪婪与短期冲动", "把地方支持变成可持续资源"],
    "transferable_principles": ["资源暂时不占优时，合法性和秩序往往比短期收益更值钱", "入局初期先稳基本盘，胜过急于兑现所有好处"],
    "non_transferable_factors": ["乱世军事占领与现代组织接管并不等价", "关中民心与封建政治名分具有时代特殊性"],
    "modern_analogy_keywords": ["接盘", "合法性", "安抚团队", "稳住基本盘", "不抢短期利益"],
    "source_note": "《史记·高祖本纪》"
  },
  {
    "id": "hanxin-secret-route",
    "title": "韩信明修栈道暗度陈仓",
    "dynasty": "西汉初年",
    "era": "楚汉战争",
    "year_range": "前206年",
    "main_figures": ["韩信", "刘邦"],
    "summary": "汉军被迫退守汉中后，通过佯动作战制造误判，再从陈仓突击东出关中。",
    "situation_tags": ["以弱对强", "守攻抉择", "联盟不稳"],
    "decision_maker": "韩信",
    "objective": "在资源尚未恢复完备的情况下重新进入战略要地关中。",
    "visible_information": ["正面通道受控", "汉军士气待振", "楚方注意力被其他方向牵制"],
    "hidden_constraints": ["不能长期困守汉中", "需要制造对手误判", "突击成功后还要迅速接续推进"],
    "options_available": ["正面强攻", "继续固守汉中", "以佯动掩护奇袭陈仓"],
    "chosen_action": "公开修复栈道吸引注意，实际由陈仓突入关中。",
    "short_term_outcome": "迅速夺回战略主动，打开东出局面。",
    "long_term_outcome": "为汉军扩大根据地、反攻楚军提供关键跳板。",
    "success_or_failure": "success",
    "key_reasons": ["识别了真正的突破点", "通过假动作重塑对手判断", "有限资源集中在单点突击"],
    "transferable_principles": ["弱势方不要全面对撞，要创造局部不对称", "佯动的价值在于重构对手预期，而不是自我感动"],
    "non_transferable_factors": ["古代地理险关与现代商业地形不同", "军事奇袭的速度优势难以直接平移到现代治理场景"],
    "modern_analogy_keywords": ["奇袭", "资源集中", "假动作", "逆袭", "突破口"],
    "source_note": "《史记·淮阴侯列传》"
  },
  {
    "id": "kunyang-battle",
    "title": "刘秀昆阳之战",
    "dynasty": "新末汉初",
    "era": "更始政权初期",
    "year_range": "23年",
    "main_figures": ["刘秀", "王邑", "王寻"],
    "summary": "刘秀在昆阳以少量兵力对抗王莽大军，通过坚守与外线突击相结合完成以少胜多。",
    "situation_tags": ["以弱对强", "守攻抉择", "联盟不稳"],
    "decision_maker": "刘秀",
    "objective": "阻止新朝主力摧毁起义军核心力量。",
    "visible_information": ["敌军兵力远超己方", "守军士气不稳", "城池一旦失守会造成连锁溃败"],
    "hidden_constraints": ["不能单靠死守", "盟军支持并不稳固", "需要短时间制造士气逆转"],
    "options_available": ["弃城撤退", "固守待援", "小股外出袭扰并配合城内坚守"],
    "chosen_action": "刘秀率小股精兵出城求援并扰乱敌军，城内外夹击取胜。",
    "short_term_outcome": "王莽军心动摇，围城态势被打破。",
    "long_term_outcome": "刘秀威望大增，为东汉建立积累政治与军事资本。",
    "success_or_failure": "success",
    "key_reasons": ["用有限兵力打敌军心理与节奏", "把守与攻结合，而不是二选一", "胜利具有强烈示范效应"],
    "transferable_principles": ["弱势方应争取局部胜利与士气逆转的复合效果", "守势中也要设计主动动作，不能被动等待"],
    "non_transferable_factors": ["战场围城环境具有高度即时性", "军事胜负对政治合法性的放大效应很强"],
    "modern_analogy_keywords": ["以少胜多", "守中带攻", "扭转士气", "窗口战役", "逆风翻盘"],
    "source_note": "《后汉书·光武帝纪》"
  },
  {
    "id": "zhou-yafu-seven-states",
    "title": "周亚夫平七国之乱",
    "dynasty": "西汉",
    "era": "景帝时期",
    "year_range": "前154年",
    "main_figures": ["周亚夫", "汉景帝", "吴王刘濞"],
    "summary": "面对七国叛乱与梁国求援压力，周亚夫没有急于正面决战，而是先断叛军粮道。",
    "situation_tags": ["内部冲突", "守攻抉择", "权力控制"],
    "decision_maker": "周亚夫",
    "objective": "平定叛乱并维护中央权威。",
    "visible_information": ["叛军来势汹汹", "梁国被围引发朝廷焦躁", "朝中主张速战声音很大"],
    "hidden_constraints": ["仓促决战风险高", "叛军后勤链较脆弱", "主帅必须承受政治压力"],
    "options_available": ["立刻驰援梁国决战", "坚守拖延", "绕开主战场先断粮道"],
    "chosen_action": "坚壁清野，避其锋芒，集中切断吴楚粮道。",
    "short_term_outcome": "短期承受巨大政治压力，但避免了主力冒险决战。",
    "long_term_outcome": "叛军因粮尽势竭而败，中央权威得到强化。",
    "success_or_failure": "success",
    "key_reasons": ["抓住对手补给脆弱点", "不被高压环境裹挟去做错误动作", "将军有足够定力执行不讨好的正确方案"],
    "transferable_principles": ["关键时刻要识别决定胜负的约束，而不是盯着最热闹的战场", "在高压舆论下坚持正确节奏，本身就是领导能力"],
    "non_transferable_factors": ["古代战争粮道决定性极强", "皇权体制下主帅与皇帝的关系不同于现代治理结构"],
    "modern_analogy_keywords": ["内部叛乱", "断对手补给", "不要被催战", "高压决策", "稳节奏"],
    "source_note": "《史记·绛侯周勃世家》"
  },
  {
    "id": "guandu-battle",
    "title": "曹操官渡之战",
    "dynasty": "东汉末",
    "era": "群雄割据",
    "year_range": "200年",
    "main_figures": ["曹操", "袁绍", "许攸"],
    "summary": "曹操在兵力处于劣势的情况下，通过稳守、侦察与突然袭击乌巢扭转了北方格局。",
    "situation_tags": ["以弱对强", "守攻抉择", "权力控制"],
    "decision_maker": "曹操",
    "objective": "击败袁绍主力，争夺北方主导权。",
    "visible_information": ["袁绍兵多粮足", "曹操后方并不绝对稳定", "长期相持对己不利"],
    "hidden_constraints": ["不能全面消耗", "必须找到决定性单点", "内部需要一场明确胜利稳定预期"],
    "options_available": ["全面决战", "长期死守", "稳守中寻机打对方粮仓"],
    "chosen_action": "坚守官渡，同时抓住许攸情报，突袭乌巢粮仓。",
    "short_term_outcome": "袁绍军粮被毁，军心瓦解。",
    "long_term_outcome": "曹操奠定统一北方的基础。",
    "success_or_failure": "success",
    "key_reasons": ["识别对方真正命门", "把有限兵力集中到决定性目标", "在守势中保留主动突击能力"],
    "transferable_principles": ["强弱对抗时，胜负常取决于关键节点而非总量", "情报与时机一旦出现，动作必须足够果断"],
    "non_transferable_factors": ["军事后勤体系与现代市场竞争不同", "个人统兵权在古代战争中作用更直接"],
    "modern_analogy_keywords": ["弱势竞争", "关键节点", "情报", "资源集中", "逆袭强敌"],
    "source_note": "《三国志·武帝纪》"
  },
  {
    "id": "red-cliffs-alliance",
    "title": "孙刘联盟赤壁抗曹",
    "dynasty": "东汉末",
    "era": "三国形成前夜",
    "year_range": "208年",
    "main_figures": ["孙权", "周瑜", "刘备", "诸葛亮", "曹操"],
    "summary": "孙权在强敌南下时选择与刘备结盟，以局部协同对抗更强大的曹操集团。",
    "situation_tags": ["联盟不稳", "以弱对强", "守攻抉择"],
    "decision_maker": "孙权",
    "objective": "阻止曹操顺江东下，一举吞并江东。",
    "visible_information": ["曹操兵力与名望占优", "刘备虽弱但有抗曹意愿", "江东内部主降主战并存"],
    "hidden_constraints": ["孙刘联盟基础脆弱", "战后利益分配必有冲突", "若不结盟则各个击破概率高"],
    "options_available": ["投降曹操", "独自应战", "与刘备结盟共同抗曹"],
    "chosen_action": "压下主降意见，与刘备结盟，在赤壁发动火攻。",
    "short_term_outcome": "击退曹操南征主力，保住江东基本盘。",
    "long_term_outcome": "三国鼎立格局初步形成，但孙刘联盟也埋下后续裂痕。",
    "success_or_failure": "success",
    "key_reasons": ["识别共同敌人足够强大", "主战派拿出可执行的作战方案", "联盟虽脆弱但在关键窗口期足够有效"],
    "transferable_principles": ["联盟不要求永久一致，只要求在关键窗口期形成足够协同", "结盟时要同时考虑战后分配与退出机制"],
    "non_transferable_factors": ["江东水战优势属于地理条件红利", "古代诸侯联盟的背盟成本与现代合作不同"],
    "modern_analogy_keywords": ["联盟", "共同敌人", "抗强敌", "短期协同", "合作不稳", "合作方", "不完全信任", "翻脸", "背刺", "联合对抗头部竞争者"],
    "source_note": "《三国志·吴主传》"
  },
  {
    "id": "gaopingling-coup",
    "title": "司马懿高平陵政变",
    "dynasty": "曹魏",
    "era": "三国时期",
    "year_range": "249年",
    "main_figures": ["司马懿", "曹爽", "曹芳"],
    "summary": "司马懿利用曹爽离开洛阳祭陵的窗口，迅速控制中枢并完成权力逆转。",
    "situation_tags": ["权力控制", "内部冲突", "用人换将"],
    "decision_maker": "司马懿",
    "objective": "重新掌握曹魏中枢决策权，清除政治对手。",
    "visible_information": ["曹爽专权引发不满", "司马懿被外界认为老病退居", "皇帝仍在名义上居中"],
    "hidden_constraints": ["若先泄露意图会被先手清除", "必须同时拿住宫城、兵权和诏令", "事后还需构造合法性叙事"],
    "options_available": ["继续隐忍等待", "公开争权", "抓住窗口迅速政变"],
    "chosen_action": "趁曹爽出城祭陵，迅速控制洛阳中枢并迫使其交权。",
    "short_term_outcome": "曹爽集团迅速失势，司马氏重新掌握中枢。",
    "long_term_outcome": "为司马氏取代曹魏奠定政治基础。",
    "success_or_failure": "success",
    "key_reasons": ["窗口识别精准", "动作集中在关键控制点", "名义合法性包装与实际兵权控制同步完成"],
    "transferable_principles": ["控制权争夺的核心在于关键节点和执行速度", "正式名分与实际控制必须同时处理，不能只占其一"],
    "non_transferable_factors": ["宫廷政变属于高风险暴力场景", "古代禁军与诏令体系不可直接类比现代组织"],
    "modern_analogy_keywords": ["控制权", "窗口期", "夺权", "中枢控制", "快速定局", "削权", "被架空", "先拿关键岗位", "先控流程再换人"],
    "source_note": "《资治通鉴》卷七十五"
  },
  {
    "id": "xuanwu-gate",
    "title": "李世民玄武门之变",
    "dynasty": "唐",
    "era": "唐初",
    "year_range": "626年",
    "main_figures": ["李世民", "李建成", "李元吉", "唐高祖"],
    "summary": "李世民在储位斗争僵持、风险不断上升时，选择在玄武门先发制人，迅速改写继承格局。",
    "situation_tags": ["权力控制", "内部冲突", "守攻抉择"],
    "decision_maker": "李世民",
    "objective": "打破储位斗争僵局并掌握继承主动权。",
    "visible_information": ["太子与齐王联手牵制李世民", "双方矛盾公开化", "继续拖延会增加被动风险"],
    "hidden_constraints": ["必须同时说服或压制皇帝", "动作失败即身家性命俱失", "事后需稳定朝局与名义秩序"],
    "options_available": ["继续隐忍", "公开争储", "先发制人迅速定局"],
    "chosen_action": "在玄武门设伏诛杀主要对手，随后控制局势。",
    "short_term_outcome": "储位斗争被迅速终结。",
    "long_term_outcome": "李世民即位，开启贞观之治。",
    "success_or_failure": "success",
    "key_reasons": ["识别拖延的成本已高于行动成本", "行动目标集中且节奏极快", "后续稳定秩序能力强于单纯夺权"],
    "transferable_principles": ["有些权力僵局拖下去只会恶化，必须评估何时由守转攻", "定局之后还要能稳定秩序，否则只是赢了第一回合"],
    "non_transferable_factors": ["宫廷继承斗争与现代组织治理存在本质差异", "成败高度依赖个人武装与皇权结构"],
    "modern_analogy_keywords": ["继承", "先发制人", "权力僵局", "控制权", "关键对手"],
    "source_note": "《旧唐书·太宗本纪》"
  },
  {
    "id": "zhao-kuangyin-cup-of-wine",
    "title": "赵匡胤杯酒释兵权",
    "dynasty": "北宋",
    "era": "宋初",
    "year_range": "961年",
    "main_figures": ["赵匡胤", "石守信", "高怀德"],
    "summary": "赵匡胤在陈桥兵变即位后，没有继续容忍禁军宿将掌握过强兵权，而是以柔性方式解除其军权。",
    "situation_tags": ["权力控制", "内部冲突", "合法性"],
    "decision_maker": "赵匡胤",
    "objective": "在不激化公开冲突的情况下收回军权，稳定新政权。",
    "visible_information": ["禁军将领资历深厚", "新朝合法性仍需巩固", "直接清洗可能引发军心不稳"],
    "hidden_constraints": ["不能让军中形成被逼反心理", "需要给将领体面退场路径", "收权后还要重建制度安排"],
    "options_available": ["强行清洗", "放任旧将继续掌权", "以安抚和利益置换逐步收权"],
    "chosen_action": "通过宴饮劝退与荣养安置，解除宿将兵权。",
    "short_term_outcome": "较平稳地化解了潜在兵变风险。",
    "long_term_outcome": "宋初中央集权得到加强，但也埋下重文轻武的长期倾向。",
    "success_or_failure": "success",
    "key_reasons": ["利益置换优于正面清洗", "在收权同时提供体面退出机制", "把个人控制转化为制度安排"],
    "transferable_principles": ["处理功臣和老资格群体时，体面退出机制常比硬冲突更有效", "收权不只靠拿走权限，还要安排利益与位置"],
    "non_transferable_factors": ["宋初军政结构与现代组织差异大", "皇帝对资源与名分拥有压倒性优势"],
    "modern_analogy_keywords": ["收权", "功臣", "体面退出", "控制权", "老团队"],
    "source_note": "《宋史·太祖本纪》"
  },
  {
    "id": "wang-anshi-reform",
    "title": "王安石变法",
    "dynasty": "北宋",
    "era": "熙宁变法",
    "year_range": "1069年-1076年",
    "main_figures": ["王安石", "宋神宗", "司马光"],
    "summary": "北宋在财政军备压力下推动系统性改革，但在执行链、地方适配和政治联盟上遭遇持续反弹。",
    "situation_tags": ["改革推进", "内部冲突", "合法性"],
    "decision_maker": "王安石",
    "objective": "富国强兵，缓解财政与边防压力。",
    "visible_information": ["财政吃紧", "边防压力上升", "皇帝支持改革", "士大夫意见分化"],
    "hidden_constraints": ["地方执行能力参差不齐", "新法触动广泛利益", "改革节奏与沟通成本被低估"],
    "options_available": ["守旧不改", "局部试点缓推", "依靠最高支持大规模推进"],
    "chosen_action": "在皇帝支持下快速推出青苗法、市易法、募役法等多项新法。",
    "short_term_outcome": "财政与调度能力短期有所改善，但政治争议迅速扩大。",
    "long_term_outcome": "新法多次反复，改革成果与副作用并存，朝廷党争加剧。",
    "success_or_failure": "mixed",
    "key_reasons": ["改革方向切中问题，但联盟维护不足", "地方执行扭曲损伤了改革名声", "推进节奏快于共识建设"],
    "transferable_principles": ["改革不仅看目标正确，还看执行链是否可承受", "越是触动利益分配，越要设计缓冲、试点与反馈回路"],
    "non_transferable_factors": ["北宋士大夫政治生态高度特殊", "皇权与台谏体系的互动难以直接对应现代组织"],
    "modern_analogy_keywords": ["改革阻力", "制度变革", "利益再分配", "执行扭曲", "党争", "表面支持实则拖延", "中层拖延", "改革推不动", "制度上线阻力"],
    "source_note": "《宋史·王安石传》"
  },
  {
    "id": "chanyuan-settlement",
    "title": "寇准力主澶渊决策",
    "dynasty": "北宋",
    "era": "宋辽对峙",
    "year_range": "1004年",
    "main_figures": ["寇准", "宋真宗", "萧太后"],
    "summary": "辽军南下逼近，朝中主和主逃声音并起，寇准力主皇帝亲征稳住局面，随后再议和。",
    "situation_tags": ["守攻抉择", "合法性", "联盟不稳"],
    "decision_maker": "寇准",
    "objective": "先稳住朝局与军心，再争取可接受的谈判结果。",
    "visible_information": ["辽军逼近", "朝廷恐慌", "若皇帝南逃将军心尽失"],
    "hidden_constraints": ["宋军不宜冒险深追", "既要稳住士气也要保全国家财政", "谈与战并非绝对对立"],
    "options_available": ["南逃避战", "全面决战", "先稳住战线和士气，再谈判收场"],
    "chosen_action": "坚持皇帝亲临澶州稳军心，形成对峙后议和。",
    "short_term_outcome": "军心稳定，辽军未能进一步突破。",
    "long_term_outcome": "达成澶渊之盟，换来较长时期边境稳定。",
    "success_or_failure": "success",
    "key_reasons": ["先解决内部信心问题", "把战场姿态与谈判目标结合", "避免在恐慌中做极端选择"],
    "transferable_principles": ["守与谈可以分阶段组合，而不是非此即彼", "领导者亲自站位，有时是恢复组织信心的关键动作"],
    "non_transferable_factors": ["古代边境战争与现代商业竞争不同", "君主亲征带来的象征效应很难复制"],
    "modern_analogy_keywords": ["危机应对", "稳军心", "先守后谈", "高压决策", "守攻转换"],
    "source_note": "《宋史·寇准传》"
  },
  {
    "id": "zhang-juzheng-kaocheng",
    "title": "张居正推行考成法与财政整顿",
    "dynasty": "明",
    "era": "万历初年",
    "year_range": "1573年-1582年",
    "main_figures": ["张居正", "万历帝"],
    "summary": "张居正在幼主时代集中中枢权威，以考成法、清丈土地和一条鞭法整顿财政与执行链。",
    "situation_tags": ["改革推进", "权力控制", "合法性"],
    "decision_maker": "张居正",
    "objective": "恢复朝廷执行力并改善财政基础。",
    "visible_information": ["明廷积弊严重", "地方执行懈怠", "中枢对地方控制力下降", "皇帝年幼便于辅政"],
    "hidden_constraints": ["改革高度依赖个人权威", "一旦失势，政策可能反复", "官僚集团对高压考核有强烈抵触"],
    "options_available": ["维持旧制", "局部整顿", "集中中枢权威后系统推进考成与财政改革"],
    "chosen_action": "先强化中枢控制，再推动考成法、清丈与一条鞭法。",
    "short_term_outcome": "行政效率与财政收入明显改善。",
    "long_term_outcome": "张居正死后部分政策反复，但改革成效留下深刻影响。",
    "success_or_failure": "mixed",
    "key_reasons": ["先抓执行链再抓政策落地", "改革与中枢控制同步推进", "过度依赖个人权威导致持续性不足"],
    "transferable_principles": ["改革要先修执行系统，再修政策文本", "只靠强人推进而不制度化，后续容易反弹"],
    "non_transferable_factors": ["明代内阁与皇权结构特殊", "幼主与首辅关系并无现代组织对应物"],
    "modern_analogy_keywords": ["执行力", "绩效管理", "财政整顿", "强力改革", "制度持续性", "先抓执行链", "压实责任", "中层执行", "考核整顿"],
    "source_note": "《明史·张居正传》"
  },
  {
    "id": "kangxi-revolt-of-three-feudatories",
    "title": "康熙削三藩并平定叛乱",
    "dynasty": "清",
    "era": "康熙初年",
    "year_range": "1673年-1681年",
    "main_figures": ["康熙帝", "吴三桂", "耿精忠", "尚可喜"],
    "summary": "康熙在藩镇尾大不掉的格局下，选择冒险削藩，并在叛乱爆发后坚持平定。",
    "situation_tags": ["权力控制", "内部冲突", "守攻抉择"],
    "decision_maker": "康熙帝",
    "objective": "收回中央权力，消除长期分裂隐患。",
    "visible_information": ["三藩拥兵自重", "削藩会引发激烈反弹", "继续放任将削弱中央权威"],
    "hidden_constraints": ["年轻皇帝资历尚浅", "战争会消耗巨大财政与军力", "一旦削而不成，中央威信重创"],
    "options_available": ["继续安抚三藩", "局部拖延", "果断削藩并准备应对全面叛乱"],
    "chosen_action": "决定削藩，叛乱后坚持长期作战直至彻底平定。",
    "short_term_outcome": "引发大规模叛乱，清廷承受巨大压力。",
    "long_term_outcome": "中央集权显著加强，藩镇问题被根本缓解。",
    "success_or_failure": "success",
    "key_reasons": ["识别长期隐患不能无限拖延", "战略决心与资源投入匹配", "在高压阶段没有轻易半途妥协"],
    "transferable_principles": ["某些结构性风险越拖越大，必须在可控时点处理", "触动既得利益的大动作，必须预备承受第一波反扑"],
    "non_transferable_factors": ["皇帝对全国军政资源拥有集中调度权", "古代藩镇问题带有军事割据性质"],
    "modern_analogy_keywords": ["中央收权", "长期隐患", "结构性风险", "强力整顿", "先痛后稳"],
    "source_note": "《清史稿·圣祖本纪》"
  },
  {
    "id": "yongzheng-tax-reform",
    "title": "雍正摊丁入亩与耗羡归公",
    "dynasty": "清",
    "era": "雍正朝",
    "year_range": "1723年-1735年",
    "main_figures": ["雍正帝"],
    "summary": "雍正以财政和基层治理问题为切入口，推行摊丁入亩、耗羡归公等一系列税政改革。",
    "situation_tags": ["改革推进", "合法性", "权力控制"],
    "decision_maker": "雍正帝",
    "objective": "稳定财政、减轻基层税制扭曲并增强中央治理能力。",
    "visible_information": ["人丁税弊端明显", "地方耗羡流弊严重", "基层治理成本高"],
    "hidden_constraints": ["地方官吏会本能抵触", "改革涉及长期利益链", "必须兼顾财政与民生承受度"],
    "options_available": ["维持旧税制", "局部修补", "系统推进税政与财政整顿"],
    "chosen_action": "推动摊丁入亩、耗羡归公、养廉银等配套改革。",
    "short_term_outcome": "财政收支更透明，地方治理激励有所调整。",
    "long_term_outcome": "清代中期财政与基层治理获得较稳定基础。",
    "success_or_failure": "success",
    "key_reasons": ["改革直指扭曲最严重的环节", "配套措施兼顾中央控制与基层激励", "并非单点修补而是系统推进"],
    "transferable_principles": ["财政改革不能只堵漏洞，还要重设激励", "制度改革需要配套补偿机制，否则执行层会变形对抗"],
    "non_transferable_factors": ["皇权体制提供了高集中度推进条件", "古代赋役制度与现代税制不可简单对应"],
    "modern_analogy_keywords": ["财政改革", "税制调整", "治理激励", "制度配套", "系统整顿"],
    "source_note": "《清史稿·世宗本纪》"
  },
  {
    "id": "qi-jiguang-train-new-army",
    "title": "戚继光整训义乌兵抗倭",
    "dynasty": "明",
    "era": "嘉靖朝",
    "year_range": "1555年-1565年",
    "main_figures": ["戚继光", "胡宗宪"],
    "summary": "面对旧军战力低下和沿海倭患，戚继光通过重新招募、训练和战法组合重建有效战斗力。",
    "situation_tags": ["用人换将", "改革推进", "守攻抉择"],
    "decision_maker": "戚继光",
    "objective": "在旧有部队战力不足的情况下快速形成可用作战力量。",
    "visible_information": ["旧军纪律松弛", "倭寇机动灵活", "沿海防线屡受冲击"],
    "hidden_constraints": ["短时间内难以完全依靠旧体系", "新军训练与装备需要时间", "必须形成适配敌情的新战法"],
    "options_available": ["继续沿用旧军旧法", "只换主将不改训练体系", "重募新兵并配套新训练与战法"],
    "chosen_action": "招募义乌兵并形成严格训练、协同作战和器械配套的新军体系。",
    "short_term_outcome": "新军战力显著提升，抗倭形势改善。",
    "long_term_outcome": "形成一套可复制的练兵与边防经验。",
    "success_or_failure": "success",
    "key_reasons": ["识别问题根源在体系而非单个将领", "换人与重训同步进行", "针对对手特性设计组织能力"],
    "transferable_principles": ["换将如果不配套训练和流程升级，往往治标不治本", "面对新型对手，要重建适配能力而不是沿用旧打法"],
    "non_transferable_factors": ["古代冷兵器与海防环境特殊", "戚家军高度依赖军事训练体系与地方征募条件"],
    "modern_analogy_keywords": ["换将", "重建团队", "训练体系", "组织战力", "应对新型对手", "旧团队打不动", "换人不如重建体系", "换打法", "重练基本功"],
    "source_note": "《明史·戚继光传》"
  },
  {
    "id": "guo-ziyi-huihe-alliance",
    "title": "郭子仪单骑说回纥",
    "dynasty": "唐",
    "era": "安史之乱后期",
    "year_range": "765年",
    "main_figures": ["郭子仪", "回纥首领"],
    "summary": "吐蕃乘虚入侵之际，郭子仪面对己方兵少与盟友摇摆，用个人信用和局势判断稳住回纥，使其不转为敌。",
    "situation_tags": ["联盟不稳", "以弱对强", "守攻抉择"],
    "decision_maker": "郭子仪",
    "objective": "避免两线受敌，稳住摇摆中的外部力量。",
    "visible_information": ["唐军兵力不足", "回纥立场可变", "吐蕃压力迫近"],
    "hidden_constraints": ["不能同时与吐蕃、回纥正面为敌", "一旦谈判失败后手有限", "需要迅速稳定局势而非长期博弈"],
    "options_available": ["正面拒敌并与回纥翻脸", "完全退避", "先稳住回纥再集中应对主要威胁"],
    "chosen_action": "郭子仪以个人威信出面，稳住回纥，避免腹背受敌。",
    "short_term_outcome": "回纥未倒向敌方，唐军压力明显下降。",
    "long_term_outcome": "为唐廷争取了稳定局势的空间。",
    "success_or_failure": "success",
    "key_reasons": ["分清主次威胁", "在资源不足时优先防止局面恶化", "通过可信承诺稳住摇摆盟友"],
    "transferable_principles": ["联盟管理的关键常常不是多么亲密，而是先防止盟友转敌", "资源不足时先减敌再争胜，比同时树敌更重要"],
    "non_transferable_factors": ["郭子仪个人威望极高，现代组织中不易复制", "唐与回纥关系包含强烈军事与朝贡背景"],
    "modern_analogy_keywords": ["摇摆盟友", "防止两线作战", "个人信用", "先稳外部关系", "危机结盟", "不完全信任的合作方", "先稳盟友", "合作但留后手", "防止盟友转敌"],
    "source_note": "《旧唐书·郭子仪传》"
  },
  {
    "id": "zeng-guofan-build-xiang-army",
    "title": "曾国藩创建湘军",
    "dynasty": "清",
    "era": "太平天国时期",
    "year_range": "1853年起",
    "main_figures": ["曾国藩"],
    "summary": "在绿营与八旗战力普遍低效的背景下，曾国藩以地方团练为基础，重建一支能够持续作战的组织。",
    "situation_tags": ["用人换将", "内部冲突", "改革推进"],
    "decision_maker": "曾国藩",
    "objective": "在旧有军事系统失灵时重建有效战力。",
    "visible_information": ["朝廷正规军屡战屡败", "太平军扩张迅猛", "地方资源与士绅力量可动员"],
    "hidden_constraints": ["新建组织需要时间和纪律", "地方武装崛起也会带来后续中央控制问题", "必须解决指挥与后勤一体化"],
    "options_available": ["继续依赖旧军体系", "只更换将领", "重新组织地方团练并严建纪律"],
    "chosen_action": "以乡里关系和严明纪律为基础，逐步建立湘军体系。",
    "short_term_outcome": "成军缓慢，但组织凝聚力与执行力提升。",
    "long_term_outcome": "湘军成为清廷平乱主力，同时也强化了地方军事实力。",
    "success_or_failure": "success",
    "key_reasons": ["看清旧体系已难以修补", "重建组织文化与纪律", "把人事、后勤、指挥当成一体设计"],
    "transferable_principles": ["当旧体系失灵时，换人不如重建组织机制", "新的执行系统往往比旧系统的局部修补更有效"],
    "non_transferable_factors": ["晚清地方军事化环境特殊", "湘军高度依赖宗族与乡绅网络"],
    "modern_analogy_keywords": ["旧系统失灵", "重建团队", "组织纪律", "地方力量", "再造执行系统", "老团队不行", "另起炉灶", "重建班底", "负责人带不动团队"],
    "source_note": "《清史稿·曾国藩传》"
  },
  {
    "id": "left-zongtang-recover-xinjiang",
    "title": "左宗棠西征收复新疆",
    "dynasty": "清",
    "era": "同治光绪之际",
    "year_range": "1876年-1878年",
    "main_figures": ["左宗棠", "阿古柏"],
    "summary": "左宗棠在西北局势复杂、后勤压力巨大的情况下，坚持先安陕甘、后图新疆的顺序推进。",
    "situation_tags": ["守攻抉择", "以弱对强", "改革推进"],
    "decision_maker": "左宗棠",
    "objective": "在资源受限情况下恢复西北控制权。",
    "visible_information": ["西北路远粮难", "新疆局势恶化", "国内财政与军力都不宽裕"],
    "hidden_constraints": ["不能两线同时推进", "后勤与运输是决定性约束", "国际压力与边疆政治交织"],
    "options_available": ["先图新疆后稳后方", "长期观望", "先稳陕甘再逐步推进新疆"],
    "chosen_action": "采取先整后方、再集中力量西征新疆的节奏。",
    "short_term_outcome": "作战推进较稳，后勤支持逐步成形。",
    "long_term_outcome": "新疆大部得以收复，清廷西北局势重新稳定。",
    "success_or_failure": "success",
    "key_reasons": ["明确了战略顺序", "把后勤当成战略本体而非附属问题", "不被政治焦虑逼成全面冒进"],
    "transferable_principles": ["远距离扩张一定先算补给，再谈攻势", "复杂局面中先稳后方，再打远征，往往比同时摊开更稳"],
    "non_transferable_factors": ["边疆战争与近代国际环境高度特殊", "地方军政与国家财政关系复杂"],
    "modern_analogy_keywords": ["远征", "后勤", "分阶段推进", "先稳后攻", "复杂项目"],
    "source_note": "《清史稿·左宗棠传》"
  },
  {
    "id": "su-qin-hezong-failure",
    "title": "六国合纵抗秦反复失效",
    "dynasty": "战国",
    "era": "战国后期",
    "year_range": "前4世纪-前3世纪",
    "main_figures": ["苏秦", "张仪", "六国诸侯"],
    "summary": "六国虽多次尝试结成合纵联盟对抗强秦，但因目标不一、彼此猜疑与短期利益诱惑而屡屡瓦解。",
    "situation_tags": ["联盟不稳", "以弱对强", "内部冲突"],
    "decision_maker": "六国诸侯",
    "objective": "通过联盟平衡强秦扩张。",
    "visible_information": ["秦国持续强大", "单个诸侯难以独自抗衡", "结盟在纸面上有利"],
    "hidden_constraints": ["六国目标并不一致", "彼此互不信任", "任何一国都可能为了短期利益单独与秦交易"],
    "options_available": ["各自为战", "建立长期合纵联盟", "边结盟边各自与秦周旋"],
    "chosen_action": "联盟多次建立又瓦解，无法形成持续一致的战略执行。",
    "short_term_outcome": "阶段性制约秦国，但难以形成持久合力。",
    "long_term_outcome": "六国最终被秦逐个击破。",
    "success_or_failure": "failure",
    "key_reasons": ["联盟缺乏共同执行机制", "成员短期利益高于长期共同目标", "缺少对背盟行为的有效约束"],
    "transferable_principles": ["联盟最怕目标不一致却假装一致", "没有退出成本和分配机制的联盟，往往只能短期有效"],
    "non_transferable_factors": ["战国诸侯的存亡风险远高于现代合作体", "纵横家的个人作用具有时代特征"],
    "modern_analogy_keywords": ["联盟失效", "多方合作", "共同敌人", "背盟", "缺少约束", "互不信任", "各怀心思", "合作翻脸", "联盟脆弱"],
    "source_note": "《战国策》"
  },
  {
    "id": "liu-bei-appoint-zhuge-liang",
    "title": "刘备三顾茅庐与隆中对定战略",
    "dynasty": "东汉末",
    "era": "三国形成前夜",
    "year_range": "207年",
    "main_figures": ["刘备", "诸葛亮"],
    "summary": "刘备在长期寄人篱下、力量薄弱时，通过主动延揽关键人才和明确长线战略，改变了组织上限。",
    "situation_tags": ["用人换将", "以弱对强", "守攻抉择"],
    "decision_maker": "刘备",
    "objective": "在弱势流动状态下找到可持续的战略方向与核心辅佐者。",
    "visible_information": ["刘备长期无稳定根据地", "自身资源有限", "曹操与孙权已形成相对优势"],
    "hidden_constraints": ["单靠个人魅力难以长期支撑", "必须找到能设计长期路径的人", "任何错误下注都可能导致彻底出局"],
    "options_available": ["继续随机应变", "投靠更强势力", "主动延揽关键人才并明确长期战略"],
    "chosen_action": "多次拜访诸葛亮，确立先取荆益、联吴抗曹的方向。",
    "short_term_outcome": "形成较清晰的发展路径与核心智囊配置。",
    "long_term_outcome": "为蜀汉立国提供战略框架。",
    "success_or_failure": "success",
    "key_reasons": ["弱势阶段先补最关键的人才短板", "把个人机动性转化为战略方向", "用清晰路线凝聚后续资源"],
    "transferable_principles": ["组织卡在瓶颈时，关键人才引入可能比短期资源更值钱", "请到对的人后，要允许其重构战略，而不是只做执行工具"],
    "non_transferable_factors": ["古代军阀格局与现代组织环境差异大", "个人忠诚绑定与现代职业关系不同"],
    "modern_analogy_keywords": ["引入关键人才", "长期战略", "弱势起步", "核心班底", "找对人", "负责人不合适", "关键岗位补强", "换核心操盘手"],
    "source_note": "《三国志·诸葛亮传》"
  },
  {
    "id": "wu-qi-chu-reform",
    "title": "吴起相楚变法受挫",
    "dynasty": "战国·楚",
    "era": "战国前期",
    "year_range": "前386年后",
    "main_figures": ["吴起", "楚悼王"],
    "summary": "吴起在楚国推行整军经武与削弱贵族特权的改革，短期见效，但因过度依赖君主支持而在楚悼王死后迅速反噬。",
    "situation_tags": ["改革推进", "内部冲突", "合法性"],
    "decision_maker": "吴起",
    "objective": "通过整顿吏治和军政，提升楚国战斗力与治理效率。",
    "visible_information": ["楚国积弊较重", "贵族特权盘根错节", "楚悼王支持吴起"],
    "hidden_constraints": ["改革过于依赖君主个人支持", "既得利益集团不会坐视", "制度化承接不足"],
    "options_available": ["维持旧秩序", "渐进改革", "依靠君主支持快速重整"],
    "chosen_action": "快速整肃吏治、打击贵族特权并整军。",
    "short_term_outcome": "楚国军政能力有所增强。",
    "long_term_outcome": "楚悼王死后，吴起被旧贵族报复，改革未能延续。",
    "success_or_failure": "failure",
    "key_reasons": ["改革速度快但制度承接弱", "既得利益反扑被低估", "最高支持者一旦消失，缺少保护层"],
    "transferable_principles": ["改革不能只依赖单一强人背书，要设计可持续承接机制", "触动深层利益时，制度化与联盟经营同样重要"],
    "non_transferable_factors": ["战国贵族政治结构与现代组织差异极大", "君主生死对改革命运影响异常直接"],
    "modern_analogy_keywords": ["改革夭折", "既得利益", "过度依赖老板支持", "制度承接", "反扑", "老板支持一撤就失败", "改革后遭反扑", "只靠一把手支持"],
    "source_note": "《史记·孙子吴起列传》"
  },
  {
    "id": "cao-cao-relocate-emperor-to-xu",
    "title": "曹操奉天子都许",
    "dynasty": "东汉末",
    "era": "汉献帝时期",
    "year_range": "196年",
    "main_figures": ["曹操", "汉献帝"],
    "summary": "曹操在群雄并起、实力尚未绝对领先时，奉迎汉献帝迁都许县，把形式合法性与实际控制结合起来。",
    "situation_tags": ["合法性", "权力控制", "以弱对强"],
    "decision_maker": "曹操",
    "objective": "借中央名义整合资源并提升自身在群雄中的政治主动权。",
    "visible_information": ["汉献帝流离失所", "群雄割据并起", "曹操尚未完全压倒其他诸侯"],
    "hidden_constraints": ["不能直接取代汉室名义", "必须同时控制皇帝与朝廷运作", "若只奉迎而不控中枢会反受掣肘"],
    "options_available": ["只经营兖州根据地", "自立旗号另起炉灶", "奉迎天子都许并控制朝廷中枢"],
    "chosen_action": "奉迎汉献帝至许县，以朝廷名义号令诸侯。",
    "short_term_outcome": "曹操迅速获得政治正当性与调度资源的名义优势。",
    "long_term_outcome": "为其统一北方、整合士人和地方势力提供了强大杠杆。",
    "success_or_failure": "success",
    "key_reasons": ["把名分和控制力合并处理", "借接盘中央中枢放大自身资源", "用制度与叙事整合外部支持"],
    "transferable_principles": ["接盘混乱局面时，先拿合法性与中枢叙事，往往比先扩地盘更有效", "形式权威和实际控制必须一起设计"],
    "non_transferable_factors": ["皇帝名义在东汉末具有特殊政治权重", "古代朝廷中枢与现代组织治理结构不同"],
    "modern_analogy_keywords": ["组织接盘", "接盘中枢", "合法性", "借名分整合资源", "控制关键流程", "被架空前先拿中枢"],
    "source_note": "《三国志·武帝纪》"
  },
  {
    "id": "han-wudi-tui-en-ling",
    "title": "汉武帝行推恩令",
    "dynasty": "西汉",
    "era": "汉武帝时期",
    "year_range": "前127年",
    "main_figures": ["汉武帝", "主父偃"],
    "summary": "面对诸侯王坐大又不宜再起大乱的局面，汉武帝采纳主父偃建议，以推恩令分化诸侯国力量。",
    "situation_tags": ["权力控制", "内部冲突", "合法性"],
    "decision_maker": "汉武帝",
    "objective": "在避免重演七国之乱的前提下削弱地方诸侯力量。",
    "visible_information": ["诸侯王势力仍大", "直接强削藩风险高", "中央需要稳妥收回控制力"],
    "hidden_constraints": ["不能再制造全面叛乱", "必须用规则而非单纯用兵拆解地方权力", "需要让削权看起来符合礼法"],
    "options_available": ["继续放任诸侯坐大", "直接武力削藩", "以推恩令分封子弟逐步拆解诸侯国"],
    "chosen_action": "通过推恩令让诸侯王将封地分给诸子，分散其封国规模。",
    "short_term_outcome": "诸侯王难以公开反对，中央收权阻力较低。",
    "long_term_outcome": "地方诸侯力量被逐步削弱，中央集权进一步巩固。",
    "success_or_failure": "success",
    "key_reasons": ["以规则设计代替正面冲突", "把收权变成渐进、低烈度过程", "抓住了地方权力结构的可分化弱点"],
    "transferable_principles": ["收权不一定靠硬碰硬，很多时候更有效的是改规则、拆结构、分利益", "想长期控盘，就要降低对手集体反扑的可能"],
    "non_transferable_factors": ["西汉宗藩制度具有时代特征", "皇帝对法令和土地分封有天然最高解释权"],
    "modern_analogy_keywords": ["收权", "不直接翻脸", "拆分权力", "规则整权", "尾大不掉", "分化既有势力"],
    "source_note": "《汉书·主父偃传》"
  },
  {
    "id": "huo-guang-depose-changyi-king",
    "title": "霍光废昌邑王立汉宣帝",
    "dynasty": "西汉",
    "era": "昭帝身后",
    "year_range": "前74年",
    "main_figures": ["霍光", "刘贺", "刘询"],
    "summary": "汉昭帝无子而崩后，霍光在新君刘贺失德失序的情况下，联合朝廷力量废黜昌邑王，改立刘询为帝。",
    "situation_tags": ["权力控制", "用人换将", "合法性"],
    "decision_maker": "霍光",
    "objective": "在接班危机中迅速稳定朝局并选择更可控的新君。",
    "visible_information": ["昭帝去世无子", "昌邑王即位后举止失序", "朝局极不稳定"],
    "hidden_constraints": ["废立皇帝必须有足够合法性包装", "如果朝臣支持不足会引发更大动荡", "换人之后还要迅速恢复秩序"],
    "options_available": ["继续容忍失序君主", "霍光直接夺位", "联合朝廷与太后废立新君"],
    "chosen_action": "以朝廷决议和太后名义废黜刘贺，迎立刘询。",
    "short_term_outcome": "朝局迅速从失控边缘拉回，关键大臣重新形成共识。",
    "long_term_outcome": "汉宣帝即位后政局相对稳定，霍光辅政格局延续。",
    "success_or_failure": "success",
    "key_reasons": ["处理继任问题时先解决合法性", "换人动作背后有足够的关键联盟支持", "并非只换掉人，而是同步稳定秩序"],
    "transferable_principles": ["接班和换帅问题，决定成败的常常不是人选本身，而是废立过程是否可被组织接受", "重大换人必须同时处理名义、联盟与执行链"],
    "non_transferable_factors": ["皇位废立属于古代极端政治场景", "霍光的外戚与辅政地位没有现代直接对应物"],
    "modern_analogy_keywords": ["接班", "换帅", "临时接盘", "高层继任", "废立负责人", "关键联盟支持"],
    "source_note": "《汉书·霍光传》"
  },
  {
    "id": "zhao-wuling-hufu-qishe",
    "title": "赵武灵王胡服骑射",
    "dynasty": "战国·赵",
    "era": "战国中期",
    "year_range": "前307年前后",
    "main_figures": ["赵武灵王"],
    "summary": "赵国面对北方骑战压力和列国竞争，赵武灵王推动胡服骑射，以军事与文化双重改革提升国力。",
    "situation_tags": ["改革推进", "以弱对强", "守攻抉择"],
    "decision_maker": "赵武灵王",
    "objective": "通过改变组织能力与作战方式提升赵国竞争力。",
    "visible_information": ["赵国边境压力增大", "传统车战不再适应", "旧贵族与旧习俗会抵触改革"],
    "hidden_constraints": ["改革不只是技术问题，也会触动身份认同", "若只改装备不改训练与战法效果有限", "君主必须亲自承担改革争议"],
    "options_available": ["沿用旧制", "局部试骑兵改革", "全面推动胡服骑射与配套训练"],
    "chosen_action": "推动服饰、兵种和训练方式系统改革。",
    "short_term_outcome": "赵国内部争议加大，但军事实力明显提升。",
    "long_term_outcome": "赵国在北方竞争中获得更强机动优势。",
    "success_or_failure": "success",
    "key_reasons": ["准确识别外部威胁变化", "改革覆盖了能力、文化与执行方式", "高层对改革承担了明确背书责任"],
    "transferable_principles": ["遇到新型竞争，不只要换工具，还要换组织能力与行为习惯", "象征层面的改革若处理得好，能推动真实能力重构"],
    "non_transferable_factors": ["战国边疆军事环境特殊", "君主个人推动改革的空间远大于现代多数组织"],
    "modern_analogy_keywords": ["应对新威胁", "换打法", "能力升级", "文化阻力", "组织转型", "旧体系不适配"],
    "source_note": "《史记·赵世家》"
  },
  {
    "id": "li-kui-reform-wei",
    "title": "李悝变法于魏",
    "dynasty": "战国·魏",
    "era": "战国初期",
    "year_range": "前5世纪后期",
    "main_figures": ["李悝", "魏文侯"],
    "summary": "魏国在新兴诸侯竞争中，通过李悝推行法制、农业与财政改革，迅速提升国家治理与战争动员能力。",
    "situation_tags": ["改革推进", "以弱对强", "合法性"],
    "decision_maker": "魏文侯",
    "objective": "把新兴魏国尽快建设成有竞争力的强国。",
    "visible_information": ["列国竞争加剧", "魏国需要建立稳定的法制与财政基础", "旧秩序不足以支撑长期扩张"],
    "hidden_constraints": ["新兴政权制度尚不稳固", "改革需要兼顾农业、赏罚与行政", "必须让新规则具备持续执行力"],
    "options_available": ["沿用旧有分封惯性", "零散修补", "系统推进法制与财政治理改革"],
    "chosen_action": "推行尽地力之教、平籴法与法治化治理安排。",
    "short_term_outcome": "魏国资源动员与治理效率增强。",
    "long_term_outcome": "魏国在战国初期率先崛起，成为强国之一。",
    "success_or_failure": "success",
    "key_reasons": ["改革围绕国家竞争力的底层环节展开", "不是单项补丁，而是制度组合拳", "高层长期支持形成稳定执行"],
    "transferable_principles": ["组织起盘期最值钱的是把基础制度先搭稳，而不是先追求表面规模", "真正能带来长期优势的改革通常发生在财政、法制与执行链底层"],
    "non_transferable_factors": ["战国国家构建与现代企业组织并不等价", "法家式高压治理存在显著时代差异"],
    "modern_analogy_keywords": ["新组织起盘", "基础制度", "法治化", "底层能力建设", "系统改革", "从底盘开始搭建"],
    "source_note": "《史记·魏世家》"
  },
  {
    "id": "tian-dan-recover-qi",
    "title": "田单即墨复齐",
    "dynasty": "战国·齐",
    "era": "燕齐战争后",
    "year_range": "前284年后",
    "main_figures": ["田单"],
    "summary": "齐国几乎亡国之际，田单据守即墨，通过整合民心、稳定组织和设计反击，一举完成复国。",
    "situation_tags": ["以弱对强", "守攻抉择", "合法性"],
    "decision_maker": "田单",
    "objective": "在残局中保住仅存据点并寻找反攻机会。",
    "visible_information": ["齐国大部沦陷", "仅余少数城池", "敌军气势正盛"],
    "hidden_constraints": ["若守城人心先散则再无翻盘机会", "必须把防守熬到可转攻的时点", "反攻需要心理与战术双重设计"],
    "options_available": ["开城投降", "纯粹死守", "整合民心后寻找心理战与奇袭机会"],
    "chosen_action": "先稳住即墨军民，再利用火牛阵与敌军松懈发动反攻。",
    "short_term_outcome": "即墨防线未崩，并成功打出决定性逆转。",
    "long_term_outcome": "齐国逐步收复失地，完成复国。",
    "success_or_failure": "success",
    "key_reasons": ["残局里先稳住人心与秩序", "没有把守势与攻势割裂开来", "善用心理战制造对手崩盘"],
    "transferable_principles": ["接盘残局时，第一目标不是炫技，而是先稳住还在手里的东西", "真正的逆袭通常来自先稳组织、再等时机、最后集中出手"],
    "non_transferable_factors": ["古代守城与复国场景极端", "火牛阵等战法带有强烈时代特性"],
    "modern_analogy_keywords": ["残局接盘", "濒危翻盘", "先稳住再反击", "士气重建", "少数据点翻盘"],
    "source_note": "《史记·田单列传》"
  },
  {
    "id": "sun-bin-wei-wei-jiu-zhao",
    "title": "孙膑围魏救赵",
    "dynasty": "战国·齐",
    "era": "战国中期",
    "year_range": "前354年-前353年",
    "main_figures": ["孙膑", "田忌"],
    "summary": "赵国被魏国主力围攻时，孙膑没有选择正面驰援，而是主张攻其必救之地，通过围魏救赵扭转局势。",
    "situation_tags": ["以弱对强", "守攻抉择", "联盟不稳"],
    "decision_maker": "田忌",
    "objective": "在不与魏军主力硬碰的前提下解救盟友赵国。",
    "visible_information": ["赵国危急", "魏军主力前压", "正面救赵成本高且胜算低"],
    "hidden_constraints": ["时间窗口有限", "若被拖入正面决战会陷入被动", "必须迫使敌军改变主攻方向"],
    "options_available": ["直接驰援赵国", "坐视赵国被围", "攻击魏国本土逼其回撤"],
    "chosen_action": "不直接赴赵，而是进攻魏国要害，诱使魏军回援后截击。",
    "short_term_outcome": "魏军被迫回撤，赵国压力迅速下降。",
    "long_term_outcome": "齐国通过间接打击建立了对魏作战优势。",
    "success_or_failure": "success",
    "key_reasons": ["不被表面战场牵着走", "找到敌军真正不能失去的点", "把救盟友和打主战场拆成两个动作处理"],
    "transferable_principles": ["帮盟友时未必要冲向最热闹的前线，很多时候更有效的是打对手后方", "弱势方应优先改变对手节奏，而不是迎合对手节奏"],
    "non_transferable_factors": ["战国诸侯战争的地理与行军条件特殊", "古代军事调动速度与现代组织响应机制不同"],
    "modern_analogy_keywords": ["间接打击", "救盟友", "围魏救赵", "不正面硬碰", "打后方", "改变对手节奏"],
    "source_note": "《史记·孙子吴起列传》"
  },
  {
    "id": "northern-wei-emperor-xiaowen-reform",
    "title": "北魏孝文帝迁都洛阳与汉化改革",
    "dynasty": "北魏",
    "era": "孝文帝时期",
    "year_range": "494年起",
    "main_figures": ["北魏孝文帝"],
    "summary": "北魏为了提升对中原的长期治理能力，决定迁都洛阳，并推动汉化改革，重塑统治方式与组织中枢。",
    "situation_tags": ["改革推进", "合法性", "权力控制"],
    "decision_maker": "北魏孝文帝",
    "objective": "提高国家治理能力并整合更大范围的人口与地域。",
    "visible_information": ["平城旧有统治方式难以覆盖中原", "鲜卑旧贵族对改革天然抵触", "迁都会牵动整个权力结构"],
    "hidden_constraints": ["改革触及身份认同与利益分配", "中枢迁移意味着组织重排", "若配套跟不上会引发长期反弹"],
    "options_available": ["维持旧都旧制", "局部引入中原制度", "迁都洛阳并推动系统汉化改革"],
    "chosen_action": "迁都洛阳，并以改姓、改服、改官制等方式推进汉化。",
    "short_term_outcome": "中枢权力重心被重新塑造，改革争议显著上升。",
    "long_term_outcome": "北魏治理能力提升，但也留下后续北方旧势力反弹的种子。",
    "success_or_failure": "mixed",
    "key_reasons": ["认识到总部位置与统治方式会塑造组织能力", "改革覆盖中枢、文化与制度三个层面", "配套改革收益大，但反弹也不小"],
    "transferable_principles": ["组织升级有时需要同时重排总部、中层和文化，不是只改流程", "越深层的组织迁移，越要准备长期磨合与阻力管理"],
    "non_transferable_factors": ["北朝族群整合背景极其特殊", "古代迁都的政治军事含义远超现代办公地点迁移"],
    "modern_analogy_keywords": ["总部迁移", "组织文化重构", "系统改革", "中枢重排", "身份阻力", "跨区域整合"],
    "source_note": "《魏书·高祖纪》"
  },
  {
    "id": "song-jin-maritime-alliance-backfire",
    "title": "宋金海上之盟反噬北宋",
    "dynasty": "北宋末",
    "era": "宋金结盟时期",
    "year_range": "1120年-1125年",
    "main_figures": ["宋徽宗", "童贯", "金太祖"],
    "summary": "北宋为联金灭辽而签订海上之盟，希望借新兴强者之力收回燕云，但在联盟目标不一致和自身实力不足下，反被金迅速反噬。",
    "situation_tags": ["联盟不稳", "以弱对强", "守攻抉择"],
    "decision_maker": "宋廷",
    "objective": "借助外部新盟友迅速改变对辽格局并收复失地。",
    "visible_information": ["辽已衰弱", "金军崛起迅猛", "宋军独自北伐能力有限"],
    "hidden_constraints": ["新盟友比旧敌更不可控", "一旦联手暴露自身弱点，后果可能更坏", "联盟没有稳固的战后秩序安排"],
    "options_available": ["继续独自对辽博弈", "维持现状", "与金结盟夹击辽国"],
    "chosen_action": "缔结海上之盟，与金联手灭辽。",
    "short_term_outcome": "辽国迅速崩解，宋廷短期看似接近目标。",
    "long_term_outcome": "金很快南下，北宋遭遇更严重安全危机并最终灭亡。",
    "success_or_failure": "failure",
    "key_reasons": ["把短期共同利益误判为长期可靠联盟", "低估了新盟友的能力与野心", "自身硬实力不足却过早暴露底牌"],
    "transferable_principles": ["与强势新盟友合作时，最大的风险常常不是当前敌人，而是盟友本身", "借外力破局前，必须先想清楚战后秩序和翻脸后的后手"],
    "non_transferable_factors": ["宋金辽三方关系受地缘与军事格局深刻影响", "古代国家灭亡级风险高于现代多数合作关系"],
    "modern_analogy_keywords": ["联盟背刺", "与虎谋皮", "合作方翻脸", "短期盟友", "借外力破局", "不完全信任的合作方"],
    "source_note": "《宋史·徽宗本纪》"
  },
  {
    "id": "liu-bei-battle-of-yiling",
    "title": "刘备夷陵之战",
    "dynasty": "蜀汉",
    "era": "三国时期",
    "year_range": "221年-222年",
    "main_figures": ["刘备", "陆逊"],
    "summary": "刘备在蜀汉立国未久、内部尚需整合之际，因荆州失陷与关羽之死而大举伐吴，最终在夷陵惨败。",
    "situation_tags": ["守攻抉择", "联盟不稳", "以弱对强"],
    "decision_maker": "刘备",
    "objective": "报复东吴、重夺荆州并重塑蜀汉声望。",
    "visible_information": ["孙刘联盟已裂", "蜀汉新立国不久", "东吴严阵以待"],
    "hidden_constraints": ["情绪化决策风险高", "后勤线被拉长", "新政权尚未稳固就打大战成本极高"],
    "options_available": ["先整内政再图东吴", "有限施压", "亲率大军全面东征"],
    "chosen_action": "刘备亲自率大军东征，与吴军决战。",
    "short_term_outcome": "战线拉长后蜀军逐步陷入被动。",
    "long_term_outcome": "夷陵惨败重创蜀汉元气，联盟破裂彻底固化。",
    "success_or_failure": "failure",
    "key_reasons": ["没有把情绪与战略分开", "政权尚未稳固就发动高成本决战", "低估了后勤与地形对长期推进的约束"],
    "transferable_principles": ["刚接盘或刚成立的新组织，最怕在情绪驱动下过早打决定性大战", "联盟破裂后是否立刻翻脸，要先看自己是否真的承受得住战役成本"],
    "non_transferable_factors": ["古代大军远征与现代组织竞争不可直接类比", "刘备个人情感因素在决策中占比很高"],
    "modern_analogy_keywords": ["情绪决策", "报复性出击", "联盟破裂后全面开战", "新组织不宜过早决战", "过度扩张"],
    "source_note": "《三国志·先主传》"
  },
  {
    "id": "zhuge-liang-northern-expedition-jieting",
    "title": "诸葛亮北伐与失街亭",
    "dynasty": "蜀汉",
    "era": "三国时期",
    "year_range": "228年",
    "main_figures": ["诸葛亮", "马谡"],
    "summary": "诸葛亮第一次北伐初期形势尚可，但街亭失守导致前线体系崩溃，被迫撤军。",
    "situation_tags": ["以弱对强", "用人换将", "守攻抉择"],
    "decision_maker": "诸葛亮",
    "objective": "利用魏国内部波动时机北出陇右，争取战略突破。",
    "visible_information": ["蜀弱魏强", "北伐窗口有限", "关键节点街亭决定补给与协同"],
    "hidden_constraints": ["长线后勤脆弱", "关键岗位用人一旦失误会拖垮全局", "前线不能承受单点失守"],
    "options_available": ["继续守势", "小规模试探", "趁窗口推进并在关键节点配置主将"],
    "chosen_action": "发起北伐，同时派马谡守街亭。",
    "short_term_outcome": "蜀军初期取得进展，但街亭失守导致局势迅速逆转。",
    "long_term_outcome": "诸葛亮被迫退军，并以挥泪斩马谡收拾残局。",
    "success_or_failure": "failure",
    "key_reasons": ["关键岗位选人失误放大了整体风险", "单点节点的重要性被低估", "弱势方容错空间远低于强势方"],
    "transferable_principles": ["弱势方打关键仗时，最怕关键岗位用错人", "越是容错低的任务，越不能拿核心节点做试错"],
    "non_transferable_factors": ["古代军事节点的成败影响极端", "北伐长期战略受多重地理与国力限制"],
    "modern_analogy_keywords": ["关键岗位选错人", "关键节点失守", "北伐窗口", "容错低", "关键执行人"],
    "source_note": "《三国志·诸葛亮传》"
  },
  {
    "id": "duke-of-zhou-eastern-expedition",
    "title": "周公东征平管蔡之乱",
    "dynasty": "西周",
    "era": "周初",
    "year_range": "前11世纪",
    "main_figures": ["周公旦", "周成王"],
    "summary": "武王去世、成王年幼之际，周公摄政引发猜忌与叛乱，最终通过东征平定局势，并在事后归政巩固合法性。",
    "situation_tags": ["合法性", "权力控制", "内部冲突"],
    "decision_maker": "周公旦",
    "objective": "在幼主继位的脆弱时期稳住政权与秩序。",
    "visible_information": ["新君年幼", "摄政容易引发篡位猜疑", "管叔蔡叔等人发动叛乱"],
    "hidden_constraints": ["出手过慢会使叛乱坐大", "出手过猛又可能损伤摄政合法性", "平乱之后还必须重建信任"],
    "options_available": ["放弃摄政退出中枢", "继续拖延观望", "东征平乱并在事后重建秩序"],
    "chosen_action": "周公主持东征平定叛乱，并在稳定后归政于成王。",
    "short_term_outcome": "周初政权避免了继位危机演变成全面失控。",
    "long_term_outcome": "周公的摄政与归政成为后世处理幼主继位的典型样本。",
    "success_or_failure": "success",
    "key_reasons": ["平乱与合法性修复同步处理", "既有足够决断，也懂得在事后归位", "把接班危机从权力争议转回秩序重建"],
    "transferable_principles": ["接班过渡期最重要的不是谁动作最大，而是谁能同时稳住秩序与名分", "临时接盘者若想长期被接受，必须设计退出或归位机制"],
    "non_transferable_factors": ["西周宗法与分封政治高度特殊", "古代摄政与现代代理治理并不完全对应"],
    "modern_analogy_keywords": ["接班过渡", "幼主", "摄政", "临时接盘", "代理负责人", "稳定继任秩序"],
    "source_note": "《史记·鲁周公世家》"
  },
  {
    "id": "zhu-di-jingnan-campaign",
    "title": "朱棣靖难之役",
    "dynasty": "明",
    "era": "建文时期",
    "year_range": "1399年-1402年",
    "main_figures": ["朱棣", "建文帝"],
    "summary": "建文削藩步步逼近之际，燕王朱棣选择以“靖难”名义起兵，在继承与削权冲突中逆转中央格局。",
    "situation_tags": ["权力控制", "合法性", "内部冲突"],
    "decision_maker": "朱棣",
    "objective": "在削藩压力下保全自身并夺取最高控制权。",
    "visible_information": ["建文朝持续削藩", "燕王军事实力强但名义上受制于中央", "继续坐等会被进一步削弱"],
    "hidden_constraints": ["起兵若缺乏合法性叙事将难以争取人心", "战事拖长风险陡增", "定局之后还要重建统治秩序"],
    "options_available": ["接受削藩", "继续隐忍谈判", "以清君侧为名发动靖难之役"],
    "chosen_action": "朱棣起兵靖难，最终攻入南京。",
    "short_term_outcome": "明廷内部力量被迅速重组，建文朝失势。",
    "long_term_outcome": "朱棣即位，明朝权力中枢被重新塑造。",
    "success_or_failure": "success",
    "key_reasons": ["把生存危机转为主动争权", "叙事包装与军事行动并行", "成功后迅速重建统治框架"],
    "transferable_principles": ["当收权动作已逼近生死线时，被动等待往往不是低风险选项", "控制权争夺中，叙事、联盟和执行速度必须同步推进"],
    "non_transferable_factors": ["宗室起兵与帝位争夺属于高烈度古代政治", "明代皇权和藩王结构没有现代直接类比"],
    "modern_analogy_keywords": ["接班争夺", "削权反击", "控制权逆转", "清君侧式叙事", "先手争权"],
    "source_note": "《明史·成祖本纪》"
  },
  {
    "id": "gaozu-baideng-and-heqin",
    "title": "汉高祖白登之围后转向和亲",
    "dynasty": "西汉",
    "era": "汉初",
    "year_range": "前200年前后",
    "main_figures": ["刘邦", "冒顿单于"],
    "summary": "西汉初立即遭匈奴强压，刘邦白登被围脱险后，没有继续硬拼，而是转向和亲与休养生息。",
    "situation_tags": ["守攻抉择", "以弱对强", "联盟不稳"],
    "decision_maker": "刘邦",
    "objective": "在国力尚弱的阶段先保全新政权并争取恢复时间。",
    "visible_information": ["匈奴兵势强盛", "汉朝刚建立不久", "继续北伐成本极高"],
    "hidden_constraints": ["情绪上难以接受退让", "若继续硬碰可能伤及根本", "求和会损伤面子与短期叙事"],
    "options_available": ["继续对匈奴强攻", "全面退守", "先和亲稳边并转入休养生息"],
    "chosen_action": "白登脱险后采取和亲与恢复国力路线。",
    "short_term_outcome": "边境压力阶段性下降，新政权获得恢复空间。",
    "long_term_outcome": "为后续文景休养与汉武反攻积累条件，但也留下长期外交争议。",
    "success_or_failure": "mixed",
    "key_reasons": ["认清生存优先级高于面子", "把短期求稳当作争取时间的手段", "没有在最虚弱时继续决战"],
    "transferable_principles": ["目标从取胜切换到生存时，策略也必须同步切换", "暂时妥协不一定是软弱，前提是它确实换来了恢复能力的时间"],
    "non_transferable_factors": ["汉匈关系属于古代边疆外交与战争体系", "和亲政策带有鲜明时代特征"],
    "modern_analogy_keywords": ["先求生存", "暂时妥协", "先守后图", "弱势阶段别决战", "保住基本盘"],
    "source_note": "《史记·高祖本纪》"
  },
  {
    "id": "yuan-chonghuan-defend-ningyuan",
    "title": "袁崇焕宁远守城",
    "dynasty": "明",
    "era": "明末后金战争",
    "year_range": "1626年",
    "main_figures": ["袁崇焕", "努尔哈赤"],
    "summary": "在明军连遭挫败、后金锋锐正盛的背景下，袁崇焕采取坚城火器防守，在宁远打出关键防御胜利。",
    "situation_tags": ["以弱对强", "守攻抉择", "合法性"],
    "decision_maker": "袁崇焕",
    "objective": "用有限兵力稳住关宁防线，阻止敌军继续南压。",
    "visible_information": ["明军此前连败", "后金攻势凌厉", "正面野战对明军不利"],
    "hidden_constraints": ["弃城会导致防线全面动摇", "贸然出战会放大劣势", "必须用有限资源打出一场可见胜利稳住预期"],
    "options_available": ["弃城后撤", "出城决战", "坚守宁远并依托火器与城防消耗敌军"],
    "chosen_action": "选择固守宁远，以城防和火器挫败后金强攻。",
    "short_term_outcome": "后金受挫，明军士气明显回升。",
    "long_term_outcome": "宁远大捷成为明末少有的关键防守胜利。",
    "success_or_failure": "success",
    "key_reasons": ["清楚知道不能在不利地形硬碰", "把有限优势集中在可控防御场景", "用一场守住的胜利重建信心"],
    "transferable_principles": ["处在弱势时，先把战场拉到自己最熟悉的场景，比盲目求快更重要", "守得住本身也可以是战略胜利"],
    "non_transferable_factors": ["明末火器、边墙与辽东地理条件特殊", "军事围攻与现代竞争并不完全同构"],
    "modern_analogy_keywords": ["以弱守强", "守住关键阵地", "不能出城硬碰", "防御反击", "打一场止跌胜利"],
    "source_note": "《明史·袁崇焕传》"
  },
  {
    "id": "li-guangbi-defend-taiyuan",
    "title": "李光弼守太原",
    "dynasty": "唐",
    "era": "安史之乱",
    "year_range": "756年-757年",
    "main_figures": ["李光弼"],
    "summary": "安史叛军势大时，李光弼守太原不乱，以坚守和择机出击撑住唐军关键据点。",
    "situation_tags": ["以弱对强", "守攻抉择", "合法性"],
    "decision_maker": "李光弼",
    "objective": "守住北方战略重镇，为整体战局争取缓冲与反转空间。",
    "visible_information": ["叛军来势极盛", "太原地位关键", "援军与资源都不宽裕"],
    "hidden_constraints": ["失守会带来连锁崩盘", "长期围困会消耗士气和补给", "只能在极有限条件下组织反击"],
    "options_available": ["弃守太原", "贸然出城决战", "坚守城池并择机进行有限出击"],
    "chosen_action": "以坚守为主、局部出击为辅，稳住太原防线。",
    "short_term_outcome": "叛军难以迅速拿下重镇，节奏被拖慢。",
    "long_term_outcome": "太原得保，为唐廷整体反攻争取到重要支点。",
    "success_or_failure": "success",
    "key_reasons": ["明确据点价值高于一时得失", "守中有攻而不是纯被动挨打", "把时间变成己方资源"],
    "transferable_principles": ["关键节点一旦丢失后果巨大时，稳住它本身就是最优先任务", "防守成功的本质是让时间站到自己这一边"],
    "non_transferable_factors": ["安史之乱的战争环境极端特殊", "古代守城资源调度与现代组织运营存在本质差异"],
    "modern_analogy_keywords": ["关键据点", "稳住防线", "守中带攻", "时间换空间", "关键节点不能丢"],
    "source_note": "《旧唐书·李光弼传》"
  },
  {
    "id": "pei-du-campaign-against-huaixi",
    "title": "裴度督战平淮西",
    "dynasty": "唐",
    "era": "元和中兴",
    "year_range": "816年-817年",
    "main_figures": ["裴度", "唐宪宗", "李愬", "吴元济"],
    "summary": "淮西长期割据、朝廷屡战不决之际，裴度主张坚定用兵并督战到底，最终配合李愬奇袭蔡州平定淮西。",
    "situation_tags": ["权力控制", "内部冲突", "守攻抉择"],
    "decision_maker": "唐宪宗",
    "objective": "打破地方割据，恢复中央对藩镇的实际控制。",
    "visible_information": ["淮西长期尾大不掉", "朝廷此前屡次久攻不下", "继续放任将持续损害中央威信"],
    "hidden_constraints": ["战争拖长会加重财政和政治疲劳", "若半途议和将进一步坐实藩镇割据", "需要中央决心与前线执行高度一致"],
    "options_available": ["继续姑息藩镇", "边打边和", "坚定督战并寻找决胜窗口"],
    "chosen_action": "任用裴度督战，坚持平淮西，最终由李愬雪夜袭蔡州定局。",
    "short_term_outcome": "朝廷战略意志统一，关键战役获得突破。",
    "long_term_outcome": "淮西平定，唐宪宗中央权威显著上升。",
    "success_or_failure": "success",
    "key_reasons": ["中央决心与前线执行形成闭环", "没有在疲劳期半途而废", "抓住了长期僵局中的决胜窗口"],
    "transferable_principles": ["处理地方割据或分支失控时，最怕的不是一时困难，而是长期摇摆", "总部一旦决定收权，就要让决心、执行与窗口判断保持一致"],
    "non_transferable_factors": ["唐代藩镇体制与现代分支管理不同", "平藩战争具有高烈度军事背景"],
    "modern_analogy_keywords": ["地方割据", "尾大不掉", "总部收权", "长期僵局", "关键分支失控", "中央决心"],
    "source_note": "《旧唐书·裴度传》"
  }
]


path: data/user_cases.json

path: examples/01_internal_conflict.md
content: # 示例 1：内斗

用户输入：

```text
我接手一个团队后发现内部两派互相掣肘，我手里资源不多，但两个月内必须把新制度推下去，我该怎么做？
```

预期分析方向：

- 主局面：内部冲突
- 次局面：改革推进、以弱对强
- 优先比较王安石变法、张居正整顿、吴起变法

预期输出摘要：

- 先识别关键执行层站位
- 不能直接全面强推
- 至少给出“先稳关键中层”“试点推进”“强授权直推”三条路径


path: examples/02_expansion_timing.md
content: # 示例 2：扩张

用户输入：

```text
我们是行业第二，头部公司体量远大于我们。现在对方组织反应变慢，我要不要趁窗口期开打价格战和渠道战？
```

预期分析方向：

- 主局面：以弱对强
- 次局面：守攻抉择
- 参考官渡之战、昆阳之战、韩信暗度陈仓

预期输出摘要：

- 不建议全面对撞
- 重点识别单点突破和时间窗口
- 生成“集中突破”“暂避锋芒”“借势结盟”等路径


path: examples/03_reform_push.md
content: # 示例 3：改革

用户输入：

```text
公司多年积弊太深，我被授权做组织变革，但很多中层表面支持、实际拖延，我是该快推还是先试点？
```

预期分析方向：

- 主局面：改革推进
- 次局面：内部冲突
- 参考商鞅变法、王安石变法、张居正改革

预期输出摘要：

- 重点讨论执行链、利益补偿、时间窗口
- 必须输出“试点推进”“先整执行链”“强授权直推”三条路径


path: examples/04_alliance_instability.md
content: # 示例 4：联盟

用户输入：

```text
我现在必须联合一个我并不完全信任的合作方去对抗更强的竞争者，但我担心项目一有进展对方就翻脸。
```

预期分析方向：

- 主局面：联盟不稳
- 次局面：以弱对强
- 参考赤壁联盟、郭子仪稳回纥、六国合纵失效

预期输出摘要：

- 先做利益绑定和退出成本设计
- 明确“绑定利益”“留足后手”“制造共同敌压”三条路径


path: examples/05_leadership_change.md
content: # 示例 5：换人

用户输入：

```text
业务负责人能力一般，但直接换人会造成团队恐慌。是先削权再换，还是先改打法保人？
```

预期分析方向：

- 主局面：用人换将
- 次局面：权力控制
- 参考赵匡胤杯酒释兵权、戚继光练兵、刘备延揽诸葛亮

预期输出摘要：

- 分析替补质量、交接成本、信号效应
- 路径至少包含“先调权后换人”“立即换将”“保人换打法”


path: examples/06_defense_or_attack.md
content: # 示例 6：防御

用户输入：

```text
我们现金流吃紧，外部对手正在试探，但如果我现在全面出击，一旦失手可能连基本盘都保不住，该怎么选？
```

预期分析方向：

- 主局面：守攻抉择
- 次局面：以弱对强
- 参考周亚夫、左宗棠、官渡之战

预期输出摘要：

- 先分析基本盘、补给、战果可见性
- 输出“守住基本盘”“有限出击”“全面推进”三条差异化路径


path: examples/07_control_game.md
content: # 示例 7：控制权博弈

用户输入：

```text
公司董事会里有人想架空我，我名义上有授权，但实际关键流程被别人卡住，我该怎么办？
```

预期分析方向：

- 主局面：权力控制
- 次局面：内部冲突
- 参考高平陵政变、玄武门之变、杯酒释兵权

预期输出摘要：

- 重点看形式权威与实际控制是否一致
- 给出“先拿中枢”“借规则整权”“快刀定局”路径比较


path: examples/08_regional_revolt.md
content: # 示例 8：地方割据 / 分支失控

用户输入：

```text
几个大区负责人尾大不掉，总部一直拖着不敢动。我现在若不处理，未来更难控；但现在动，又可能一起反弹。
```

预期分析方向：

- 主局面：权力控制
- 次局面：内部冲突、守攻抉择
- 参考康熙削三藩、周亚夫平七国

预期输出摘要：

- 必须评估拖延成本和第一波反扑承受力
- 区分“继续安抚”“局部拖延”“果断处理”三种路线


path: examples/09_rebuild_team.md
content: # 示例 9：重建团队

用户输入：

```text
现有团队已经明显打不动新竞争环境了，继续修补还是从头搭一支新团队？
```

预期分析方向：

- 主局面：用人换将
- 次局面：改革推进
- 参考戚继光练兵、曾国藩创建湘军、洋务运动的制度短板

预期输出摘要：

- 不能只讨论换人，要讨论训练、流程、激励是否同步重构
- 重点比较“旧体系修补”和“新体系重建”的边界


path: examples/10_external_pressure.md
content: # 示例 10：外部高压与求稳

用户输入：

```text
外部大环境很差，我真正目标不是赢一仗，而是先把组织活下来。这种情况下是不是该主动收缩？
```

预期分析方向：

- 主局面：守攻抉择
- 次局面：合法性、以弱对强
- 参考澶渊决策、南宋和议路线、左宗棠先稳后攻

预期输出摘要：

- 先明确目标是“生存”还是“取胜”
- 输出中必须承认求稳策略的长期叙事代价


path: examples/11_add_case_to_library.md
content: # Natural Language Case Ingestion

## User Request

```text
把“赵武灵王胡服骑射”这个案例加入案例库，后续检索也要能用。核心局面是改革推进和以弱对强，关键决策是主动改制和推动军事转型，短期内阻力很大，但长期提升了赵国机动战力。来源请记《史记·赵世家》。
```

## Expected Skill Behavior

- 判断用户目标是“持久化入库”，不是临时分析
- 对缺失字段只追问 1-3 个关键问题
- 把自然语言整理成单条 JSON
- 调用本地脚本写入 `data/user_cases.json`
- 返回新增案例 `id`，并告知以后检索会自动加载


path: examples/case_submission_template.json
content: {
  "id": "new-historical-case-id",
  "title": "案例标题",
  "dynasty": "朝代或时期",
  "era": "历史阶段",
  "year_range": "时间范围",
  "main_figures": [
    "关键人物甲",
    "关键人物乙"
  ],
  "summary": "用 1-2 句话概括事件与局面。",
  "situation_tags": [
    "改革推进",
    "联盟不稳"
  ],
  "decision_maker": "主要决策者",
  "objective": "决策者想达成什么。",
  "visible_information": [
    "当时公开可见的条件 1",
    "当时公开可见的条件 2"
  ],
  "hidden_constraints": [
    "不易被外部直接看到的限制 1",
    "不易被外部直接看到的限制 2"
  ],
  "options_available": [
    "可选路径 1",
    "可选路径 2"
  ],
  "chosen_action": "最终采取的动作。",
  "short_term_outcome": "短期结果。",
  "long_term_outcome": "中长期结果。",
  "success_or_failure": "mixed",
  "key_reasons": [
    "成败原因 1",
    "成败原因 2"
  ],
  "transferable_principles": [
    "可迁移原则 1",
    "可迁移原则 2"
  ],
  "non_transferable_factors": [
    "不可直接照搬的因素 1",
    "不可直接照搬的因素 2"
  ],
  "modern_analogy_keywords": [
    "适用场景关键词 1",
    "适用场景关键词 2"
  ],
  "source_note": "史料来源或用户提供的来源说明"
}


path: manifest.json
content: {
  "display_name": "以史为鉴",
  "slug": "yi-shi-wei-jian",
  "repository_name": "LearnFromHistory-skill",
  "version": "0.1.4",
  "description": "以史为鉴 yi-shi-wei-jian: use/call this Chinese-history decision sandbox when users explicitly mention 以史为鉴、借古鉴今、历史类比、沙盘推演, or ask realistic organization/business/team strategy questions about reform, internal conflict, weak-vs-strong competition, unstable alliances, control rights, leadership replacement, attack/defense timing, or adding sourced historical cases.",
  "license": "MIT",
  "entry": "SKILL.md",
  "language": "zh-CN",
  "homepage": "https://github.com/GreatXiaoRY/LearnFromHistory-skill",
  "compatibility": [
    "claude-code",
    "openclaw",
    "agentskills-compatible"
  ],
  "distribution": {
    "type": "git",
    "repository": "https://github.com/GreatXiaoRY/LearnFromHistory-skill.git",
    "install_slug": "yi-shi-wei-jian"
  },
  "runtime": {
    "python": "3.10+",
    "external_api_required": false
  }
}


path: prompts/add_case_intake.md
content: # 新增案例入库提示

当用户要求“把一个新历史案例加入案例库”时，按下面流程执行：

1. 先判断这是不是要持久化入库，而不是临时举例。
2. 如果用户信息不完整，只追问 1-3 个最关键的问题。
3. 把用户的自然语言整理成单条 JSON，对齐案例模板。
4. 不要要求用户手工改仓库文件；优先由你直接调用本地脚本写入。
5. 写入成功后，返回新增案例的 `id`，并告知以后检索会自动加载。

必须补齐或确认的字段：

- `title`
- `summary`
- `situation_tags`
- `chosen_action`
- `key_reasons`
- `transferable_principles`
- `source_note`

推荐执行命令：

```powershell
@'
{
  "id": "example-case-id",
  "title": "案例标题",
  "dynasty": "朝代或时期",
  "era": "历史阶段",
  "year_range": "时间范围",
  "main_figures": ["人物甲", "人物乙"],
  "summary": "事件与局面概述",
  "situation_tags": ["改革推进"],
  "decision_maker": "主要决策者",
  "objective": "想达成的目标",
  "visible_information": ["公开条件 1"],
  "hidden_constraints": ["隐性限制 1"],
  "options_available": ["选项 1", "选项 2"],
  "chosen_action": "最终动作",
  "short_term_outcome": "短期结果",
  "long_term_outcome": "长期结果",
  "success_or_failure": "mixed",
  "key_reasons": ["原因 1"],
  "transferable_principles": ["原则 1"],
  "non_transferable_factors": ["不可照搬因素 1"],
  "modern_analogy_keywords": ["关键词 1"],
  "source_note": "来源说明"
}
'@ | python scripts/add_case.py --stdin
```

如果用户还没说清楚，不要编造史料或来源。


path: prompts/classify_situation.md
content: # classify_situation

任务：把用户的现实问题归类为一个主局面和一到两个次级局面。

## 操作步骤

1. 先做结构语义拆解，不要先盯字面词。
2. 至少抽取这些维度：目标、资源强弱、内部摩擦、外部压力、联盟依赖、信任风险、时间窗口、合法性约束、执行阻力、行动取向。
2. 在以下类别中选主局面：
   - 以弱对强
   - 内部冲突
   - 改革推进
   - 联盟不稳
   - 守攻抉择
   - 权力控制
   - 用人换将
3. 如果用户信息不足，最多提出 3 个澄清问题。
4. 如果不提问，必须明确你使用了哪些默认假设。
5. 如果用户只是随口说“我该怎么办”，优先把问题翻译成结构化局面，而不是先展开泛泛建议。

## 分类标准

- `以弱对强`：资源、地位、份额、正式权威明显弱于对手
- `内部冲突`：团队、股东、派系或关键执行层出现对抗
- `改革推进`：制度、流程、激励、组织结构需要改变
- `联盟不稳`：合作能带来收益，但承诺不牢、目标不一
- `守攻抉择`：要决定先守基本盘还是主动出击
- `权力控制`：控制权、任命权、继承、关键中枢归属
- `用人换将`：要不要换人、提拔、空降、削权、重配岗位

## 触发表达提示

下列表达通常意味着应该触发本 skill：

- “先稳内部还是先推进”
- “要不要换掉负责人”
- “合作方不太可信，还要不要联手”
- “我比对手弱很多，该怎么破局”
- “该守基本盘还是主动扩张”
- “控制权被架空了怎么办”

如果问题更像纯历史问答，就不要勉强套进决策辅助模式。

## 额外要求

- 不要把“出现了某个词”当成分类完成
- 要解释这个问题在结构上为什么更像某一类局面
- 如果一个问题同时有“推进”和“先稳住”的张力，优先把它视为真实的守攻抉择，而不是简单按单个词归类

## 输出

- 主局面
- 次局面
- 3 条以内判断依据
- 关键缺口或默认假设
- 如果有歧义，说明最容易混淆的另一个局面是什么


path: prompts/compare_cases.md
content: # compare_cases

任务：把已选案例做横向比较，找出用户真正该借鉴的结构，而不是表面动作。

## 比较维度

1. 谁占优势，优势来自哪里
2. 谁的内部一致性更强
3. 关键窗口期是什么
4. 决策动作是先守、先改、先结盟还是先收权
5. 结果好坏最核心的原因是什么

## 输出要求

- 提炼 3-5 条共性
- 提炼 2-3 条关键差异
- 指出哪条差异最影响现实可迁移性
- 明确写出“可迁移部分”和“不可直接照搬部分”

## 重点提醒

- 同样的动作，在不同约束下会得到不同结果
- 不要只说“都成功了”或“都失败了”
- 必须说明哪些条件可以借，哪些条件不能照搬
- 如果一个案例的失败机制特别清晰，要优先把那个失败机制抽出来


path: prompts/retrieve_cases.md
content: # retrieve_cases

任务：从案例库中选择 2-4 个与当前问题结构最接近的中国历史案例。

## 检索原则

1. 优先看结构语义，不优先看知名度，也不优先看字面词是否一致。
2. 重点对齐：
   - situation_tags
   - objective
   - hidden_constraints
   - chosen_action
   - key_reasons
   - modern_analogy_keywords 仅作辅助
3. 选出的案例要尽量形成对照：
   - 至少一个成功案例
   - 如有必要，加入一个失败或代价过高的案例
   - 如果问题是改革、联盟或控制权问题，优先加入一个“代价被低估”的反例
4. 如果多个案例都像，优先保留约束条件更像的那个。
5. 如果问题里出现“合作方翻脸、不完全信任、表面支持实则拖延、先削权再换人、先守后攻”等现代语句，不要只找同词案例，要优先匹配具有相同结构约束的案例。

## 每个案例必须输出

- 事件
- 核心局面
- 关键决策
- 成败原因
- 为什么像当前问题

## 避免事项

- 不要把“著名”误当成“相似”
- 不要只罗列故事，不解释对应关系
- 不要把历史结果直接当成现实预言
- 不要把“同属联盟/改革/换将”当成已经足够，相似点必须落到约束条件
- 不要把检索退化成关键词列表对碰


path: prompts/safety_boundary.md
content: # safety_boundary

任务：给出明确的风险与边界提醒，防止用户把历史类比误读成现实预测。

## 必须写出的两句话

- 历史类比 != 现实预测
- 推演 != 结果保证

## 还要补充说明

- 历史人物、制度、地理、技术条件不可直接照搬
- 输出只能作为结构化思考工具，不能替代专业判断
- 如果用户提供的信息不足，要提醒结论依赖假设
- 如果问题属于法律、医疗、投资等高风险领域，只保留框架性分析，不给结论性指令

## 语气要求

- 清晰
- 克制
- 不要神化历史
- 不要绝对化


path: prompts/sandbox_simulation.md
content: # sandbox_simulation

任务：对每条决策路径做沙盘推演。这是本 skill 的核心差异点。

## 必须逐路径分析

对每条路径，按下面 5 个维度写完整，不得省略：

1. 适用条件
2. 短期收益
3. 短期风险
4. 中期演化
5. 最容易失败点

## 推演方法

1. 先假设这条路径真的被执行
2. 判断执行后 1-4 周内最可能出现什么反应
3. 再判断 1-3 个周期后的局面会如何演化
4. 指出最容易导致整条路径失败的那个机制
5. 给出一个“应该在哪个观察点复盘或转向”的判断节点

## 重点变量

- 资源是否会被拉断
- 内部是否会分裂
- 对手是否会提前反制
- 盟友是否会摇摆
- 时间窗口是否会关闭
- 合法性是否会被削弱

## 禁止事项

- 不要写成空泛建议
- 不要只说“有风险”
- 不要输出“必胜”或“一定失败”
- 不要遗漏第二轮反应，例如中层拖延、盟友观望、对手提前反制、授权缩水


path: prompts/synthesize_advice.md
content: # synthesize_advice

任务：把局面判断、案例比较和变量分析，综合成 2-4 条现实决策路径。

## 生成路径时必须满足

- 每条路径互相有实质差异
- 每条路径都能映射到不同的历史结构
- 路径名字要简洁明确，例如：
  - 立即推进
  - 先稳内部
  - 暂避锋芒
  - 联盟博弈
  - 先调权后换人
  - 先试点再扩张

## 路径设计原则

1. 一条激进路径
2. 一条稳健路径
3. 一条折中或试点路径
4. 如果局面涉及联盟或换将，再补一条对应路径
5. 路径名称要能让用户一眼看懂，不要写成抽象空话
6. 每条路径都要明确呼应前面识别到的结构压力，而不是只换措辞

## 输出

- 路径名称
- 核心动作
- 适用前提
- 主要代价
- 优先借鉴的历史结构

## 额外要求

- 如果“先稳内部”和“立即推进”都可行，必须把它们拆成两条，而不是混成一条折中建议
- 如果问题涉及不可信盟友，至少有一条路径要体现“合作但留后手”
- 如果问题涉及换人，至少有一条路径要体现“先调权再换人”或“保人换打法”
- 不要把路径写成从同一个思路平移出来的改写版


path: README.md
content: <p align="center">
  <img alt="以史为鉴.skill" src="https://img.shields.io/badge/%E4%BB%A5%E5%8F%B2%E4%B8%BA%E9%89%B4.skill-Decision%20Sandbox-000000?style=for-the-badge">
</p>

<h1 align="center">以史为鉴.skill</h1>

<p align="center">
  <strong>把中国历史案例，变成现实决策的结构化分析与沙盘推演工具。</strong><br>
  <strong>Chinese History Decision Skill for Claude Code &amp; OpenClaw</strong><br>
  现实里的难题，往往不是缺一个建议，而是看不清自己身在什么局。<br>
  团队内耗、改革推不动、盟友不稳、资源不如对手、该换人还是再等等，<strong>以史为鉴.skill</strong> 会让 agent 先识局、再鉴史、最后推演可选路径的收益、风险和失败点。
</p>

<p align="center">
  <code>LearnFromHistory-skill</code> · <code>yi-shi-wei-jian</code>
</p>

<p align="center">
  <img alt="Python" src="https://img.shields.io/badge/Python-3.10%2B-3776AB?logo=python&logoColor=white">
  <img alt="License" src="https://img.shields.io/badge/License-MIT-16a34a">
  <img alt="Runtime" src="https://img.shields.io/badge/Runtime-Claude%20Code%20%7C%20OpenClaw-111827">
  <img alt="Skill Slug" src="https://img.shields.io/badge/Slug-yi--shi--wei--jian-7c3aed">
</p>

`LearnFromHistory-skill` 是一个面向 Claude Code 和 OpenClaw 的 Agent Skill。

它不做历史百科式讲解，而是把现实问题拆成三步：

- 识局：先判断你现在处在什么局
- 鉴史：再找 2-4 个结构相似的历史案例
- 推演：最后给出多条路径，并逐条做沙盘推演

如果你想做的不是“聊历史”，而是“借历史帮助决策”，这个仓库就是为这个场景设计的。

## Why This Skill

大多数“历史类比”工具的问题，不是不会举例，而是停在举例。

这个 skill 的目标是把历史案例真正转成可用的决策分析，固定输出：

- `【局面判断】`
- `【历史参照】`
- `【关键变量】`
- `【可选路径】`
- `【沙盘推演】`
- `【借鉴原则】`
- `【边界提醒】`

其中 `【沙盘推演】` 是核心差异点。它不会只给一句建议，而是把每条路径拆成：

- 适用条件
- 短期收益
- 短期风险
- 中期演化
- 最容易失败点

## What You Get

当前仓库已经包含：

- 40 条结构化中国历史案例
- 可持续扩充的用户案例库 `data/user_cases.json`
- 面向分类、检索、比较、推演和安全边界的 prompts
- 可本地运行的 Python CLI
- 发布检查、安装检查和自动化测试

项目身份如下：

| Item | Value |
| --- | --- |
| GitHub repository | `LearnFromHistory-skill` |
| Skill name | `以史为鉴` |
| Skill slug | `yi-shi-wei-jian` |
| Entry file | `SKILL.md` |
| Runtime | Python 3.10+ |
| License | MIT |

## A Quick Example

用户输入：

```text
我接手一个派系很重的团队，资源不多，但必须在两个月内推动新制度上线。我现在该先稳内部，还是直接推进改革？
```

skill 不会只回答“先稳后推”这种空话，而会输出类似这样的结构：

```text
【局面判断】
主局面：改革推进
次局面：内部冲突、以弱对强

【历史参照】
1. 秦孝公任用商鞅变法
2. 王安石变法
3. 吴起相楚变法受挫

【关键变量】
- 执行链条
- 利益补偿
- 时间窗口
- 合法性

【可选路径】
1. 先整执行链
2. 试点推进
3. 强授权直推
```

## Install In One Minute

### OpenClaw

ClawHub 安装：

```bash
clawhub install yi-shi-wei-jian
```

或者直接跟你的龙虾说：

```text
安装以史为鉴 skill
```

手动安装：

```bash
git clone https://github.com/GreatXiaoRY/LearnFromHistory-skill.git skills/yi-shi-wei-jian
```

### Claude Code

项目级安装：

```bash
git clone https://github.com/GreatXiaoRY/LearnFromHistory-skill.git .claude/skills/yi-shi-wei-jian
```

全局安装：

```bash
git clone https://github.com/GreatXiaoRY/LearnFromHistory-skill.git ~/.claude/skills/yi-shi-wei-jian
```

安装完成后重启会话，让宿主重新加载 `SKILL.md`。

## Natural Language Usage

分析现实问题：

```text
请用以史为鉴分析：我必须联合一个不完全信任的合作方，对抗更强的对手，但我担心项目一推进，对方就会翻脸。
```

新增案例入库：

```text
把“赵武灵王胡服骑射”这个案例加入案例库，后续检索也要能用。核心局面是改革推进和以弱对强，关键决策是主动改制，来源请记《史记·赵世家》。
```

安装后，宿主 agent 可以先补齐缺失字段，再把整理后的结构化案例写入本地库，供以后继续检索使用。

## Add New Cases

这个项目不把案例库写死在最初的 40 条里。

基础案例位于：

- `data/historical_cases.json`

用户新增案例位于：

- `data/user_cases.json`

查看新增案例模板：

```powershell
python src/main.py --print-case-template
```

从文件写入新案例：

```powershell
python scripts/add_case.py --case-file path\to\new_case.json
```

直接通过标准输入写入：

```powershell
@'
{ ... 单条案例 JSON ... }
'@ | python scripts/add_case.py --stdin
```

`--stdin` 这一条很重要，因为它让 Claude Code / OpenClaw 这类宿主可以把自然语言整理后的结构化结果直接写入案例库，而不要求用户手工编辑 JSON 文件。

## Local CLI

分析问题：

```powershell
python src/main.py --question "我接手一个派系很重的团队，资源不多，但必须在两个月内推动新制度上线，我该怎么布局？"
```

打印案例模板：

```powershell
python src/main.py --print-case-template
```

直接新增案例：

```powershell
python src/main.py --add-case-json "{...单条案例 JSON...}"
```

## Development

环境准备：

```powershell
python -m venv .venv
.venv\Scripts\Activate.ps1
pip install -r requirements.txt
```

本地验证：

```powershell
python scripts/validate_cases.py
python scripts/verify_install.py
python scripts/check_release.py
python -m unittest discover -s tests
```

`.github/workflows/ci.yml` 会在 GitHub Actions 中执行同样的检查。

## Project Structure

```text
LearnFromHistory-skill/
├─ SKILL.md
├─ README.md
├─ skill.json
├─ manifest.json
├─ data/
│  ├─ historical_cases.json
│  ├─ user_cases.json
│  └─ cases.schema.json
├─ prompts/
├─ examples/
├─ scripts/
├─ src/
└─ tests/
```

## Notes

- 仓库名是 `LearnFromHistory-skill`
- 技能安装目录必须是 `yi-shi-wei-jian`
- 仓库只使用本地数据和相对路径，不依赖外部 API
- `user_cases.json` 会随着用户新增案例持续扩充
- 项目结构已经按 Claude Code / OpenClaw / ClawHub 分发场景整理

## License

本仓库采用 [MIT License](LICENSE)。


path: requirements.txt
content: pytest>=8.3.0


path: scripts/add_case.py
content: from __future__ import annotations

import argparse
import json
import sys
from pathlib import Path


REPO_ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(REPO_ROOT / "src"))

from case_store import CaseStore, CaseValidationError, build_case_template  # noqa: E402


def read_stdin_text() -> str:
    return sys.stdin.buffer.read().decode("utf-8", errors="strict")


def build_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(description="将新增历史案例写入 data/user_cases.json。")
    parser.add_argument("--case-file", help="新增案例 JSON 文件路径。")
    parser.add_argument("--case-json", help="直接传入单条案例 JSON 字符串。")
    parser.add_argument("--stdin", action="store_true", help="从标准输入读取单条案例 JSON。")
    parser.add_argument("--print-template", action="store_true", help="输出案例模板 JSON。")
    parser.add_argument("--core-cases-path", help="基础案例库路径，默认 data/historical_cases.json。")
    parser.add_argument("--user-cases-path", help="用户案例库路径，默认 data/user_cases.json。")
    return parser


def main() -> int:
    parser = build_parser()
    args = parser.parse_args()

    if args.print_template:
        print(json.dumps(build_case_template(), ensure_ascii=False, indent=2))
        return 0

    input_modes = [bool(args.case_file), bool(args.case_json), bool(args.stdin)]
    if sum(input_modes) != 1:
        parser.error("请从 --case-file、--case-json 或 --stdin 中选择一种输入方式。")

    core_cases_path = Path(args.core_cases_path).expanduser().resolve() if args.core_cases_path else REPO_ROOT / "data" / "historical_cases.json"
    user_cases_path = Path(args.user_cases_path).expanduser().resolve() if args.user_cases_path else REPO_ROOT / "data" / "user_cases.json"
    store = CaseStore(core_cases_path, user_cases_path)

    try:
        if args.case_file:
            case_file = Path(args.case_file).expanduser().resolve()
            if not case_file.exists():
                print(f"案例文件不存在: {case_file}", file=sys.stderr)
                return 1
            candidate = store.load_case_candidate(case_file)
        elif args.case_json:
            candidate = store.parse_case_payload(args.case_json)
        else:
            candidate = store.parse_case_payload(read_stdin_text())
        added_case = store.add_case(candidate)
    except (CaseValidationError, json.JSONDecodeError) as exc:
        print(f"新增案例失败: {exc}", file=sys.stderr)
        return 1

    print(f"新增案例成功: {added_case['id']} -> {user_cases_path}")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())


path: scripts/check_release.py
content: from __future__ import annotations

import json
import sys
from pathlib import Path


REPO_ROOT = Path(__file__).resolve().parents[1]
EXPECTED_SLUG = "yi-shi-wei-jian"
EXPECTED_REPO = "LearnFromHistory-skill"
EXPECTED_HOMEPAGE = "https://github.com/GreatXiaoRY/LearnFromHistory-skill"
EXPECTED_LICENSE = "MIT"
ALLOWED_FRONTMATTER_KEYS = {
    "name",
    "description",
    "homepage",
    "user-invocable",
    "metadata",
}


def fail(message: str) -> int:
    print(message, file=sys.stderr)
    return 1


def parse_frontmatter(path: Path) -> dict[str, str]:
    content = path.read_text(encoding="utf-8")
    if not content.startswith("---\n"):
        raise ValueError("SKILL.md 缺少 YAML frontmatter。")

    end_marker = "\n---\n"
    end_index = content.find(end_marker, 4)
    if end_index == -1:
        raise ValueError("SKILL.md frontmatter 结束标记不正确。")

    frontmatter = content[4:end_index]
    result: dict[str, str] = {}
    for raw_line in frontmatter.splitlines():
        if not raw_line.strip():
            continue
        if ":" not in raw_line:
            raise ValueError(f"frontmatter 行格式无效: {raw_line}")
        key, value = raw_line.split(":", 1)
        key = key.strip()
        value = value.strip()
        if key in result:
            raise ValueError(f"frontmatter 存在重复字段: {key}")
        result[key] = value
    return result


def main() -> int:
    required_paths = [
        REPO_ROOT / "SKILL.md",
        REPO_ROOT / "README.md",
        REPO_ROOT / "LICENSE",
        REPO_ROOT / "skill.json",
        REPO_ROOT / "manifest.json",
        REPO_ROOT / "data" / "user_cases.json",
        REPO_ROOT / "examples" / "case_submission_template.json",
        REPO_ROOT / "prompts" / "add_case_intake.md",
        REPO_ROOT / "scripts" / "add_case.py",
        REPO_ROOT / "src" / "case_store.py",
        REPO_ROOT / ".clawhubignore",
        REPO_ROOT / ".github" / "workflows" / "ci.yml",
    ]
    missing = [str(path.relative_to(REPO_ROOT)) for path in required_paths if not path.exists()]
    if missing:
        return fail(f"缺少发布关键文件: {', '.join(missing)}")

    skill_json = json.loads((REPO_ROOT / "skill.json").read_text(encoding="utf-8"))
    manifest_json = json.loads((REPO_ROOT / "manifest.json").read_text(encoding="utf-8"))

    if skill_json.get("slug") != EXPECTED_SLUG:
        return fail("skill.json 的 slug 不正确。")
    if skill_json.get("repository_name") != EXPECTED_REPO:
        return fail("skill.json 的 repository_name 不正确。")
    if skill_json.get("license") != EXPECTED_LICENSE:
        return fail("skill.json 的 license 不正确。")
    if skill_json.get("homepage") != EXPECTED_HOMEPAGE:
        return fail("skill.json 的 homepage 不正确。")

    if manifest_json.get("slug") != EXPECTED_SLUG:
        return fail("manifest.json 的 slug 不正确。")
    if manifest_json.get("repository_name") != EXPECTED_REPO:
        return fail("manifest.json 的 repository_name 不正确。")
    if manifest_json.get("license") != EXPECTED_LICENSE:
        return fail("manifest.json 的 license 不正确。")
    if manifest_json.get("homepage") != EXPECTED_HOMEPAGE:
        return fail("manifest.json 的 homepage 不正确。")

    skill_version = skill_json.get("version")
    manifest_version = manifest_json.get("version")
    if not skill_version or skill_version != manifest_version:
        return fail("skill.json 与 manifest.json 的 version 不一致。")

    try:
        frontmatter = parse_frontmatter(REPO_ROOT / "SKILL.md")
    except ValueError as exc:
        return fail(str(exc))

    unexpected_keys = sorted(set(frontmatter) - ALLOWED_FRONTMATTER_KEYS)
    if unexpected_keys:
        return fail(f"SKILL.md frontmatter 包含非发布友好字段: {', '.join(unexpected_keys)}")

    if frontmatter.get("name") != EXPECTED_SLUG:
        return fail("SKILL.md frontmatter 的 name 必须等于 skill slug。")
    description = frontmatter.get("description", "")
    required_description_markers = [
        "请用/使用/调用",
        "以史为鉴",
        "借古鉴今",
        "历史类比",
        "沙盘推演",
        "organization/business/team",
        "reform",
        "internal conflict",
        "unstable alliance",
        "control-right",
        "leadership/personnel",
    ]
    for marker in required_description_markers:
        if marker not in description:
            return fail(f"SKILL.md frontmatter description 缺少触发提示: {marker}")
    if frontmatter.get("homepage") != EXPECTED_HOMEPAGE:
        return fail("SKILL.md frontmatter 的 homepage 不正确。")
    if frontmatter.get("user-invocable") != "true":
        return fail("SKILL.md frontmatter 的 user-invocable 必须为 true。")

    metadata_text = frontmatter.get("metadata")
    if not metadata_text:
        return fail("SKILL.md frontmatter 缺少 metadata。")

    try:
        metadata = json.loads(metadata_text)
    except json.JSONDecodeError as exc:
        return fail(f"SKILL.md frontmatter 的 metadata 不是有效 JSON: {exc}")

    if metadata.get("slug") != EXPECTED_SLUG:
        return fail("SKILL.md metadata.slug 不正确。")
    if metadata.get("repo_name") != EXPECTED_REPO:
        return fail("SKILL.md metadata.repo_name 不正确。")
    if metadata.get("version") != skill_version:
        return fail("SKILL.md metadata.version 必须与 JSON 元数据一致。")

    openclaw_metadata = metadata.get("openclaw", {})
    if openclaw_metadata.get("always") is True:
        return fail("SKILL.md metadata.openclaw.always 不能为 true，避免请求不必要的常驻权限。")
    if openclaw_metadata.get("skillKey") != EXPECTED_SLUG:
        return fail("SKILL.md metadata.openclaw.skillKey 不正确。")
    if openclaw_metadata.get("homepage") != EXPECTED_HOMEPAGE:
        return fail("SKILL.md metadata.openclaw.homepage 不正确。")

    license_text = (REPO_ROOT / "LICENSE").read_text(encoding="utf-8")
    if "MIT License" not in license_text:
        return fail("LICENSE 文件不是 MIT License。")

    clawhubignore = (REPO_ROOT / ".clawhubignore").read_text(encoding="utf-8").splitlines()
    if "AGENTS.md" not in {line.strip() for line in clawhubignore}:
        return fail(".clawhubignore 必须排除 AGENTS.md，避免把本地 agent 协作指令发布到 ClawHub。")

    readme = (REPO_ROOT / "README.md").read_text(encoding="utf-8")
    required_readme_markers = [
        EXPECTED_REPO,
        EXPECTED_SLUG,
        "以史为鉴",
        "OpenClaw",
        "--stdin",
        "user_cases.json",
        "MIT",
    ]
    for marker in required_readme_markers:
        if marker not in readme:
            return fail(f"README.md 缺少发布所需说明: {marker}")

    print("发布检查通过。")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())


path: scripts/validate_cases.py
content: from __future__ import annotations

import sys
from pathlib import Path


REPO_ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(REPO_ROOT / "src"))

from case_store import CaseStore, CaseValidationError  # noqa: E402


def main() -> int:
    store = CaseStore(REPO_ROOT / "data" / "historical_cases.json", REPO_ROOT / "data" / "user_cases.json")

    try:
        core_cases = store.load_core_cases()
        user_cases = store.load_user_cases()
        all_cases = store.load_all_cases()
    except CaseValidationError as exc:
        print(str(exc), file=sys.stderr)
        return 1

    print(f"案例校验通过，基础案例 {len(core_cases)} 条，用户案例 {len(user_cases)} 条，共 {len(all_cases)} 条。")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())


path: scripts/verify_install.py
content: from __future__ import annotations

import json
import os
import subprocess
import sys
from pathlib import Path


def main() -> int:
    repo_root = Path(__file__).resolve().parents[1]
    required_paths = [
        repo_root / "SKILL.md",
        repo_root / "README.md",
        repo_root / "skill.json",
        repo_root / "manifest.json",
        repo_root / "data" / "historical_cases.json",
        repo_root / "data" / "user_cases.json",
        repo_root / "examples" / "case_submission_template.json",
        repo_root / "prompts" / "add_case_intake.md",
        repo_root / "prompts" / "sandbox_simulation.md",
        repo_root / "scripts" / "add_case.py",
        repo_root / "src" / "case_store.py",
        repo_root / "src" / "main.py",
        repo_root / "tests" / "test_cli.py",
    ]

    missing = [str(path.relative_to(repo_root)) for path in required_paths if not path.exists()]
    if missing:
        print("缺少关键文件:", ", ".join(missing), file=sys.stderr)
        return 1

    skill_metadata = json.loads((repo_root / "skill.json").read_text(encoding="utf-8"))
    if skill_metadata.get("slug") != "yi-shi-wei-jian":
        print("skill.json 中的 slug 不正确。", file=sys.stderr)
        return 1

    result = subprocess.run(
        [
            sys.executable,
            str(repo_root / "src" / "main.py"),
            "--question",
            "公司内部出现派系对抗，我资源偏弱，但必须推进一项涉及利益调整的新制度。",
        ],
        capture_output=True,
        text=True,
        encoding="utf-8",
        errors="replace",
        env={**os.environ, "PYTHONIOENCODING": "utf-8"},
        check=False,
    )
    if result.returncode != 0:
        print(result.stderr, file=sys.stderr)
        return result.returncode

    template_result = subprocess.run(
        [
            sys.executable,
            str(repo_root / "src" / "main.py"),
            "--print-case-template",
        ],
        capture_output=True,
        text=True,
        encoding="utf-8",
        errors="replace",
        env={**os.environ, "PYTHONIOENCODING": "utf-8"},
        check=False,
    )
    if template_result.returncode != 0:
        print(template_result.stderr, file=sys.stderr)
        return template_result.returncode
    if '"id": "new-historical-case-id"' not in template_result.stdout:
        print("新增案例模板输出不正确。", file=sys.stderr)
        return 1

    required_sections = [
        "【局面判断】",
        "【历史参照】",
        "【关键变量】",
        "【可选路径】",
        "【沙盘推演】",
        "【借鉴原则】",
        "【边界提醒】",
    ]
    for section in required_sections:
        if section not in result.stdout:
            print(f"CLI 输出缺少 section: {section}", file=sys.stderr)
            return 1

    print("安装验证通过。")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())


path: skill.json
content: {
  "name": "以史为鉴",
  "slug": "yi-shi-wei-jian",
  "repository_name": "LearnFromHistory-skill",
  "version": "0.1.4",
  "description": "以史为鉴 yi-shi-wei-jian: use/call this Chinese-history decision sandbox when users explicitly mention 以史为鉴、借古鉴今、历史类比、沙盘推演, or ask realistic organization/business/team strategy questions about reform, internal conflict, weak-vs-strong competition, unstable alliances, control rights, leadership replacement, attack/defense timing, or adding sourced historical cases.",
  "author": "GreatXiaoRY",
  "license": "MIT",
  "language": "zh-CN",
  "entry": "SKILL.md",
  "homepage": "https://github.com/GreatXiaoRY/LearnFromHistory-skill",
  "platforms": [
    "claude-code",
    "openclaw",
    "agentskills-compatible"
  ],
  "tags": [
    "history",
    "chinese-history",
    "decision-support",
    "historical-analogy",
    "sandbox-simulation",
    "strategy",
    "china-history"
  ],
  "install": {
    "skill_dir": "skills/yi-shi-wei-jian",
    "project_skill_dir": ".claude/skills/yi-shi-wei-jian",
    "clone_target": "yi-shi-wei-jian",
    "copy_and_restart": true
  },
  "runtime": {
    "python": "3.10+",
    "external_api_required": false,
    "relative_paths_only": true
  },
  "capabilities": [
    "局面判断",
    "历史映射",
    "关键变量识别",
    "决策路径生成",
    "沙盘推演",
    "借鉴原则",
    "边界提醒"
  ]
}


path: src/analyzer.py
content: from __future__ import annotations

from dataclasses import dataclass

from classifier import SituationAssessment


@dataclass
class DecisionPath:
    name: str
    summary: str
    suitable_conditions: str
    short_term_benefit: str
    short_term_risk: str
    mid_term_evolution: str
    failure_point: str


class DecisionAnalyzer:
    VARIABLE_LIBRARY: dict[str, list[tuple[str, str]]] = {
        "以弱对强": [
            ("资源", "你能否集中有限资源打到决定性节点，而不是全面摊薄。"),
            ("时间窗口", "对手是否正处在迟缓、内耗或判断失真的窗口期。"),
            ("联盟稳定性", "你是否能借外力缩小正面硬碰的差距。"),
            ("对手状态", "对手是不是过度自信、线条过长或内部松动。"),
        ],
        "内部冲突": [
            ("内部一致性", "关键执行层是否愿意跟随你的节奏。"),
            ("合法性", "你是否握有公开授权或占据规则优势。"),
            ("信息控制", "冲突是否停留在局部，还是已经扩散成全面失序。"),
            ("关键人物", "谁是真正能改变局势的中间层与节点人物。"),
        ],
        "改革推进": [
            ("执行链条", "方案再正确，也要看谁来执行、谁会拖延。"),
            ("利益补偿", "改革是否给受损方留下缓冲空间。"),
            ("时间窗口", "现在适合全面推进，还是更适合局部试点。"),
            ("合法性", "你是否拥有足够的正式授权与叙事正当性。"),
        ],
        "联盟不稳": [
            ("共同敌人", "联盟是否真的有足够强的外部压力。"),
            ("承诺机制", "是否有可验证、可兑现的利益绑定。"),
            ("退出成本", "盟友翻脸时，代价是否足够高。"),
            ("后手", "即使联盟破裂，你是否仍有独立生存方案。"),
        ],
        "守攻抉择": [
            ("基本盘", "一旦出手失败，你还能守住什么。"),
            ("节奏", "此时推进是抢先，还是过早暴露自己。"),
            ("战果可见性", "短期内是否能形成可见成果。"),
            ("补给", "资源与组织是否足以支撑中期消耗。"),
        ],
        "权力控制": [
            ("形式权威", "名义上的授权是否支持你的动作。"),
            ("实际控制", "关键岗位、信息流、资源流谁在掌握。"),
            ("继任叙事", "你要证明自己是在稳局，而不是单纯夺权。"),
            ("反制能力", "对手若提前动作，你有没有快速收口的能力。"),
        ],
        "用人换将": [
            ("人岗匹配", "现在的问题到底是人不对，还是结构不对。"),
            ("替补质量", "换下去以后是否真有更稳的人接得住。"),
            ("交接成本", "换人后组织能否承受短期磨合损失。"),
            ("信号效应", "此次换人会给组织发出什么信号。"),
        ],
    }

    PATH_LIBRARY: dict[str, list[tuple[str, str, str, str, str, str]]] = {
        "以弱对强": [
            ("暂避锋芒", "避免正面消耗，把冲突拖到对手不舒服的场景。", "你没有短期硬碰条件，但有回旋空间。", "保全基本盘，降低被一击击溃的概率。", "容易被误判为软弱，内部士气可能波动。", "若能拖到对手失误，可转入主动局。", "拖延过久却没有建立新优势。"),
            ("集中突破", "把所有有限资源砸向最关键的一点。", "你能识别决定胜负的单点，并有足够执行力。", "一旦突破成功，局面会迅速改观。", "押错点位会导致资源清空。", "突破后可能带动中立方转向。", "没有建立后续跟进，首胜后反被反扑。"),
            ("借势结盟", "通过联盟补齐你最缺的一块短板。", "存在暂时利益一致的外部伙伴。", "快速缩小资源差距。", "盟友目标不完全一致，后续容易反噬。", "如果绑定机制设计得好，能形成稳定均势。", "把命运完全押给不稳定盟友。"),
        ],
        "内部冲突": [
            ("先稳关键中层", "先稳住执行链条，再处理公开冲突。", "你的主要风险来自组织失控。", "能迅速降低执行层离心。", "短期内看起来动作不够强。", "若中层站稳，后续清理与调整成本更低。", "误把核心反对者当成可安抚对象。"),
            ("公开定规矩", "先把边界和纪律公开化，压缩模糊空间。", "你掌握规则解释权或名义授权。", "可迅速提高组织可预期性。", "过早亮牌可能刺激对手提前联手。", "若执行到位，组织会回到规则轨道。", "规则出台后执行不一致，反而损伤威信。"),
            ("分化对手", "区分强硬反对者与摇摆者，避免把所有人推到一起。", "对方内部并非铁板一块。", "有机会降低正面冲突规模。", "操作过慢会被对手识破。", "成功后可形成局部倒向。", "没有给摇摆者真实收益，分化失败。"),
        ],
        "改革推进": [
            ("试点推进", "先做一块可见样板，再扩展制度。", "时间允许局部验证，且失败成本可控。", "能用结果为改革争取支持。", "试点范围太小会被视为无关痛痒。", "试点成功后可逐步扩面。", "样板没有做成，改革叙事当场受损。"),
            ("先整执行链", "先抓考核、节奏和责任链，再上大方案。", "改革阻力主要来自执行层，而非顶层共识。", "短期能看到纪律与效率改善。", "若没有同步解释，容易被理解为单纯加压。", "执行链稳定后，制度改革落地率会提升。", "只抓执行不调激励，后续反弹集中。"),
            ("强授权直推", "拿到最高授权后集中推进核心改革。", "你已有明确背书，且窗口期很短。", "速度快，能抢在阻力组织化前完成关键步骤。", "一旦首轮受挫，反对者会迅速结盟。", "如果第一阶段成果明显，后续阻力会下降。", "高估授权强度，低估基层消化能力。"),
        ],
        "联盟不稳": [
            ("先绑定利益", "先把分配、回报和退出成本写清楚。", "联盟仍愿意合作，但信任不足。", "能降低短期背刺概率。", "谈判成本高，速度变慢。", "规则清楚后联盟更可持续。", "只签原则不做执行约束。"),
            ("留足后手", "合作但不把核心生死线全部交出去。", "盟友价值高，但不可完全信任。", "即便联盟破裂，也不至于致命。", "合作深度不足，战果可能受限。", "中期可根据局势再决定是否加码。", "过度防范导致盟友感到你不可信。"),
            ("制造共同敌压", "把联盟内部差异压到共同外部压力之下。", "外部威胁真实且双方都承受不起。", "能迅速形成协同。", "一旦外部压力下降，联盟会重新松动。", "短期效果通常最好，但耐久度有限。", "误判外部威胁强度，联盟很快失去粘性。"),
        ],
        "守攻抉择": [
            ("守住基本盘", "先确保现金流、核心团队和关键阵地不失。", "你当前最怕的是一次失败后再无翻身资本。", "降低系统性崩盘风险。", "可能错失先手。", "若敌方后劲不足，你会赢得更长窗口。", "守得太久，团队转入消极心态。"),
            ("有限出击", "只打一个能验证方向的战役，不全面铺开。", "你需要信号性胜利，但资源不足以全面推进。", "有机会打出士气与预期。", "首战选错会伤害信心。", "若打赢，可转入更积极态势。", "把试探战误做决战。"),
            ("全面推进", "趁窗口期主动扩张，试图一次改写格局。", "机会窗口短，且你已有足够准备。", "一旦成功，收益最大。", "资源链容易被拉断。", "成则重塑秩序，败则伤到根本。", "补给与组织能力跟不上前线节奏。"),
        ],
        "权力控制": [
            ("先拿中枢", "优先控制关键岗位、信息流和审批链。", "名义授权不完全可靠，实际控制更重要。", "能迅速改变真实力量对比。", "动作过早可能激化全面对抗。", "若中枢稳定，后续整编成本会下降。", "只拿位置，不拿执行人。"),
            ("借规则整权", "用制度、任命和流程重排控制权，而非直接摊牌。", "你需要保住名分与合法性。", "更容易争取中间层支持。", "推进较慢，给对手留了反制窗口。", "如果节奏稳，组织会默认新秩序。", "规则变更后没有配套执行。"),
            ("快刀定局", "在对手尚未完成组织化前，快速定局。", "窗口很短，且你已有足够把握。", "避免长期消耗。", "失败即反噬。", "成则局面清晰，败则威信受重创。", "高估支持面，低估对方反扑。"),
        ],
        "用人换将": [
            ("先调权后换人", "先削减关键岗位权限，再做正式替换。", "直接换人会引发强反弹。", "减少换人时的系统性震荡。", "短期容易形成双轨并行。", "若交接顺利，可自然完成替换。", "权责不清，形成更大内耗。"),
            ("立即换将", "用明确动作重置信号和纪律。", "问题根源确实集中在人，而非结构。", "能快速释放组织信号。", "替补若接不住，局面会更坏。", "若新负责人能力足够，可迅速止损。", "把结构问题误判为单人问题。"),
            ("保人换打法", "先不换人，先改目标、节奏和协作方式。", "当前没有更好的替补，且问题部分来自结构失配。", "避免交接成本。", "若旧问题重复，会被视为优柔寡断。", "若打法调整有效，可为后续换人与否争取时间。", "没有配套监督，打法改革流于口号。"),
        ],
    }

    def analyze(self, question: str, assessment: SituationAssessment, cases: list[dict]) -> dict:
        variables = self._select_variables(assessment.primary, cases)
        paths = self._select_paths(assessment.primary)
        principles = self._collect_principles(cases)
        return {
            "situation": assessment,
            "cases": cases,
            "variables": variables,
            "paths": paths,
            "principles": principles,
            "boundary": [
                "历史类比 != 现实预测，历史只能提供结构参照，不提供确定答案。",
                "推演 != 结果保证，现实执行中的人、制度、技术和外部环境都可能改变结果。",
                "不要照搬历史人物的做法，应只借鉴背后的结构条件、节奏与失败机制。",
            ],
            "assumptions": self._build_assumptions(question),
        }

    def _select_variables(self, primary: str, cases: list[dict]) -> list[tuple[str, str]]:
        variables = list(self.VARIABLE_LIBRARY.get(primary, self.VARIABLE_LIBRARY["守攻抉择"]))
        if any("合法性" in case["situation_tags"] for case in cases):
            variables.append(("合法性", "你是否占据规则、名分或公开授权，这会决定很多动作能否被组织接受。"))
        deduped: list[tuple[str, str]] = []
        seen_names: set[str] = set()
        for name, explanation in variables:
            if name in seen_names:
                continue
            deduped.append((name, explanation))
            seen_names.add(name)
        return deduped[:6]

    def _select_paths(self, primary: str) -> list[DecisionPath]:
        raw_paths = self.PATH_LIBRARY.get(primary, self.PATH_LIBRARY["守攻抉择"])
        return [
            DecisionPath(
                name=name,
                summary=summary,
                suitable_conditions=suitable_conditions,
                short_term_benefit=short_term_benefit,
                short_term_risk=short_term_risk,
                mid_term_evolution=mid_term_evolution,
                failure_point=failure_point,
            )
            for name, summary, suitable_conditions, short_term_benefit, short_term_risk, mid_term_evolution, failure_point in raw_paths
        ]

    def _collect_principles(self, cases: list[dict]) -> list[str]:
        principles: list[str] = []
        for case in cases:
            for principle in case["transferable_principles"]:
                if principle not in principles:
                    principles.append(principle)
        return principles[:5]

    def _build_assumptions(self, question: str) -> list[str]:
        assumptions = []
        if not any(keyword in question for keyword in ["预算", "资源", "现金流", "人手"]):
            assumptions.append("默认你当前资源不是无限的，需要在关键节点集中投入。")
        if not any(keyword in question for keyword in ["上级", "董事会", "授权", "合法"]):
            assumptions.append("默认你并没有完全不受约束的最高授权，需要考虑合法性与组织接受度。")
        if not any(keyword in question for keyword in ["盟友", "合作方", "股东", "伙伴"]):
            assumptions.append("默认外部支持并不稳定，不能把成败全部押在联盟上。")
        return assumptions


path: src/case_store.py
content: from __future__ import annotations

import json
import re
from pathlib import Path


REQUIRED_FIELDS = {
    "id",
    "title",
    "dynasty",
    "era",
    "year_range",
    "main_figures",
    "summary",
    "situation_tags",
    "decision_maker",
    "objective",
    "visible_information",
    "hidden_constraints",
    "options_available",
    "chosen_action",
    "short_term_outcome",
    "long_term_outcome",
    "success_or_failure",
    "key_reasons",
    "transferable_principles",
    "non_transferable_factors",
    "modern_analogy_keywords",
    "source_note",
}

FIELD_ORDER = [
    "id",
    "title",
    "dynasty",
    "era",
    "year_range",
    "main_figures",
    "summary",
    "situation_tags",
    "decision_maker",
    "objective",
    "visible_information",
    "hidden_constraints",
    "options_available",
    "chosen_action",
    "short_term_outcome",
    "long_term_outcome",
    "success_or_failure",
    "key_reasons",
    "transferable_principles",
    "non_transferable_factors",
    "modern_analogy_keywords",
    "source_note",
]

LIST_FIELDS = {
    "main_figures",
    "situation_tags",
    "visible_information",
    "hidden_constraints",
    "options_available",
    "key_reasons",
    "transferable_principles",
    "non_transferable_factors",
    "modern_analogy_keywords",
}

STRING_FIELDS = REQUIRED_FIELDS - LIST_FIELDS
VALID_OUTCOMES = {"success", "failure", "mixed"}
ID_PATTERN = re.compile(r"^[a-z0-9-]+$")


class CaseValidationError(ValueError):
    pass


def build_case_template() -> dict:
    return {
        "id": "new-historical-case-id",
        "title": "案例标题",
        "dynasty": "朝代或时期",
        "era": "历史阶段",
        "year_range": "时间范围",
        "main_figures": ["关键人物甲", "关键人物乙"],
        "summary": "用 1-2 句话概括事件与局面。",
        "situation_tags": ["改革推进", "联盟不稳"],
        "decision_maker": "主要决策者",
        "objective": "决策者想达成什么。",
        "visible_information": ["当时公开可见的条件 1", "当时公开可见的条件 2"],
        "hidden_constraints": ["不易被外部直接看到的限制 1", "不易被外部直接看到的限制 2"],
        "options_available": ["可选路径 1", "可选路径 2"],
        "chosen_action": "最终采取的动作。",
        "short_term_outcome": "短期结果。",
        "long_term_outcome": "中长期结果。",
        "success_or_failure": "mixed",
        "key_reasons": ["成败原因 1", "成败原因 2"],
        "transferable_principles": ["可迁移原则 1", "可迁移原则 2"],
        "non_transferable_factors": ["不可直接照搬的因素 1", "不可直接照搬的因素 2"],
        "modern_analogy_keywords": ["适用场景关键词 1", "适用场景关键词 2"],
        "source_note": "史料来源或用户提供的来源说明",
    }


class CaseStore:
    def __init__(self, core_cases_path: Path, user_cases_path: Path | None = None) -> None:
        self.core_cases_path = core_cases_path
        self.user_cases_path = user_cases_path or core_cases_path.with_name("user_cases.json")
        self.ensure_user_cases_file()

    def ensure_user_cases_file(self) -> None:
        if not self.user_cases_path.exists():
            self.user_cases_path.write_text("[]\n", encoding="utf-8")

    def load_core_cases(self) -> list[dict]:
        cases = self._load_cases(self.core_cases_path)
        if len(cases) < 40:
            raise CaseValidationError("基础案例数量不足，至少需要 40 条。")
        return cases

    def load_user_cases(self) -> list[dict]:
        return self._load_cases(self.user_cases_path)

    def load_all_cases(self) -> list[dict]:
        all_cases = self.load_core_cases() + self.load_user_cases()
        self._ensure_unique_ids(all_cases)
        return all_cases

    def add_case(self, case: dict) -> dict:
        normalized = self.normalize_case(case)
        existing_cases = self.load_all_cases()
        existing_ids = {item["id"] for item in existing_cases}
        if normalized["id"] in existing_ids:
            raise CaseValidationError(f"案例 id 已存在: {normalized['id']}")

        user_cases = self.load_user_cases()
        user_cases.append(normalized)
        self.user_cases_path.write_text(
            json.dumps(user_cases, ensure_ascii=False, indent=2) + "\n",
            encoding="utf-8",
        )
        return normalized

    def load_case_candidate(self, path: Path) -> dict:
        payload = self.parse_case_payload(path.read_text(encoding="utf-8"))
        return payload

    def parse_case_payload(self, payload_text: str) -> dict:
        payload = json.loads(payload_text)
        if isinstance(payload, list):
            if len(payload) != 1:
                raise CaseValidationError("新增案例文件必须是单个对象，或只包含 1 条案例的数组。")
            payload = payload[0]
        if not isinstance(payload, dict):
            raise CaseValidationError("新增案例文件必须是 JSON 对象。")
        return payload

    def _load_cases(self, path: Path) -> list[dict]:
        if not path.exists():
            return []

        payload = json.loads(path.read_text(encoding="utf-8"))
        if not isinstance(payload, list):
            raise CaseValidationError(f"{path.name} 必须是案例数组。")

        normalized_cases = [self.normalize_case(case) for case in payload]
        self._ensure_unique_ids(normalized_cases, source_name=path.name)
        return normalized_cases

    def normalize_case(self, case: dict) -> dict:
        if not isinstance(case, dict):
            raise CaseValidationError("案例必须是 JSON 对象。")

        missing = REQUIRED_FIELDS - set(case)
        if missing:
            raise CaseValidationError(f"案例缺少字段: {sorted(missing)}")

        extra = set(case) - REQUIRED_FIELDS
        if extra:
            raise CaseValidationError(f"案例包含未定义字段: {sorted(extra)}")

        normalized: dict[str, str | list[str]] = {}
        for field in FIELD_ORDER:
            value = case[field]
            if field in LIST_FIELDS:
                if not isinstance(value, list):
                    raise CaseValidationError(f"字段 {field} 必须是数组。")
                items = [str(item).strip() for item in value if str(item).strip()]
                if not items:
                    raise CaseValidationError(f"字段 {field} 不能为空数组。")
                if field == "options_available" and len(items) < 2:
                    raise CaseValidationError("字段 options_available 至少需要 2 个选项。")
                normalized[field] = items
                continue

            text = str(value).strip()
            if not text:
                raise CaseValidationError(f"字段 {field} 不能为空。")
            normalized[field] = text

        case_id = str(normalized["id"])
        if not ID_PATTERN.match(case_id):
            raise CaseValidationError("字段 id 只能包含小写字母、数字和连字符。")

        if normalized["success_or_failure"] not in VALID_OUTCOMES:
            raise CaseValidationError("字段 success_or_failure 必须是 success、failure 或 mixed。")

        return normalized  # type: ignore[return-value]

    def _ensure_unique_ids(self, cases: list[dict], source_name: str = "案例集合") -> None:
        seen_ids: set[str] = set()
        for case in cases:
            case_id = case["id"]
            if case_id in seen_ids:
                raise CaseValidationError(f"{source_name} 中存在重复案例 id: {case_id}")
            seen_ids.add(case_id)


path: src/classifier.py
content: from __future__ import annotations

from dataclasses import dataclass

from structural_semantics import StructuralProfile, infer_question_profile


@dataclass
class SituationAssessment:
    primary: str
    secondary: list[str]
    scores: dict[str, int]
    structural_profile: StructuralProfile
    rationale: list[str]


class SituationClassifier:
    CATEGORY_DESCRIPTIONS = {
        "以弱对强": "资源偏弱且外部压力强",
        "内部冲突": "内部摩擦与执行掣肘已经影响决策",
        "改革推进": "核心难题在于制度、流程或利益重分配",
        "联盟不稳": "需要借力合作，但信任与目标一致性不足",
        "守攻抉择": "关键决策在于先稳住还是主动推进",
        "权力控制": "控制权、任命权或组织中枢归属存在压力",
        "用人换将": "问题聚焦在人事调整与岗位重配",
    }

    def classify(self, question: str) -> SituationAssessment:
        profile = infer_question_profile(question)
        scores = self._score_categories(profile, question)
        ranked = sorted(scores.items(), key=lambda item: item[1], reverse=True)

        primary = ranked[0][0] if ranked and ranked[0][1] > 0 else "守攻抉择"
        secondary = [category for category, score in ranked[1:3] if score > 0]

        rationale = self._build_rationale(primary, secondary, profile, scores)
        return SituationAssessment(
            primary=primary,
            secondary=secondary,
            scores=scores,
            structural_profile=profile,
            rationale=rationale,
        )

    def _score_categories(self, profile: StructuralProfile, question: str) -> dict[str, int]:
        scores = {category: 0 for category in self.CATEGORY_DESCRIPTIONS}
        dims = profile.dimensions

        if dims["resource_state"] == "scarce":
            scores["以弱对强"] += 4
        if dims["external_pressure"] == "high":
            scores["以弱对强"] += 4
            scores["守攻抉择"] += 1
        elif dims["external_pressure"] == "medium":
            scores["以弱对强"] += 2

        if dims["internal_friction"] == "high":
            scores["内部冲突"] += 5
        elif dims["internal_friction"] == "medium":
            scores["内部冲突"] += 2

        if dims["change_pressure"] == "high":
            scores["改革推进"] += 5
        elif dims["change_pressure"] == "medium":
            scores["改革推进"] += 2

        if dims["execution_resistance"] == "high":
            scores["改革推进"] += 3
            scores["内部冲突"] += 2
        elif dims["execution_resistance"] == "medium":
            scores["改革推进"] += 1

        if dims["alliance_dependency"] == "high":
            scores["联盟不稳"] += 4
        elif dims["alliance_dependency"] == "medium":
            scores["联盟不稳"] += 2

        if dims["trust_risk"] == "high":
            scores["联盟不稳"] += 5
        elif dims["trust_risk"] == "medium":
            scores["联盟不稳"] += 2

        if dims["control_pressure"] == "high":
            scores["权力控制"] += 5
        elif dims["control_pressure"] == "medium":
            scores["权力控制"] += 2

        if dims["personnel_pressure"] == "high":
            scores["用人换将"] += 5
        elif dims["personnel_pressure"] == "medium":
            scores["用人换将"] += 2

        if dims["legitimacy_pressure"] == "high":
            scores["权力控制"] += 2
            scores["改革推进"] += 2
            scores["内部冲突"] += 1
        elif dims["legitimacy_pressure"] == "medium":
            scores["权力控制"] += 1
            scores["改革推进"] += 1

        if dims["time_pressure"] == "high":
            scores["守攻抉择"] += 3
            scores["改革推进"] += 1
        elif dims["time_pressure"] == "medium":
            scores["守攻抉择"] += 1

        action_bias = dims["action_bias"]
        if action_bias in {"advance", "consolidate", "mixed"}:
            scores["守攻抉择"] += 4
        if action_bias == "ally":
            scores["联盟不稳"] += 2
        if action_bias == "replace":
            scores["用人换将"] += 2
            scores["权力控制"] += 1

        if "控制权" in question and dims["personnel_pressure"] != "low":
            scores["权力控制"] += 1
        if "先稳内部还是" in question or "该守还是该攻" in question:
            scores["守攻抉择"] += 2

        return scores

    def _build_rationale(
        self,
        primary: str,
        secondary: list[str],
        profile: StructuralProfile,
        scores: dict[str, int],
    ) -> list[str]:
        focus = profile.active_focus(limit=4)
        rationale: list[str] = []
        if focus:
            rationale.append(f"识别到的结构信号：{'、'.join(focus)}。")
        rationale.append(f"主局面判为“{primary}”，因为它最能解释当前问题的核心矛盾：{self.CATEGORY_DESCRIPTIONS[primary]}。")
        for category in secondary:
            if scores.get(category, 0) > 0:
                rationale.append(f"次级局面补充为“{category}”，因为问题里同时存在：{self.CATEGORY_DESCRIPTIONS[category]}。")
        return rationale


path: src/main.py
content: from __future__ import annotations

import argparse
import json
import sys
from pathlib import Path

from analyzer import DecisionAnalyzer
from case_store import CaseStore, CaseValidationError, build_case_template
from classifier import SituationClassifier
from renderer import ResponseRenderer
from retriever import CaseRetriever


def read_stdin_text() -> str:
    return sys.stdin.buffer.read().decode("utf-8", errors="strict")


def build_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(description="以史为鉴：把中国历史案例映射到现实决策问题。")
    parser.add_argument("question_text", nargs="*", help="待分析的问题。")
    parser.add_argument("--question", dest="question", help="待分析的问题。")
    parser.add_argument("--top-k", type=int, default=3, help="返回案例数量，默认 3。")
    parser.add_argument("--add-case-file", help="将新增案例 JSON 写入 data/user_cases.json。")
    parser.add_argument("--add-case-json", help="直接传入单条案例 JSON 字符串，并写入 data/user_cases.json。")
    parser.add_argument("--add-case-stdin", action="store_true", help="从标准输入读取单条案例 JSON，并写入 data/user_cases.json。")
    parser.add_argument("--print-case-template", action="store_true", help="输出新增案例模板 JSON。")
    parser.add_argument("--core-cases-path", help="基础案例库路径，默认 data/historical_cases.json。")
    parser.add_argument("--user-cases-path", help="用户案例库路径，默认 data/user_cases.json。")
    return parser


def main() -> int:
    parser = build_parser()
    args = parser.parse_args()

    repo_root = Path(__file__).resolve().parents[1]
    cases_path = Path(args.core_cases_path).expanduser().resolve() if args.core_cases_path else repo_root / "data" / "historical_cases.json"
    user_cases_path = Path(args.user_cases_path).expanduser().resolve() if args.user_cases_path else repo_root / "data" / "user_cases.json"
    store = CaseStore(cases_path, user_cases_path)

    if args.print_case_template:
        print(json.dumps(build_case_template(), ensure_ascii=False, indent=2))
        return 0

    add_case_modes = [bool(args.add_case_file), bool(args.add_case_json), bool(args.add_case_stdin)]
    if sum(add_case_modes) > 1:
        parser.error("请从 --add-case-file、--add-case-json 或 --add-case-stdin 中选择一种新增案例输入方式。")

    if args.add_case_file or args.add_case_json or args.add_case_stdin:
        try:
            if args.add_case_file:
                candidate = store.load_case_candidate(Path(args.add_case_file).expanduser().resolve())
            elif args.add_case_json:
                candidate = store.parse_case_payload(args.add_case_json)
            else:
                candidate = store.parse_case_payload(read_stdin_text())
            added_case = store.add_case(candidate)
        except (CaseValidationError, FileNotFoundError, json.JSONDecodeError) as exc:
            print(f"新增案例失败: {exc}", file=sys.stderr)
            return 1
        print(f"新增案例成功: {added_case['id']} -> {user_cases_path}")
        return 0

    question = args.question or " ".join(args.question_text).strip()
    if not question:
        parser.error("请通过 --question 或位置参数提供问题。")

    classifier = SituationClassifier()
    retriever = CaseRetriever(cases_path, user_cases_path)
    analyzer = DecisionAnalyzer()
    renderer = ResponseRenderer()

    assessment = classifier.classify(question)
    cases = retriever.retrieve(question, assessment, top_k=max(2, min(args.top_k, 4)))
    analysis = analyzer.analyze(question, assessment, cases)
    print(renderer.render(analysis))
    return 0


if __name__ == "__main__":
    raise SystemExit(main())


path: src/renderer.py
content: from __future__ import annotations


class ResponseRenderer:
    def render(self, analysis: dict) -> str:
        situation = analysis["situation"]
        cases = analysis["cases"]
        variables = analysis["variables"]
        paths = analysis["paths"]
        principles = analysis["principles"]
        assumptions = analysis["assumptions"]

        sections: list[str] = []

        sections.append("【局面判断】")
        sections.append(f"主局面：{situation.primary}")
        if situation.secondary:
            sections.append(f"次局面：{'、'.join(situation.secondary)}")
        if assumptions:
            sections.append("默认假设：")
            sections.extend([f"- {item}" for item in assumptions])
        sections.append("判断依据：")
        sections.extend([f"- {item}" for item in situation.rationale])
        sections.append("")

        sections.append("【历史参照】")
        for index, case in enumerate(cases, start=1):
            sections.append(f"{index}. {case['title']}（{case['dynasty']}）")
            sections.append(f"- 事件：{case['summary']}")
            sections.append(f"- 核心局面：{'、'.join(case['situation_tags'])}")
            sections.append(f"- 关键决策：{case['chosen_action']}")
            sections.append(f"- 成败原因：{'；'.join(case['key_reasons'])}")
            if case.get("_match_reasons"):
                sections.append(f"- 为什么像当前问题：{'；'.join(case['_match_reasons'])}")
        sections.append("")

        sections.append("【关键变量】")
        for name, explanation in variables:
            sections.append(f"- {name}：{explanation}")
        sections.append("")

        sections.append("【可选路径】")
        for index, path in enumerate(paths, start=1):
            sections.append(f"{index}. {path.name}：{path.summary}")
        sections.append("")

        sections.append("【沙盘推演】")
        for index, path in enumerate(paths, start=1):
            sections.append(f"{index}. {path.name}")
            sections.append(f"- 适用条件：{path.suitable_conditions}")
            sections.append(f"- 短期收益：{path.short_term_benefit}")
            sections.append(f"- 短期风险：{path.short_term_risk}")
            sections.append(f"- 中期演化：{path.mid_term_evolution}")
            sections.append(f"- 最容易失败点：{path.failure_point}")
        sections.append("")

        sections.append("【借鉴原则】")
        for principle in principles:
            sections.append(f"- {principle}")
        sections.append("")

        sections.append("【边界提醒】")
        for warning in analysis["boundary"]:
            sections.append(f"- {warning}")

        return "\n".join(sections)


path: src/retriever.py
content: from __future__ import annotations

from pathlib import Path

from case_store import CaseStore
from classifier import SituationAssessment
from structural_semantics import infer_case_profile, structural_similarity


class CaseRetriever:
    QUERY_TERMS = [
        "改革", "新制度", "制度上线", "试点", "执行链", "中层拖延", "表面支持",
        "联盟", "合作方", "翻脸", "不完全信任", "背刺", "共同敌人",
        "更强", "头部竞争者", "资源不多", "资源不够", "弱势", "窗口期",
        "换人", "换将", "负责人", "削权", "架空", "控制权", "接班", "继任",
        "守住", "进攻", "防守", "扩张", "收缩", "基本盘", "后手",
    ]

    def __init__(self, cases_path: Path, user_cases_path: Path | None = None) -> None:
        self.cases_path = cases_path
        self.user_cases_path = user_cases_path
        self.case_store = CaseStore(cases_path, user_cases_path)
        self.cases = self.case_store.load_all_cases()
        self.case_profiles = {case["id"]: infer_case_profile(case) for case in self.cases}

    def retrieve(self, question: str, assessment: SituationAssessment, top_k: int = 3) -> list[dict]:
        scored_cases: list[tuple[int, dict]] = []
        query_fragments = self._extract_query_fragments(question)
        for case in self.cases:
            score = 0
            tags = set(case["situation_tags"])
            case_profile = self.case_profiles[case["id"]]
            semantic_score, semantic_reasons = structural_similarity(assessment.structural_profile, case_profile)

            if assessment.primary in tags:
                score += 10
            score += 4 * len(tags.intersection(assessment.secondary))
            score += semantic_score
            score += self._score_textual_support(case, question, query_fragments)

            if case["success_or_failure"] != "success" and assessment.primary in tags:
                score += 2

            annotated_case = dict(case)
            annotated_case["_match_reasons"] = semantic_reasons or ["该案例在结构约束上与当前问题接近。"]
            annotated_case["_semantic_score"] = semantic_score
            scored_cases.append((score, annotated_case))

        ranked = [case for _, case in sorted(scored_cases, key=lambda item: item[0], reverse=True)]
        selected = self._select_diverse_cases(ranked, top_k)
        selected = self._ensure_outcome_diversity(selected, ranked, assessment)
        return selected if selected else ranked[:top_k]

    def _extract_query_fragments(self, question: str) -> set[str]:
        return {term for term in self.QUERY_TERMS if term in question}

    def _score_textual_support(self, case: dict, question: str, query_fragments: set[str]) -> int:
        score = 0
        support_fields = [
            case["summary"],
            case["objective"],
            case["chosen_action"],
            *case["hidden_constraints"],
            *case["visible_information"],
            *case["modern_analogy_keywords"],
        ]
        for text in support_fields:
            if text in question:
                score += 2
                continue
            if any(fragment and fragment in str(text) for fragment in query_fragments):
                score += 1
        return min(score, 8)

    def _select_diverse_cases(self, ranked: list[dict], top_k: int) -> list[dict]:
        selected: list[dict] = []
        seen_titles: set[str] = set()
        seen_dynasties: set[str] = set()

        for case in ranked:
            if case["title"] in seen_titles:
                continue
            dynasty_penalty = case["dynasty"] in seen_dynasties and len(selected) < max(top_k - 1, 1)
            if dynasty_penalty:
                continue
            selected.append(case)
            seen_titles.add(case["title"])
            seen_dynasties.add(case["dynasty"])
            if len(selected) >= top_k:
                break
        return selected

    def _ensure_outcome_diversity(
        self, selected: list[dict], ranked: list[dict], assessment: SituationAssessment
    ) -> list[dict]:
        if len(selected) < 3:
            return selected

        if any(case["success_or_failure"] != "success" for case in selected):
            return selected

        for candidate in ranked:
            if candidate in selected:
                continue
            if assessment.primary not in candidate["situation_tags"]:
                continue
            if candidate["success_or_failure"] == "success":
                continue
            selected[-1] = candidate
            break
        return selected


path: src/structural_semantics.py
content: from __future__ import annotations

from dataclasses import dataclass


DIMENSION_LABELS = {
    "resource_state": "资源状态",
    "internal_friction": "内部摩擦",
    "external_pressure": "外部压力",
    "alliance_dependency": "联盟依赖",
    "trust_risk": "信任风险",
    "change_pressure": "变革强度",
    "control_pressure": "控制权压力",
    "personnel_pressure": "用人调整压力",
    "time_pressure": "时间压力",
    "legitimacy_pressure": "合法性压力",
    "execution_resistance": "执行阻力",
    "action_bias": "行动取向",
}

VALUE_PHRASES = {
    "resource_state": {
        "scarce": "资源偏弱",
        "balanced": "资源不占明显优势",
        "strong": "资源较强",
    },
    "internal_friction": {
        "low": "内部摩擦低",
        "medium": "内部存在掣肘",
        "high": "内部摩擦高",
    },
    "external_pressure": {
        "low": "外部压力低",
        "medium": "外部压力存在",
        "high": "外部压力高",
    },
    "alliance_dependency": {
        "low": "不依赖联盟",
        "medium": "部分依赖联盟",
        "high": "高度依赖联盟",
    },
    "trust_risk": {
        "low": "信任风险低",
        "medium": "信任风险存在",
        "high": "低信任合作",
    },
    "change_pressure": {
        "low": "变革压力低",
        "medium": "存在调整压力",
        "high": "变革压力高",
    },
    "control_pressure": {
        "low": "控制权压力低",
        "medium": "控制权存在争议",
        "high": "控制权压力高",
    },
    "personnel_pressure": {
        "low": "用人调整压力低",
        "medium": "存在人事调整压力",
        "high": "用人调整压力高",
    },
    "time_pressure": {
        "low": "时间压力低",
        "medium": "时间窗口有限",
        "high": "时间压力高",
    },
    "legitimacy_pressure": {
        "low": "合法性压力低",
        "medium": "合法性需要兼顾",
        "high": "合法性压力高",
    },
    "execution_resistance": {
        "low": "执行阻力低",
        "medium": "执行阻力存在",
        "high": "执行阻力高",
    },
    "action_bias": {
        "neutral": "行动取向未明",
        "advance": "倾向主动推进",
        "consolidate": "倾向先稳住",
        "ally": "倾向借力结盟",
        "replace": "倾向调整人或权",
        "mixed": "同时存在推进与稳局压力",
    },
}

LEVEL_DIMENSIONS = {
    "internal_friction",
    "external_pressure",
    "alliance_dependency",
    "trust_risk",
    "change_pressure",
    "control_pressure",
    "personnel_pressure",
    "time_pressure",
    "legitimacy_pressure",
    "execution_resistance",
}

DIMENSION_WEIGHTS = {
    "resource_state": 4,
    "internal_friction": 4,
    "external_pressure": 4,
    "alliance_dependency": 4,
    "trust_risk": 4,
    "change_pressure": 4,
    "control_pressure": 4,
    "personnel_pressure": 4,
    "time_pressure": 3,
    "legitimacy_pressure": 3,
    "execution_resistance": 4,
    "action_bias": 3,
}

QUESTION_CUES = {
    "resource_state": {
        "scarce": [
            "资源不多", "资源不够", "资源有限", "预算紧", "预算不多", "现金流紧",
            "人手不足", "弱势", "打不过", "对手更强", "寡不敌众", "头部竞争者", "强敌",
        ],
        "strong": ["资源充足", "优势明显", "我方更强", "兵强马壮"],
    },
    "internal_friction": {
        "high": [
            "派系", "内斗", "扯皮", "掣肘", "不服", "站队", "分裂", "反弹",
            "阳奉阴违", "表面支持", "拖延执行", "后方掣肘", "推进被叫停", "前后方失配",
        ],
        "medium": ["摩擦", "不同意见", "有人阻力", "有人拖延"],
    },
    "external_pressure": {
        "high": ["强敌", "头部", "对手更强", "外部压力", "竞争对手更强", "压着打", "共同敌人"],
        "medium": ["竞争", "外部对手", "对手", "挑战"],
    },
    "alliance_dependency": {
        "high": ["联盟", "盟友", "合作方", "联手", "合伙人", "伙伴", "渠道", "外部支持"],
        "medium": ["合作", "联合", "协同"],
    },
    "trust_risk": {
        "high": ["不信任", "不完全信任", "翻脸", "背刺", "目标不一致", "立场不一致", "担心合作方"],
        "medium": ["信任不足", "留后手", "合作但保留"],
    },
    "change_pressure": {
        "high": ["改革", "变法", "新制度", "制度上线", "流程再造", "转型", "重组", "组织变革"],
        "medium": ["调整", "改一改", "优化流程", "改制度"],
    },
    "control_pressure": {
        "high": ["控制权", "架空", "收权", "削权", "夺权", "中枢", "关键流程", "尾大不掉", "总部", "分支"],
        "medium": ["权限", "权力", "任命权", "统筹权"],
    },
    "personnel_pressure": {
        "high": ["换人", "换将", "撤换", "负责人不行", "换负责人", "空降", "保人", "代理负责人"],
        "medium": ["提拔", "任用", "接任", "带队"],
    },
    "time_pressure": {
        "high": ["立刻", "马上", "两个月", "本月", "短期", "窗口期", "现在就要", "尽快"],
        "medium": ["近期", "尽早", "不久后"],
    },
    "legitimacy_pressure": {
        "high": ["董事会", "授权", "名分", "合法性", "上级", "规则", "公开支持", "政治正确"],
        "medium": ["背书", "审批", "程序", "流程合法"],
    },
    "execution_resistance": {
        "high": ["拖延执行", "推不动", "中层拖延", "执行走样", "落实不下去", "执行链断", "推进被叫停", "被叫停"],
        "medium": ["执行难", "落地难", "推进阻力", "节奏失配", "前后方失配"],
    },
    "action_bias": {
        "advance": ["推进", "进攻", "扩张", "出击", "强推", "主动打", "往前推"],
        "consolidate": ["先稳", "防守", "守住", "收缩", "稳内部", "暂避锋芒", "稳基本盘"],
        "ally": ["结盟", "联手", "合作", "借力", "联合"],
        "replace": ["换人", "换将", "削权", "调权", "换负责人"],
    },
}

CASE_CUES = {
    **QUESTION_CUES,
    "internal_friction": {
        "high": QUESTION_CUES["internal_friction"]["high"] + ["贵族反扑", "内部意见分裂", "后方掣肘", "前后方节奏失配"],
        "medium": QUESTION_CUES["internal_friction"]["medium"],
    },
    "external_pressure": {
        "high": QUESTION_CUES["external_pressure"]["high"] + ["六国", "强秦", "曹操", "金国", "强邻"],
        "medium": QUESTION_CUES["external_pressure"]["medium"],
    },
    "legitimacy_pressure": {
        "high": QUESTION_CUES["legitimacy_pressure"]["high"] + ["民心", "正当性", "约法三章", "名义支持"],
        "medium": QUESTION_CUES["legitimacy_pressure"]["medium"],
    },
    "execution_resistance": {
        "high": QUESTION_CUES["execution_resistance"]["high"] + ["前后方节奏失配", "推进被叫停"],
        "medium": QUESTION_CUES["execution_resistance"]["medium"] + ["节奏失配"],
    },
}

CASE_TAG_HINTS = {
    "以弱对强": {"resource_state": "scarce", "external_pressure": "high"},
    "内部冲突": {"internal_friction": "high"},
    "改革推进": {"change_pressure": "high", "execution_resistance": "medium"},
    "联盟不稳": {"alliance_dependency": "high", "trust_risk": "high"},
    "守攻抉择": {"action_bias": "mixed"},
    "权力控制": {"control_pressure": "high", "legitimacy_pressure": "medium"},
    "用人换将": {"personnel_pressure": "high"},
    "合法性": {"legitimacy_pressure": "high"},
}


@dataclass
class StructuralProfile:
    dimensions: dict[str, str]
    matched_signals: dict[str, list[str]]

    def active_focus(self, limit: int = 4) -> list[str]:
        focus: list[tuple[int, str]] = []
        for dimension, value in self.dimensions.items():
            if dimension == "action_bias":
                if value != "neutral":
                    focus.append((DIMENSION_WEIGHTS[dimension], VALUE_PHRASES[dimension][value]))
                continue
            if value in {"high", "medium", "scarce", "strong"}:
                focus.append((DIMENSION_WEIGHTS[dimension], VALUE_PHRASES[dimension][value]))
        focus.sort(key=lambda item: item[0], reverse=True)
        return [item[1] for item in focus[:limit]]


def infer_question_profile(question: str) -> StructuralProfile:
    return _infer_profile_from_text(question, QUESTION_CUES)


def infer_case_profile(case: dict) -> StructuralProfile:
    case_text = " ".join(
        [
            case["title"],
            case["summary"],
            case["objective"],
            case["chosen_action"],
            *case["visible_information"],
            *case["hidden_constraints"],
            *case["options_available"],
            *case["key_reasons"],
            *case["modern_analogy_keywords"],
        ]
    )
    profile = _infer_profile_from_text(case_text, CASE_CUES)
    for tag in case["situation_tags"]:
        hints = CASE_TAG_HINTS.get(tag, {})
        for dimension, hinted_value in hints.items():
            profile.dimensions[dimension] = _merge_value(dimension, profile.dimensions[dimension], hinted_value)
    return profile


def structural_similarity(question_profile: StructuralProfile, case_profile: StructuralProfile) -> tuple[int, list[str]]:
    score = 0
    reasons: list[tuple[int, str]] = []
    for dimension, question_value in question_profile.dimensions.items():
        case_value = case_profile.dimensions.get(dimension)
        if not case_value:
            continue

        if dimension == "action_bias":
            dimension_score = _score_action_bias(question_value, case_value)
        elif dimension == "resource_state":
            dimension_score = _score_resource_state(question_value, case_value)
        else:
            dimension_score = _score_level_dimension(question_value, case_value)

        if dimension_score <= 0:
            continue

        weighted = dimension_score * DIMENSION_WEIGHTS[dimension]
        score += weighted
        reasons.append((weighted, f"{DIMENSION_LABELS[dimension]}接近：{VALUE_PHRASES[dimension][case_value]}"))

    reasons.sort(key=lambda item: item[0], reverse=True)
    return score, [reason for _, reason in reasons[:3]]


def _infer_profile_from_text(text: str, cue_library: dict[str, dict[str, list[str]]]) -> StructuralProfile:
    lowered = text.lower()
    dimensions: dict[str, str] = {
        "resource_state": "balanced",
        "internal_friction": "low",
        "external_pressure": "low",
        "alliance_dependency": "low",
        "trust_risk": "low",
        "change_pressure": "low",
        "control_pressure": "low",
        "personnel_pressure": "low",
        "time_pressure": "low",
        "legitimacy_pressure": "low",
        "execution_resistance": "low",
        "action_bias": "neutral",
    }
    matched_signals: dict[str, list[str]] = {dimension: [] for dimension in dimensions}

    for dimension, value_map in cue_library.items():
        counts = {value: 0 for value in value_map}
        for value, cues in value_map.items():
            for cue in cues:
                if cue in text or cue.lower() in lowered:
                    counts[value] += 1
                    matched_signals[dimension].append(cue)

        if dimension == "action_bias":
            dimensions[dimension] = _resolve_action_bias(counts)
        elif dimension == "resource_state":
            if counts.get("scarce", 0) > counts.get("strong", 0) and counts.get("scarce", 0) > 0:
                dimensions[dimension] = "scarce"
            elif counts.get("strong", 0) > 0:
                dimensions[dimension] = "strong"
        else:
            dimensions[dimension] = _resolve_level(counts)

    return StructuralProfile(dimensions=dimensions, matched_signals=matched_signals)


def _resolve_level(counts: dict[str, int]) -> str:
    if counts.get("high", 0) > 0:
        return "high"
    if counts.get("medium", 0) > 0:
        return "medium"
    return "low"


def _resolve_action_bias(counts: dict[str, int]) -> str:
    ranked = sorted(counts.items(), key=lambda item: item[1], reverse=True)
    if not ranked or ranked[0][1] == 0:
        return "neutral"
    if len(ranked) > 1 and ranked[1][1] > 0 and ranked[0][1] == ranked[1][1]:
        return "mixed"
    top_value = ranked[0][0]
    if top_value in {"advance", "consolidate"} and counts.get("advance", 0) > 0 and counts.get("consolidate", 0) > 0:
        return "mixed"
    return top_value


def _merge_value(dimension: str, current: str, hinted: str) -> str:
    if dimension == "action_bias":
        if current == "neutral":
            return hinted
        if current == hinted:
            return current
        if {current, hinted} <= {"advance", "consolidate"}:
            return "mixed"
        return current
    if dimension == "resource_state":
        if current == "balanced":
            return hinted
        return current
    order = ["low", "medium", "high"]
    return order[max(order.index(current), order.index(hinted))]


def _score_level_dimension(question_value: str, case_value: str) -> int:
    if question_value == "low":
        return 0
    if question_value == case_value:
        return 3 if question_value == "high" else 2
    if question_value == "medium" and case_value == "high":
        return 1
    return 0


def _score_resource_state(question_value: str, case_value: str) -> int:
    if question_value == "balanced":
        return 0
    if question_value == case_value:
        return 3
    return 0


def _score_action_bias(question_value: str, case_value: str) -> int:
    if question_value == "neutral":
        return 0
    if question_value == case_value:
        return 3
    if question_value == "mixed" and case_value in {"advance", "consolidate"}:
        return 2
    if question_value in {"advance", "consolidate"} and case_value == "mixed":
        return 1
    return 0


path: tests/test_add_case_script.py
content: from __future__ import annotations

import json
import subprocess
import sys
import tempfile
from pathlib import Path
import unittest


REPO_ROOT = Path(__file__).resolve().parents[1]


class AddCaseScriptTestCase(unittest.TestCase):
    def test_add_case_script_accepts_stdin(self) -> None:
        sample_case = {
            "id": "han-wen-di-xing-jian",
            "title": "汉文帝轻徭薄赋与休养生息",
            "dynasty": "西汉",
            "era": "文景之治前期",
            "year_range": "前180年-前157年",
            "main_figures": ["汉文帝"],
            "summary": "在经历大规模动荡后，通过减负与节制动作修复基本盘。",
            "situation_tags": ["守攻抉择", "改革推进"],
            "decision_maker": "汉文帝",
            "objective": "先稳住社会与财政，再逐步恢复国家能力。",
            "visible_information": ["社会经历前期动荡", "民生恢复优先级高"],
            "hidden_constraints": ["过快扩张会重新压垮基本盘", "过强动作会刺激旧伤复发"],
            "options_available": ["继续高压征发", "先休养生息", "局部调整"],
            "chosen_action": "主动放慢动作，以恢复秩序和承受力为先。",
            "short_term_outcome": "社会压力下降，基本秩序稳定。",
            "long_term_outcome": "为后续发展积累了承受力和财政空间。",
            "success_or_failure": "success",
            "key_reasons": ["识别优先级正确", "没有在脆弱阶段过度用力"],
            "transferable_principles": ["组织脆弱时先修复承受力，往往比立刻扩张更重要。"],
            "non_transferable_factors": ["古代国家治理与现代组织经营环境不同。"],
            "modern_analogy_keywords": ["休养生息", "先稳基本盘", "减负", "恢复承受力"],
            "source_note": "《史记·孝文本纪》",
        }

        with tempfile.TemporaryDirectory() as temp_dir:
            user_cases_path = Path(temp_dir) / "user_cases.json"
            result = subprocess.run(
                [
                    sys.executable,
                    str(REPO_ROOT / "scripts" / "add_case.py"),
                    "--stdin",
                    "--user-cases-path",
                    str(user_cases_path),
                ],
                input=json.dumps(sample_case, ensure_ascii=False),
                capture_output=True,
                text=True,
                encoding="utf-8",
                errors="replace",
                check=False,
            )

            self.assertEqual(result.returncode, 0, msg=result.stderr)
            self.assertIn(sample_case["id"], result.stdout)
            saved_cases = json.loads(user_cases_path.read_text(encoding="utf-8"))
            self.assertEqual(saved_cases[0]["id"], sample_case["id"])


if __name__ == "__main__":
    unittest.main()


path: tests/test_case_store.py
content: from __future__ import annotations

import json
import sys
import tempfile
from pathlib import Path
import unittest


REPO_ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(REPO_ROOT / "src"))

from case_store import CaseStore  # noqa: E402


class CaseStoreTestCase(unittest.TestCase):
    def test_add_case_appends_to_user_case_file(self) -> None:
        sample_case = {
            "id": "tang-li-jing-ping-tujue",
            "title": "李靖突袭平定东突厥",
            "dynasty": "唐",
            "era": "唐太宗时期",
            "year_range": "630年",
            "main_figures": ["李靖", "李世民"],
            "summary": "唐朝在北方威胁尚未完全整合前，抓住窗口发起快速打击，改变边境压力格局。",
            "situation_tags": ["守攻抉择", "以弱对强"],
            "decision_maker": "李世民",
            "objective": "通过主动出击削弱持续性边境威胁。",
            "visible_information": ["东突厥内部并不稳固", "唐军需要速战速决"],
            "hidden_constraints": ["补给线拉长风险高", "如果首击失利会暴露北线空虚"],
            "options_available": ["继续防守", "小规模试探", "集中突袭"],
            "chosen_action": "抓住对手失序窗口，授权李靖快速突袭。",
            "short_term_outcome": "东突厥主力受挫，北方压力显著下降。",
            "long_term_outcome": "唐朝边境形势改善，战略主动权提升。",
            "success_or_failure": "success",
            "key_reasons": ["抓住窗口期", "指挥权集中", "行动速度快于对手调整速度"],
            "transferable_principles": ["窗口期来临时，有限但果断的出击可能优于长期被动消耗"],
            "non_transferable_factors": ["古代骑兵与边境战略环境无法直接照搬到现代组织"],
            "modern_analogy_keywords": ["窗口期", "主动出击", "速战速决", "先发制人"],
            "source_note": "《旧唐书·李靖传》",
        }

        with tempfile.TemporaryDirectory() as temp_dir:
            user_cases_path = Path(temp_dir) / "user_cases.json"
            store = CaseStore(REPO_ROOT / "data" / "historical_cases.json", user_cases_path)
            added_case = store.add_case(sample_case)

            self.assertEqual(added_case["id"], sample_case["id"])
            saved_cases = json.loads(user_cases_path.read_text(encoding="utf-8"))
            self.assertEqual(len(saved_cases), 1)
            self.assertEqual(saved_cases[0]["title"], sample_case["title"])

    def test_retriever_can_load_user_cases(self) -> None:
        sample_case = {
            "id": "song-yue-fei-bei-fa",
            "title": "岳飞北伐与后方掣肘",
            "dynasty": "南宋",
            "era": "宋金对峙",
            "year_range": "1140年-1141年",
            "main_figures": ["岳飞", "宋高宗", "秦桧"],
            "summary": "前线推进存在战机，但后方政治目标与前线战略目标并不一致，导致节奏被打断。",
            "situation_tags": ["守攻抉择", "内部冲突"],
            "decision_maker": "宋高宗",
            "objective": "在前线作战与内部政治稳定之间做取舍。",
            "visible_information": ["前线已有战果", "内部意见并不统一"],
            "hidden_constraints": ["和战路线冲突", "前线胜利可能反过来改变内部权力平衡"],
            "options_available": ["继续北伐", "转入守势", "边打边谈"],
            "chosen_action": "通过召回与议和打断前线节奏。",
            "short_term_outcome": "内部控制更稳，但错失前线扩大战果的窗口。",
            "long_term_outcome": "长期战略主动权受损，内部与外部目标持续错位。",
            "success_or_failure": "mixed",
            "key_reasons": ["内部目标不一致", "前后方节奏失配", "政治安全压过战略收益"],
            "transferable_principles": ["前线动作必须和后方真实目标一致，否则战果难以转化为结构优势"],
            "non_transferable_factors": ["宋金时期的军政结构与现代组织决策环境不同"],
            "modern_analogy_keywords": ["后方掣肘", "前后方目标不一致", "内部目标冲突", "推进被叫停"],
            "source_note": "《宋史·岳飞传》",
        }

        with tempfile.TemporaryDirectory() as temp_dir:
            user_cases_path = Path(temp_dir) / "user_cases.json"
            store = CaseStore(REPO_ROOT / "data" / "historical_cases.json", user_cases_path)
            store.add_case(sample_case)
            cases = store.load_all_cases()

            self.assertTrue(any(case["id"] == sample_case["id"] for case in cases))


path: tests/test_cli.py
content: from __future__ import annotations

import json
import os
import subprocess
import sys
import tempfile
from pathlib import Path
import unittest


REPO_ROOT = Path(__file__).resolve().parents[1]


class CLITestCase(unittest.TestCase):
    def test_cli_outputs_required_sections(self) -> None:
        result = subprocess.run(
            [
                sys.executable,
                str(REPO_ROOT / "src" / "main.py"),
                "--question",
                "公司内部两派冲突严重，我资源偏弱，但两个月内必须推进新制度。",
            ],
            capture_output=True,
            text=True,
            encoding="utf-8",
            errors="replace",
            env={**os.environ, "PYTHONIOENCODING": "utf-8"},
            check=False,
        )
        self.assertEqual(result.returncode, 0, msg=result.stderr)
        for section in [
            "【局面判断】",
            "【历史参照】",
            "【关键变量】",
            "【可选路径】",
            "【沙盘推演】",
            "【借鉴原则】",
            "【边界提醒】",
        ]:
            self.assertIn(section, result.stdout)

    def test_cli_can_print_case_template(self) -> None:
        result = subprocess.run(
            [
                sys.executable,
                str(REPO_ROOT / "src" / "main.py"),
                "--print-case-template",
            ],
            capture_output=True,
            text=True,
            encoding="utf-8",
            errors="replace",
            env={**os.environ, "PYTHONIOENCODING": "utf-8"},
            check=False,
        )
        self.assertEqual(result.returncode, 0, msg=result.stderr)
        self.assertIn('"id": "new-historical-case-id"', result.stdout)

    def test_cli_can_add_case_from_json(self) -> None:
        sample_case = {
            "id": "ming-zhang-ju-zheng-kao-cheng",
            "title": "张居正推行考成法",
            "dynasty": "明",
            "era": "明神宗初年",
            "year_range": "1573年-1582年",
            "main_figures": ["张居正", "明神宗"],
            "summary": "通过考核与责任链压实执行，短期提升行政效率，但也累积了政治反弹。",
            "situation_tags": ["改革推进", "内部冲突"],
            "decision_maker": "张居正",
            "objective": "整顿行政执行链，提高政策落地能力。",
            "visible_information": ["行政疲沓", "顶层支持仍在"],
            "hidden_constraints": ["改革得罪既得利益", "执行强化会带来后续政治反弹"],
            "options_available": ["维持旧制", "局部整顿", "全面考成"],
            "chosen_action": "推动考成法，强化考核和责任追踪。",
            "short_term_outcome": "执行效率提升，政策推动速度加快。",
            "long_term_outcome": "改革成果部分保留，但政治反扑也很明显。",
            "success_or_failure": "mixed",
            "key_reasons": ["执行链压实", "顶层背书存在", "利益受损方反弹强"],
            "transferable_principles": ["改革要同时考虑执行效率提升和后续反弹管理。"],
            "non_transferable_factors": ["晚明政治结构与现代组织不同。"],
            "modern_analogy_keywords": ["执行链", "考核压实", "改革反弹", "责任追踪"],
            "source_note": "《明史·张居正传》",
        }

        with tempfile.TemporaryDirectory() as temp_dir:
            user_cases_path = Path(temp_dir) / "user_cases.json"
            result = subprocess.run(
                [
                    sys.executable,
                    str(REPO_ROOT / "src" / "main.py"),
                    "--add-case-json",
                    json.dumps(sample_case, ensure_ascii=False),
                    "--user-cases-path",
                    str(user_cases_path),
                ],
                capture_output=True,
                text=True,
                encoding="utf-8",
                errors="replace",
                env={**os.environ, "PYTHONIOENCODING": "utf-8"},
                check=False,
            )

            self.assertEqual(result.returncode, 0, msg=result.stderr)
            self.assertIn(sample_case["id"], result.stdout)
            saved_cases = json.loads(user_cases_path.read_text(encoding="utf-8"))
            self.assertEqual(saved_cases[0]["id"], sample_case["id"])


if __name__ == "__main__":
    unittest.main()


path: tests/test_data.py
content: from __future__ import annotations

from pathlib import Path
import sys
import unittest


REPO_ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(REPO_ROOT / "src"))

from case_store import CaseStore, REQUIRED_FIELDS  # noqa: E402


class DataTestCase(unittest.TestCase):
    def test_case_count_and_fields(self) -> None:
        store = CaseStore(REPO_ROOT / "data" / "historical_cases.json", REPO_ROOT / "data" / "user_cases.json")
        cases = store.load_core_cases()
        self.assertGreaterEqual(len(cases), 40)
        for case in cases:
            self.assertTrue(REQUIRED_FIELDS.issubset(case.keys()))
            self.assertTrue(case["source_note"])

    def test_user_cases_file_exists(self) -> None:
        self.assertTrue((REPO_ROOT / "data" / "user_cases.json").exists())


if __name__ == "__main__":
    unittest.main()


path: tests/test_retrieval.py
content: from __future__ import annotations

import json
import sys
import tempfile
from pathlib import Path
import unittest


REPO_ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(REPO_ROOT / "src"))

from classifier import SituationClassifier  # noqa: E402
from retriever import CaseRetriever  # noqa: E402


class RetrievalTestCase(unittest.TestCase):
    def setUp(self) -> None:
        self.classifier = SituationClassifier()
        self.retriever = CaseRetriever(REPO_ROOT / "data" / "historical_cases.json")

    def test_alliance_query_prefers_alliance_cases(self) -> None:
        question = "我们必须联合一个不完全信任的合作方，对抗更强的头部竞争者，但我担心项目一推进对方就翻脸。"
        assessment = self.classifier.classify(question)
        cases = self.retriever.retrieve(question, assessment, top_k=3)
        titles = {case["title"] for case in cases}

        self.assertEqual(assessment.primary, "联盟不稳")
        self.assertIn("孙刘联盟赤壁抗曹", titles)
        self.assertTrue(
            {"郭子仪单骑说回纥", "六国合纵抗秦反复失效"} & titles,
            msg=f"联盟查询未命中预期案例: {titles}",
        )

    def test_reform_query_keeps_counterexample(self) -> None:
        question = "团队里很多人表面支持改革，实际拖延执行，我资源不多，但要推动新制度上线。"
        assessment = self.classifier.classify(question)
        cases = self.retriever.retrieve(question, assessment, top_k=3)

        self.assertEqual(assessment.primary, "改革推进")
        self.assertTrue(any(case["success_or_failure"] != "success" for case in cases))

    def test_branch_control_query_hits_split_and_centralization_cases(self) -> None:
        question = "几个大区负责人已经尾大不掉，总部一直拖着不敢动。我如果现在收权，可能一起反弹。"
        assessment = self.classifier.classify(question)
        cases = self.retriever.retrieve(question, assessment, top_k=3)
        titles = {case["title"] for case in cases}

        self.assertIn(assessment.primary, {"权力控制", "内部冲突"})
        self.assertTrue(
            {"汉武帝行推恩令", "康熙削三藩并平定叛乱", "裴度督战平淮西"} & titles,
            msg=f"地方割据/收权查询未命中预期案例: {titles}",
        )

    def test_user_case_can_be_retrieved(self) -> None:
        sample_case = {
            "id": "jin-xie-an-fei-shui",
            "title": "谢安统筹淝水之战前后方协同",
            "dynasty": "东晋",
            "era": "东晋十六国",
            "year_range": "383年",
            "main_figures": ["谢安", "谢玄", "苻坚"],
            "summary": "前线作战与后方统筹需要同步稳定，否则临战易失序。",
            "situation_tags": ["守攻抉择", "内部冲突"],
            "decision_maker": "谢安",
            "objective": "在强敌来压时维持前后方节奏一致，避免内部自乱。",
            "visible_information": ["前线压力很大", "内部必须保持稳定"],
            "hidden_constraints": ["前后方节奏失配会放大战场风险", "内部恐慌会削弱执行力"],
            "options_available": ["全面收缩", "稳定后方后有限应对", "仓促决战"],
            "chosen_action": "稳住后方节奏，同时支持前线抓住战机。",
            "short_term_outcome": "内部秩序稳定，前线执行更集中。",
            "long_term_outcome": "前后方目标一致时，弱势方也能放大战果。",
            "success_or_failure": "success",
            "key_reasons": ["后方稳定", "前后方目标一致", "没有被恐慌打乱节奏"],
            "transferable_principles": ["关键阶段要先稳住后方节奏，再让前线动作兑现。"],
            "non_transferable_factors": ["古代战场环境与现代组织场景并不相同。"],
            "modern_analogy_keywords": ["后方掣肘", "前后方协同", "推进被叫停", "内部先稳住"],
            "source_note": "《晋书·谢安传》",
        }

        with tempfile.TemporaryDirectory() as temp_dir:
            user_cases_path = Path(temp_dir) / "user_cases.json"
            user_cases_path.write_text(json.dumps([sample_case], ensure_ascii=False, indent=2), encoding="utf-8")
            retriever = CaseRetriever(REPO_ROOT / "data" / "historical_cases.json", user_cases_path)
            question = "前线已经有成果，但后方一直掣肘，推进总被叫停，我该先稳内部还是继续往前推？"
            assessment = self.classifier.classify(question)
            cases = retriever.retrieve(question, assessment, top_k=3)

            self.assertTrue(any(case["id"] == sample_case["id"] for case in cases))


if __name__ == "__main__":
    unittest.main()


path: tests/test_skill_metadata.py
content: from __future__ import annotations

import json
from pathlib import Path
import unittest


REPO_ROOT = Path(__file__).resolve().parents[1]


class SkillMetadataTestCase(unittest.TestCase):
    def test_skill_json_matches_slug(self) -> None:
        metadata = json.loads((REPO_ROOT / "skill.json").read_text(encoding="utf-8"))
        self.assertEqual(metadata["slug"], "yi-shi-wei-jian")
        self.assertEqual(metadata["repository_name"], "LearnFromHistory-skill")
        self.assertEqual(metadata["entry"], "SKILL.md")
        self.assertEqual(metadata["license"], "MIT")
        self.assertEqual(metadata["homepage"], "https://github.com/GreatXiaoRY/LearnFromHistory-skill")

    def test_skill_md_contains_frontmatter(self) -> None:
        content = (REPO_ROOT / "SKILL.md").read_text(encoding="utf-8")
        self.assertIn("name: yi-shi-wei-jian", content)
        self.assertIn("homepage: https://github.com/GreatXiaoRY/LearnFromHistory-skill", content)
        self.assertIn("user-invocable: true", content)
        self.assertIn('"slug":"yi-shi-wei-jian"', content)

    def test_skill_description_keeps_trigger_surface(self) -> None:
        content = (REPO_ROOT / "SKILL.md").read_text(encoding="utf-8")
        frontmatter = content.split("---", 2)[1]
        description = next(line for line in frontmatter.splitlines() if line.startswith("description:"))
        required_markers = [
            "请用/使用/调用",
            "以史为鉴",
            "借古鉴今",
            "历史类比",
            "沙盘推演",
            "organization/business/team",
            "reform",
            "internal conflict",
            "unstable alliance",
            "control-right",
            "leadership/personnel",
        ]
        for marker in required_markers:
            self.assertIn(marker, description)

    def test_release_files_exist(self) -> None:
        self.assertTrue((REPO_ROOT / "LICENSE").exists())
        self.assertTrue((REPO_ROOT / ".github" / "workflows" / "ci.yml").exists())
        self.assertTrue((REPO_ROOT / "data" / "user_cases.json").exists())
        self.assertTrue((REPO_ROOT / "examples" / "case_submission_template.json").exists())
        self.assertTrue((REPO_ROOT / "prompts" / "add_case_intake.md").exists())
        self.assertTrue((REPO_ROOT / "scripts" / "add_case.py").exists())
        self.assertTrue((REPO_ROOT / "src" / "case_store.py").exists())


if __name__ == "__main__":
    unittest.main()


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)