Ver Fonte

upgrade: replace Mermaid with VI-consistent HTML chart screenshots

4 charts with unified dark theme + terracotta orange (#D4532B):
- chart-loop: core optimization cycle flowchart
- chart-rubric: 8-dimension scoring system (60+40=100)
- chart-phases: 5-phase optimization lifecycle
- chart-ratchet: ratchet mechanism visualization
alchain há 2 meses atrás
pai
commit
d376fd9150

+ 38 - 180
README.md

@@ -6,31 +6,11 @@
 
 受 [Andrej Karpathy 的 autoresearch](https://github.com/karpathy/autoresearch) 启发,将自主实验循环从模型训练搬到 Skill 优化领域。一个只能向前转的棘轮。
 
-> [**查看可视化展示页 →**](https://alchaincyf.github.io/auto-skill-optimizer/)
-
 ---
 
 ## 核心循环
 
-```mermaid
-graph LR
-    A["🔍 评估"] --> B["🔧 改进"]
-    B --> C["🧪 实测验证"]
-    C --> D["👤 人类确认"]
-    D --> E{分数提升?}
-    E -->|Yes| F["✅ 保留 commit"]
-    E -->|No| G["↩️ git revert"]
-    F --> A
-    G --> A
-
-    style A fill:#D4532B,color:#fff,stroke:none
-    style B fill:#333,color:#fff,stroke:none
-    style C fill:#333,color:#fff,stroke:none
-    style D fill:#333,color:#fff,stroke:none
-    style E fill:#fafafa,color:#111,stroke:#D4532B,stroke-width:2px
-    style F fill:#2B8A3E,color:#fff,stroke:none
-    style G fill:#C92A2A,color:#fff,stroke:none
-```
+![Core Loop](assets/chart-loop.png)
 
 ---
 
@@ -46,40 +26,18 @@ Auto Skill Optimizer 同时评估**结构质量**和**实际效果**,然后只
 
 ## 从 autoresearch 到 Skill Optimizer
 
-```mermaid
-graph TB
-    subgraph autoresearch["🔬 Karpathy autoresearch"]
-        direction TB
-        AR1["program.md<br/>目标与约束"]
-        AR2["train.py<br/>被优化的代码"]
-        AR3["val_bpb<br/>评估指标"]
-        AR4["git ratchet<br/>只进不退"]
-    end
-
-    subgraph optimizer["⚡ Auto Skill Optimizer"]
-        direction TB
-        SO1["SKILL.md<br/>评估标准与约束"]
-        SO2["每个 SKILL.md<br/>被优化的资产"]
-        SO3["8 维加权总分<br/>结构 60 + 效果 40"]
-        SO4["keep / revert<br/>只保留改进"]
-    end
-
-    AR1 -.->|映射| SO1
-    AR2 -.->|映射| SO2
-    AR3 -.->|映射| SO3
-    AR4 -.->|映射| SO4
-
-    style autoresearch fill:#fafafa,stroke:#999,stroke-width:1px
-    style optimizer fill:#fdf2ec,stroke:#D4532B,stroke-width:2px
-    style AR1 fill:#f5f5f5,stroke:#999,color:#333
-    style AR2 fill:#f5f5f5,stroke:#999,color:#333
-    style AR3 fill:#f5f5f5,stroke:#999,color:#333
-    style AR4 fill:#f5f5f5,stroke:#999,color:#333
-    style SO1 fill:#D4532B,color:#fff,stroke:none
-    style SO2 fill:#D4532B,color:#fff,stroke:none
-    style SO3 fill:#D4532B,color:#fff,stroke:none
-    style SO4 fill:#D4532B,color:#fff,stroke:none
-```
+这个项目直接受 Karpathy autoresearch 启发。autoresearch 的做法是:写一个 `program.md` 定义目标和约束,让 agent 自主生成和测试代码变更,只保留可测量的改进。
+
+我们把同样的思路搬到了 Skill 优化:
+
+| autoresearch | Auto Skill Optimizer | 为什么这样映射 |
+|:---|:---|:---|
+| `program.md` | 本 SKILL.md | 定义评估标准和约束规则 |
+| `train.py` | 每个待优化的 SKILL.md | 被优化的资产,每次实验只改它 |
+| `val_bpb` | 8 维加权总分(满分100) | 可量化的优化目标 |
+| `git ratchet` | keep / revert 机制 | 只保留有改进的 commit |
+| `test set` | test-prompts.json | 验证改进是否真的有效 |
+| 全自主运行 | **人在回路** | Skill 的好坏比 loss 更微妙,需要人的判断 |
 
 关键区别:autoresearch 全自主运行(loss 可以自动比较),Skill 优化增加了**人在回路**。因为 Skill 的「好坏」不像 loss 那样可以纯数值判断。
 
@@ -87,13 +45,13 @@ graph TB
 
 ## 五条核心原则
 
-```
-01  单一可编辑资产    每次只改一个 SKILL.md,变量可控,改进可归因
-02  双重评估         结构评分(静态分析)+ 效果验证(跑测试看输出)
-03  棘轮机制         只保留改进,自动回滚退步,分数只升不降
-04  独立评分         评分用子 agent,避免「自己改自己评」的偏差
-05  人在回路         每个 Skill 优化完后暂停,用户确认再继续
-```
+| # | 原则 | 说明 |
+|:---|:---|:---|
+| 01 | **单一可编辑资产** | 每次只改一个 SKILL.md,变量可控,改进可归因 |
+| 02 | **双重评估** | 结构评分(静态分析)+ 效果验证(跑测试看输出) |
+| 03 | **棘轮机制** | 只保留改进,自动回滚退步,分数只升不降 |
+| 04 | **独立评分** | 评分用子 agent,避免「自己改自己评」的偏差 |
+| 05 | **人在回路** | 每个 Skill 优化完后暂停,用户确认再继续下一个 |
 
 ---
 
@@ -101,37 +59,7 @@ graph TB
 
 总分 100。结构维度靠静态分析(60分),效果维度必须实测(40分)。
 
-```mermaid
-graph LR
-    subgraph structure["结构维度 — 60 分"]
-        S1["Frontmatter 质量<br/><b>8</b>"]
-        S2["工作流清晰度<br/><b>15</b>"]
-        S3["边界条件覆盖<br/><b>10</b>"]
-        S4["检查点设计<br/><b>7</b>"]
-        S5["指令具体性<br/><b>15</b>"]
-        S6["资源整合度<br/><b>5</b>"]
-    end
-
-    subgraph effect["效果维度 — 40 分"]
-        E1["整体架构<br/><b>15</b>"]
-        E2["🎯 实测表现<br/><b>25</b>"]
-    end
-
-    structure --> TOTAL["总分<br/><b>100</b>"]
-    effect --> TOTAL
-
-    style structure fill:#f5f5f5,stroke:#999,stroke-width:1px
-    style effect fill:#fdf2ec,stroke:#D4532B,stroke-width:2px
-    style TOTAL fill:#D4532B,color:#fff,stroke:none
-    style E2 fill:#D4532B,color:#fff,stroke:none
-    style S1 fill:#fff,stroke:#ddd
-    style S2 fill:#fff,stroke:#ddd
-    style S3 fill:#fff,stroke:#ddd
-    style S4 fill:#fff,stroke:#ddd
-    style S5 fill:#fff,stroke:#ddd
-    style S6 fill:#fff,stroke:#ddd
-    style E1 fill:#fff,stroke:#ddd
-```
+![Evaluation Rubric](assets/chart-rubric.png)
 
 > 实测表现权重最高(25分)。Skill 写得再漂亮,跑出来效果不好就是零。
 
@@ -139,48 +67,18 @@ graph LR
 
 ## 优化循环:5 个阶段
 
-```mermaid
-graph TB
-    P0["<b>Phase 0</b><br/>初始化<br/>确定范围 · 创建 git 分支 · 加载历史"]
-    P05["<b>Phase 0.5</b><br/>测试设计<br/>为每个 Skill 设计 2-3 个测试 prompt"]
-    P1["<b>Phase 1</b><br/>基线评估<br/>8 维度打分 · 建立优化前基准线"]
-    P2["<b>Phase 2</b><br/>优化循环<br/>诊断 → 改进 → 重评 → keep/revert"]
-    P3["<b>Phase 3</b><br/>汇总报告<br/>Before/After 分数表 · 关键改进摘要"]
-
-    P0 --> P05
-    P05 -->|"👤 人类确认测试 prompt"| P1
-    P1 -->|"👤 人类确认基线分数"| P2
-    P2 -->|"👤 每个 Skill 完成后确认"| P3
-
-    style P0 fill:#f5f5f5,stroke:#999,color:#333
-    style P05 fill:#f5f5f5,stroke:#999,color:#333
-    style P1 fill:#333,color:#fff,stroke:none
-    style P2 fill:#D4532B,color:#fff,stroke:none
-    style P3 fill:#333,color:#fff,stroke:none
-```
+系统在每个阶段内自主运行,但在阶段之间暂停等待人类确认。
+
+![Optimization Lifecycle](assets/chart-phases.png)
 
 **Phase 2 的核心逻辑**:
 
-```mermaid
-graph TB
-    A["找出得分最低的维度"] --> B["生成 1 个具体改进方案"]
-    B --> C["编辑 SKILL.md · git commit"]
-    C --> D["子 agent 独立重新评分"]
-    D --> E{"新分 > 旧分?"}
-    E -->|"Yes ✅"| F["保留改进"]
-    E -->|"No ❌"| G["git revert"]
-    F --> H{"达到 3 轮?"}
-    G --> I["跳到下一个 Skill"]
-    H -->|No| A
-    H -->|Yes| I
-    I --> J["👤 展示 diff + 分数变化<br/>等待人类确认"]
-
-    style A fill:#333,color:#fff,stroke:none
-    style E fill:#fafafa,stroke:#D4532B,stroke-width:2px,color:#111
-    style F fill:#2B8A3E,color:#fff,stroke:none
-    style G fill:#C92A2A,color:#fff,stroke:none
-    style J fill:#D4532B,color:#fff,stroke:none
-```
+1. 找出得分最低的维度
+2. 针对该维度生成 1 个具体改进方案
+3. 编辑 SKILL.md,git commit
+4. 子 agent 独立重新评分
+5. 新分 > 旧分 → 保留;否则 → git revert
+6. 每个 Skill 完成后暂停,展示 diff + 分数变化,等用户确认
 
 ---
 
@@ -188,58 +86,12 @@ graph TB
 
 分数只能上升。每一轮要么改进 Skill,要么干净地回滚。不会随时间积累局部退化。
 
-```mermaid
-graph LR
-    R0["72<br/><small>基线</small>"]
-    R1["78<br/><small>✅ 保留</small>"]
-    R2["<s>75</s><br/><small>❌ 回滚</small>"]
-    R3["84<br/><small>✅ 保留</small>"]
-    R4["87<br/><small>✅ 保留</small>"]
-
-    R0 --> R1 --> R2 --> R3 --> R4
-
-    style R0 fill:#666,color:#fff,stroke:none
-    style R1 fill:#2B8A3E,color:#fff,stroke:none
-    style R2 fill:#fff,color:#C92A2A,stroke:#C92A2A,stroke-width:2px,stroke-dasharray:5 5
-    style R3 fill:#2B8A3E,color:#fff,stroke:none
-    style R4 fill:#2B8A3E,color:#fff,stroke:none
-```
+![Ratchet Mechanism](assets/chart-ratchet.png)
 
 轮次 2 的 75 分低于当前最优的 78 分,被自动回滚。有效基线始终锁定在 78,后续改进从 78 继续。
 
 ---
 
-## 为什么需要双重评估
-
-```mermaid
-graph TB
-    subgraph old["❌ 纯结构审查"]
-        O1["检查 frontmatter 格式"]
-        O2["验证步骤编号"]
-        O3["确认路径有效"]
-        O4["⚠️ 无法判断实际输出质量"]
-        O5["⚠️ 无法检测过度约束"]
-    end
-
-    subgraph new["✅ 双重评估"]
-        N1["结构评分 + 实测验证"]
-        N2["跑真实 prompt 对比输出"]
-        N3["子 agent 独立评分"]
-        N4["每轮只改一个维度"]
-        N5["分数不涨就回滚"]
-    end
-
-    style old fill:#f9f9f9,stroke:#ccc,stroke-width:1px
-    style new fill:#fdf2ec,stroke:#D4532B,stroke-width:2px
-    style O4 fill:#fff5f5,stroke:#C92A2A,color:#C92A2A
-    style O5 fill:#fff5f5,stroke:#C92A2A,color:#C92A2A
-    style N1 fill:#D4532B,color:#fff,stroke:none
-    style N2 fill:#D4532B,color:#fff,stroke:none
-    style N3 fill:#D4532B,color:#fff,stroke:none
-```
-
----
-
 ## 快速开始
 
 ### 安装
@@ -316,8 +168,14 @@ auto-skill-optimizer/
 ├── README.md              # 你正在看的文件
 ├── SKILL.md               # 核心:评估标准 + 优化流程 + 约束规则
 ├── showcase.html          # Pentagram 风格的可视化展示页(可本地打开)
+├── docs/                  # GitHub Pages(公开后可访问)
+│   └── index.html
 └── assets/
-    └── aso-hero.png       # README 配图
+    ├── banner.svg         # README 头图
+    ├── chart-loop.png     # 核心循环流程图
+    ├── chart-rubric.png   # 8 维度评估体系
+    ├── chart-phases.png   # 5 阶段优化时间线
+    └── chart-ratchet.png  # 棘轮机制可视化
 ```
 
 ---

+ 179 - 0
assets/chart-loop.html

@@ -0,0 +1,179 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<title>Auto Skill Optimizer - Core Loop</title>
+<link rel="preconnect" href="https://fonts.googleapis.com">
+<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
+<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700;800;900&display=swap" rel="stylesheet">
+<style>
+  * { margin: 0; padding: 0; box-sizing: border-box; }
+  html, body {
+    width: 1200px;
+    height: 500px;
+    background: #111111;
+    overflow: hidden;
+    font-family: 'Inter', sans-serif;
+  }
+</style>
+</head>
+<body>
+<svg width="1200" height="500" xmlns="http://www.w3.org/2000/svg">
+  <defs>
+    <!-- Arrow markers -->
+    <marker id="arr-orange" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
+      <polygon points="0 0, 10 3.5, 0 7" fill="#D4532B"/>
+    </marker>
+    <marker id="arr-green" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
+      <polygon points="0 0, 10 3.5, 0 7" fill="#2B8A3E"/>
+    </marker>
+    <marker id="arr-red" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
+      <polygon points="0 0, 10 3.5, 0 7" fill="#C92A2A"/>
+    </marker>
+    <marker id="arr-orange-up" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
+      <polygon points="0 0, 10 3.5, 0 7" fill="#D4532B"/>
+    </marker>
+  </defs>
+
+  <!-- Background -->
+  <rect width="1200" height="500" fill="#111111"/>
+
+  <!-- CORE LOOP label -->
+  <text x="48" y="50" fill="#D4532B" font-family="Inter, sans-serif" font-size="11" font-weight="700" letter-spacing="3">CORE LOOP</text>
+
+  <!--
+    Layout plan (y-center = 200):
+    Block width = 120, height = 70
+    Gap between blocks = 36 (arrow)
+    Decision diamond: center at x=750, size 90×90
+
+    Blocks horizontal positions (left edge):
+    B1 EVALUATE:  x=48,  center=108
+    B2 IMPROVE:   x=228, center=288
+    B3 VALIDATE:  x=408, center=468
+    B4 CONFIRM:   x=588, center=648
+    Diamond:      center=790
+    YES block:    x=958, center=1018  (top, y=145)
+    NO block:     x=958, center=1018  (bottom, y=255)
+
+    All vertical center: y=200
+    YES block center y = 160
+    NO block center y = 260
+  -->
+
+  <!-- ======================== -->
+  <!-- MAIN PROCESS BLOCKS      -->
+  <!-- ======================== -->
+
+  <!-- B1: EVALUATE -->
+  <rect x="48" y="165" width="124" height="70" fill="#FFFFFF"/>
+  <text x="110" y="196" fill="#111111" font-family="Inter, sans-serif" font-size="13" font-weight="800" text-anchor="middle">EVALUATE</text>
+  <text x="110" y="213" fill="#555555" font-family="Inter, sans-serif" font-size="10" font-weight="600" text-anchor="middle">评估当前技能</text>
+
+  <!-- Arrow B1→B2 -->
+  <line x1="172" y1="200" x2="204" y2="200" stroke="#D4532B" stroke-width="2" marker-end="url(#arr-orange)"/>
+
+  <!-- B2: IMPROVE -->
+  <rect x="210" y="165" width="124" height="70" fill="#FFFFFF"/>
+  <text x="272" y="196" fill="#111111" font-family="Inter, sans-serif" font-size="13" font-weight="800" text-anchor="middle">IMPROVE</text>
+  <text x="272" y="213" fill="#555555" font-family="Inter, sans-serif" font-size="10" font-weight="600" text-anchor="middle">生成改进方案</text>
+
+  <!-- Arrow B2→B3 -->
+  <line x1="334" y1="200" x2="366" y2="200" stroke="#D4532B" stroke-width="2" marker-end="url(#arr-orange)"/>
+
+  <!-- B3: VALIDATE -->
+  <rect x="372" y="165" width="124" height="70" fill="#FFFFFF"/>
+  <text x="434" y="196" fill="#111111" font-family="Inter, sans-serif" font-size="13" font-weight="800" text-anchor="middle">VALIDATE</text>
+  <text x="434" y="213" fill="#555555" font-family="Inter, sans-serif" font-size="10" font-weight="600" text-anchor="middle">实测验证效果</text>
+
+  <!-- Arrow B3→B4 -->
+  <line x1="496" y1="200" x2="528" y2="200" stroke="#D4532B" stroke-width="2" marker-end="url(#arr-orange)"/>
+
+  <!-- B4: CONFIRM -->
+  <rect x="534" y="165" width="124" height="70" fill="#FFFFFF"/>
+  <text x="596" y="196" fill="#111111" font-family="Inter, sans-serif" font-size="13" font-weight="800" text-anchor="middle">CONFIRM</text>
+  <text x="596" y="213" fill="#555555" font-family="Inter, sans-serif" font-size="10" font-weight="600" text-anchor="middle">人类确认结果</text>
+
+  <!-- Arrow B4→Diamond -->
+  <line x1="658" y1="200" x2="698" y2="200" stroke="#D4532B" stroke-width="2" marker-end="url(#arr-orange)"/>
+
+  <!-- ======================== -->
+  <!-- DECISION DIAMOND         -->
+  <!-- center: 790, 200         -->
+  <!-- size: 96×80              -->
+  <!-- ======================== -->
+  <polygon points="790,152 838,200 790,248 742,200" fill="#D4532B"/>
+  <text x="790" y="196" fill="#FFFFFF" font-family="Inter, sans-serif" font-size="12" font-weight="800" text-anchor="middle">SCORE</text>
+  <text x="790" y="212" fill="#FFFFFF" font-family="Inter, sans-serif" font-size="12" font-weight="800" text-anchor="middle">UP?</text>
+
+  <!-- ======================== -->
+  <!-- YES PATH (top branch)    -->
+  <!-- ======================== -->
+
+  <!-- YES PATH: diamond top → up → right to YES block -->
+  <!-- Diamond top point: 790, 152 -->
+  <path d="M790,152 L790,120 L954,120"
+        stroke="#2B8A3E" stroke-width="2" fill="none" marker-end="url(#arr-green)"/>
+
+  <!-- YES label -->
+  <text x="860" y="113" fill="#2B8A3E" font-family="Inter, sans-serif" font-size="10" font-weight="700" letter-spacing="1" text-anchor="middle">YES</text>
+
+  <!-- YES result block: KEEP / git commit -->
+  <rect x="960" y="85" width="130" height="70" fill="#2B8A3E"/>
+  <text x="1025" y="115" fill="#FFFFFF" font-family="Inter, sans-serif" font-size="13" font-weight="800" text-anchor="middle">KEEP</text>
+  <text x="1025" y="133" fill="rgba(255,255,255,0.75)" font-family="Inter, sans-serif" font-size="10" font-weight="600" text-anchor="middle">git commit</text>
+
+  <!-- ======================== -->
+  <!-- NO PATH (bottom branch)  -->
+  <!-- ======================== -->
+
+  <!-- NO PATH: diamond bottom → down → right to NO block -->
+  <!-- Diamond bottom point: 790, 248 -->
+  <path d="M790,248 L790,280 L954,280"
+        stroke="#C92A2A" stroke-width="2" fill="none" marker-end="url(#arr-red)"/>
+
+  <!-- NO label -->
+  <text x="860" y="298" fill="#C92A2A" font-family="Inter, sans-serif" font-size="10" font-weight="700" letter-spacing="1" text-anchor="middle">NO</text>
+
+  <!-- NO result block: REVERT / git revert -->
+  <rect x="960" y="245" width="130" height="70" fill="#C92A2A"/>
+  <text x="1025" y="275" fill="#FFFFFF" font-family="Inter, sans-serif" font-size="13" font-weight="800" text-anchor="middle">REVERT</text>
+  <text x="1025" y="293" fill="rgba(255,255,255,0.75)" font-family="Inter, sans-serif" font-size="10" font-weight="600" text-anchor="middle">git revert</text>
+
+  <!-- ======================== -->
+  <!-- LOOP BACK ARROW          -->
+  <!-- from KEEP/REVERT → back to EVALUATE -->
+  <!-- ======================== -->
+
+  <!-- From right side of YES block (1090, 120) → right to 1155 → down to 420 → left to 48 → up to 200 (B1 left) -->
+  <path d="M1090,120 L1155,120 L1155,420 L48,420 L48,235"
+        stroke="#D4532B" stroke-width="2" fill="none" stroke-dasharray="6,4"/>
+
+  <!-- Also from NO block right → join same vertical -->
+  <path d="M1090,280 L1155,280"
+        stroke="#D4532B" stroke-width="2" fill="none" stroke-dasharray="6,4"/>
+
+  <!-- Arrow head pointing up at B1 left -->
+  <polygon points="42,236 54,236 48,222" fill="#D4532B"/>
+
+  <!-- LOOP BACK label along bottom -->
+  <text x="590" y="448" fill="#444444" font-family="Inter, sans-serif" font-size="11" font-weight="600" text-anchor="middle" letter-spacing="3">LOOP BACK</text>
+
+  <!-- ======================== -->
+  <!-- STEP NUMBERS             -->
+  <!-- ======================== -->
+  <text x="48" y="158" fill="#D4532B" font-family="Inter, sans-serif" font-size="10" font-weight="700">01</text>
+  <text x="210" y="158" fill="#D4532B" font-family="Inter, sans-serif" font-size="10" font-weight="700">02</text>
+  <text x="372" y="158" fill="#D4532B" font-family="Inter, sans-serif" font-size="10" font-weight="700">03</text>
+  <text x="534" y="158" fill="#D4532B" font-family="Inter, sans-serif" font-size="10" font-weight="700">04</text>
+  <text x="762" y="145" fill="#D4532B" font-family="Inter, sans-serif" font-size="10" font-weight="700" opacity="0.9">05</text>
+
+  <!-- ======================== -->
+  <!-- SUBTITLE TEXT            -->
+  <!-- ======================== -->
+  <text x="48" y="476" fill="#333333" font-family="Inter, sans-serif" font-size="10" font-weight="600" letter-spacing="1">AUTO SKILL OPTIMIZER</text>
+  <text x="1152" y="476" fill="#333333" font-family="Inter, sans-serif" font-size="10" font-weight="600" text-anchor="end" letter-spacing="1">CONTINUOUS IMPROVEMENT ENGINE</text>
+
+</svg>
+</body>
+</html>

BIN
assets/chart-loop.png


+ 221 - 0
assets/chart-phases.html

@@ -0,0 +1,221 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<title>Optimization Lifecycle</title>
+<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700;800;900&display=swap" rel="stylesheet">
+<style>
+  * { margin: 0; padding: 0; box-sizing: border-box; }
+
+  body {
+    width: 1200px;
+    height: 400px;
+    background: #111111;
+    font-family: 'Inter', -apple-system, sans-serif;
+    overflow: hidden;
+    position: relative;
+  }
+
+  .top-label {
+    position: absolute;
+    top: 28px;
+    left: 44px;
+    font-size: 11px;
+    font-weight: 800;
+    letter-spacing: 0.18em;
+    color: #D4532B;
+    text-transform: uppercase;
+  }
+
+  /* Center row: phases + arrows */
+  .row {
+    position: absolute;
+    top: 50%;
+    left: 50%;
+    transform: translate(-50%, -50%);
+    display: flex;
+    align-items: center;
+    gap: 0;
+  }
+
+  /* === Phase boxes === */
+  .phase {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    border-radius: 8px;
+    flex-shrink: 0;
+  }
+
+  .phase-num {
+    font-weight: 900;
+    line-height: 1;
+  }
+
+  .phase-name {
+    font-weight: 600;
+    text-align: center;
+    line-height: 1.3;
+  }
+
+  /* Regular dark */
+  .p-dark {
+    background: #1D1D1D;
+    border: 1px solid #2D2D2D;
+    width: 130px;
+    height: 130px;
+  }
+  .p-dark .phase-num {
+    font-size: 38px;
+    color: #FFFFFF;
+    margin-bottom: 10px;
+  }
+  .p-dark .phase-name {
+    font-size: 13px;
+    color: #888888;
+  }
+
+  /* White */
+  .p-white {
+    background: #FFFFFF;
+    border: 1px solid #DDDDDD;
+    width: 130px;
+    height: 130px;
+  }
+  .p-white .phase-num {
+    font-size: 38px;
+    color: #111111;
+    margin-bottom: 10px;
+  }
+  .p-white .phase-name {
+    font-size: 13px;
+    color: #555555;
+  }
+
+  /* Core - Phase 2 */
+  .p-core {
+    background: #D4532B;
+    border: 2px solid #E06035;
+    width: 196px;
+    height: 196px;
+    box-shadow: 0 0 50px rgba(212, 83, 43, 0.4), 0 0 16px rgba(212, 83, 43, 0.25);
+  }
+  .p-core .phase-num {
+    font-size: 56px;
+    color: #FFFFFF;
+    margin-bottom: 12px;
+  }
+  .p-core .phase-name {
+    font-size: 15px;
+    font-weight: 700;
+    color: rgba(255,255,255,0.93);
+  }
+
+  /* === Connector === */
+  .connector {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    width: 72px;
+    flex-shrink: 0;
+    position: relative;
+  }
+
+  .conn-label {
+    font-size: 9.5px;
+    color: #505050;
+    font-weight: 600;
+    letter-spacing: 0.04em;
+    white-space: nowrap;
+    margin-bottom: 9px;
+  }
+
+  .arrow {
+    display: flex;
+    align-items: center;
+    width: 100%;
+  }
+
+  .arrow-line {
+    flex: 1;
+    height: 2px;
+    background: #D4532B;
+  }
+
+  .arrow-head {
+    width: 0;
+    height: 0;
+    border-top: 5px solid transparent;
+    border-bottom: 5px solid transparent;
+    border-left: 9px solid #D4532B;
+  }
+</style>
+</head>
+<body>
+
+  <div class="top-label">OPTIMIZATION LIFECYCLE</div>
+
+  <div class="row">
+
+    <div class="phase p-dark">
+      <div class="phase-num">0</div>
+      <div class="phase-name">初始化</div>
+    </div>
+
+    <div class="connector">
+      <div class="conn-label">人类确认</div>
+      <div class="arrow">
+        <div class="arrow-line"></div>
+        <div class="arrow-head"></div>
+      </div>
+    </div>
+
+    <div class="phase p-dark">
+      <div class="phase-num">0.5</div>
+      <div class="phase-name">测试设计</div>
+    </div>
+
+    <div class="connector">
+      <div class="conn-label">人类确认</div>
+      <div class="arrow">
+        <div class="arrow-line"></div>
+        <div class="arrow-head"></div>
+      </div>
+    </div>
+
+    <div class="phase p-white">
+      <div class="phase-num">1</div>
+      <div class="phase-name">基线评估</div>
+    </div>
+
+    <div class="connector">
+      <div class="conn-label">人类确认</div>
+      <div class="arrow">
+        <div class="arrow-line"></div>
+        <div class="arrow-head"></div>
+      </div>
+    </div>
+
+    <div class="phase p-core">
+      <div class="phase-num">2</div>
+      <div class="phase-name">优化循环</div>
+    </div>
+
+    <div class="connector">
+      <div class="conn-label">人类确认</div>
+      <div class="arrow">
+        <div class="arrow-line"></div>
+        <div class="arrow-head"></div>
+      </div>
+    </div>
+
+    <div class="phase p-dark">
+      <div class="phase-num">3</div>
+      <div class="phase-name">汇总报告</div>
+    </div>
+
+  </div>
+
+</body>
+</html>

BIN
assets/chart-phases.png


+ 273 - 0
assets/chart-ratchet.html

@@ -0,0 +1,273 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Ratchet Mechanism</title>
+<style>
+  @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700;800&display=swap');
+
+  * { margin: 0; padding: 0; box-sizing: border-box; }
+
+  body {
+    width: 1200px;
+    height: 450px;
+    background: #111111;
+    font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
+    display: flex;
+    flex-direction: column;
+    overflow: hidden;
+    position: relative;
+  }
+
+  .header {
+    padding: 28px 60px 0;
+    display: flex;
+    align-items: baseline;
+    gap: 16px;
+  }
+
+  .label {
+    color: #D4532B;
+    font-size: 13px;
+    font-weight: 800;
+    letter-spacing: 2px;
+    text-transform: uppercase;
+  }
+
+  .subtitle {
+    color: #555;
+    font-size: 12px;
+    font-weight: 600;
+    letter-spacing: 1px;
+  }
+
+  .chart-area {
+    flex: 1;
+    display: flex;
+    align-items: flex-end;
+    justify-content: center;
+    padding: 0 60px 60px;
+    gap: 0;
+    position: relative;
+  }
+
+  .bars-wrapper {
+    display: flex;
+    align-items: flex-end;
+    gap: 40px;
+    position: relative;
+    width: 100%;
+    justify-content: center;
+  }
+
+  .bar-group {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    position: relative;
+    width: 80px;
+  }
+
+  .score {
+    font-size: 36px;
+    font-weight: 800;
+    color: #ffffff;
+    margin-bottom: 10px;
+    line-height: 1;
+  }
+
+  .score.rollback {
+    color: #C92A2A;
+    text-decoration: line-through;
+    text-decoration-thickness: 3px;
+  }
+
+  .bar {
+    width: 80px;
+    border-radius: 4px 4px 0 0;
+    position: relative;
+  }
+
+  .bar.baseline {
+    background: #444444;
+  }
+
+  .bar.retained {
+    background: #ffffff;
+  }
+
+  .bar.rollback-bar {
+    background: transparent;
+    border: 2px dashed #C92A2A;
+    border-bottom: none;
+  }
+
+  .bar.highlight {
+    background: #D4532B;
+  }
+
+  .round-label {
+    margin-top: 12px;
+    color: #666666;
+    font-size: 12px;
+    font-weight: 600;
+    letter-spacing: 0.5px;
+    white-space: nowrap;
+  }
+
+  /* SVG overlay for arrows and ratchet line */
+  .svg-overlay {
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    pointer-events: none;
+  }
+</style>
+</head>
+<body>
+
+<div class="header">
+  <div class="label">RATCHET MECHANISM</div>
+  <div class="subtitle">— effective baseline only moves up</div>
+</div>
+
+<div class="chart-area" id="chartArea">
+  <div class="bars-wrapper" id="barsWrapper">
+    <!-- bars will be injected by JS -->
+  </div>
+  <svg class="svg-overlay" id="svgOverlay"></svg>
+</div>
+
+<script>
+  const scores = [72, 78, 75, 84, 87];
+  const types  = ['baseline', 'retained', 'rollback', 'retained', 'highlight'];
+  const rounds = ['轮次 0', '轮次 1', '轮次 2', '轮次 3', '轮次 4'];
+
+  // Effective baseline sequence (ratchet): 72, 78, 78, 84, 87
+  const effectiveBaseline = [72, 78, 78, 84, 87];
+
+  const maxScore = 90;
+  const minScore = 60;
+  const chartHeight = 270; // px available for bars
+
+  function barHeight(score) {
+    return Math.round((score - minScore) / (maxScore - minScore) * chartHeight);
+  }
+
+  const wrapper = document.getElementById('barsWrapper');
+
+  scores.forEach((score, i) => {
+    const group = document.createElement('div');
+    group.className = 'bar-group';
+    group.id = `group-${i}`;
+
+    const scoreEl = document.createElement('div');
+    scoreEl.className = 'score' + (types[i] === 'rollback' ? ' rollback' : '');
+    scoreEl.textContent = score;
+
+    const bar = document.createElement('div');
+    bar.className = 'bar ' + (types[i] === 'rollback' ? 'rollback-bar' : types[i]);
+    const h = barHeight(score);
+    bar.style.height = h + 'px';
+
+    const label = document.createElement('div');
+    label.className = 'round-label';
+    label.textContent = rounds[i];
+
+    group.appendChild(scoreEl);
+    group.appendChild(bar);
+    group.appendChild(label);
+    wrapper.appendChild(group);
+  });
+
+  // Draw arrows and ratchet line after layout
+  requestAnimationFrame(() => {
+    requestAnimationFrame(() => {
+      const svg = document.getElementById('svgOverlay');
+      const chartArea = document.getElementById('chartArea');
+      const chartRect = chartArea.getBoundingClientRect();
+
+      // Collect bar group positions
+      const groups = [];
+      for (let i = 0; i < 5; i++) {
+        const g = document.getElementById(`group-${i}`);
+        const rect = g.getBoundingClientRect();
+        // top of the bar (not the score label)
+        const bar = g.querySelector('.bar');
+        const barRect = bar.getBoundingClientRect();
+        groups.push({
+          cx: rect.left - chartRect.left + rect.width / 2,
+          barTop: barRect.top - chartRect.top,
+          barBottom: barRect.bottom - chartRect.top,
+        });
+      }
+
+      // Arrow heads: connect bar top centers (exclude rollback from arrows, draw arrow anyway between all)
+      const arrowColor = '#D4532B';
+      const arrowGap = 8;
+
+      let svgContent = `
+        <defs>
+          <marker id="arrow" markerWidth="8" markerHeight="8" refX="6" refY="3" orient="auto">
+            <path d="M0,0 L0,6 L8,3 z" fill="${arrowColor}" />
+          </marker>
+        </defs>
+      `;
+
+      // Draw horizontal arrows between consecutive bar centers at mid-height of the lower bar
+      for (let i = 0; i < 4; i++) {
+        const fromX = groups[i].cx + 40 + arrowGap;
+        const toX = groups[i+1].cx - 40 - arrowGap - 8;
+        const higherBarTop = Math.min(groups[i].barTop, groups[i+1].barTop);
+        const lowerBarTop = Math.max(groups[i].barTop, groups[i+1].barTop);
+        const lowerBarBottom = Math.max(groups[i].barBottom, groups[i+1].barBottom);
+        const y = lowerBarTop + (lowerBarBottom - lowerBarTop) * 0.5;
+
+        // Use a slightly raised y to look cleaner
+        const arrowY = Math.min(groups[i].barTop, groups[i+1].barTop) - 18;
+        const clampedY = Math.max(arrowY, 40);
+
+        svgContent += `<line x1="${fromX}" y1="${clampedY}" x2="${toX}" y2="${clampedY}"
+          stroke="${arrowColor}" stroke-width="2" marker-end="url(#arrow)" opacity="0.7"/>`;
+      }
+
+      // Ratchet line: connects effective baseline tops
+      // Effective baseline scores: 72, 78, 78, 84, 87
+      // For round 2 (rollback), use effective = 78, not 75
+      const effectiveHeights = effectiveBaseline.map(s => barHeight(s));
+      const baselineBottom = groups[0].barBottom; // all bars share same bottom
+
+      // Points for ratchet line
+      const points = groups.map((g, i) => {
+        const effH = effectiveHeights[i];
+        const y = baselineBottom - effH;
+        return { x: g.cx, y };
+      });
+
+      // Draw dashed orange line through effective baseline tops
+      let pathD = `M ${points[0].x} ${points[0].y}`;
+      for (let i = 1; i < points.length; i++) {
+        pathD += ` L ${points[i].x} ${points[i].y}`;
+      }
+
+      svgContent += `<path d="${pathD}" fill="none" stroke="${arrowColor}" stroke-width="2"
+        stroke-dasharray="6,4" opacity="0.9"/>`;
+
+      // Dots at each effective baseline point
+      points.forEach((p, i) => {
+        svgContent += `<circle cx="${p.x}" cy="${p.y}" r="4" fill="${arrowColor}" opacity="0.9"/>`;
+      });
+
+      // Label for the ratchet line
+      svgContent += `<text x="${points[4].x + 10}" y="${points[4].y - 6}" fill="${arrowColor}"
+        font-family="Inter, sans-serif" font-size="11" font-weight="700" letter-spacing="0.5">EFFECTIVE FLOOR</text>`;
+
+      svg.innerHTML = svgContent;
+    });
+  });
+</script>
+</body>
+</html>

BIN
assets/chart-ratchet.png


+ 351 - 0
assets/chart-rubric.html

@@ -0,0 +1,351 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=1200">
+<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700;900&display=swap" rel="stylesheet">
+<style>
+  * { margin: 0; padding: 0; box-sizing: border-box; }
+
+  body {
+    width: 1200px;
+    height: 600px;
+    overflow: hidden;
+    background: #111111;
+    font-family: 'Inter', system-ui, -apple-system, sans-serif;
+    color: #FFFFFF;
+  }
+
+  .container {
+    width: 1200px;
+    height: 600px;
+    display: flex;
+    flex-direction: column;
+    padding: 44px 56px 36px 56px;
+    position: relative;
+  }
+
+  /* Header */
+  .header {
+    display: flex;
+    align-items: flex-start;
+    justify-content: space-between;
+    margin-bottom: 36px;
+  }
+
+  .rubric-label {
+    color: #D4532B;
+    font-size: 11px;
+    font-weight: 700;
+    letter-spacing: 3px;
+    text-transform: uppercase;
+  }
+
+  .title {
+    font-size: 26px;
+    font-weight: 900;
+    color: #FFFFFF;
+    margin-top: 8px;
+    letter-spacing: -0.5px;
+  }
+
+  .subtitle {
+    font-size: 13px;
+    color: #666666;
+    margin-top: 4px;
+    font-weight: 400;
+  }
+
+  /* Main content: two columns + divider */
+  .main {
+    flex: 1;
+    display: flex;
+    gap: 0;
+    align-items: stretch;
+  }
+
+  /* Left panel */
+  .panel {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+  }
+
+  .panel-header {
+    display: flex;
+    align-items: baseline;
+    gap: 10px;
+    margin-bottom: 22px;
+  }
+
+  .panel-title {
+    font-size: 13px;
+    font-weight: 700;
+    color: #666666;
+    text-transform: uppercase;
+    letter-spacing: 2px;
+  }
+
+  .panel-score {
+    font-size: 28px;
+    font-weight: 900;
+    color: #FFFFFF;
+  }
+
+  .panel-score.orange {
+    color: #D4532B;
+  }
+
+  /* Divider */
+  .divider {
+    width: 1px;
+    background: #D4532B;
+    margin: 0 44px;
+    flex-shrink: 0;
+  }
+
+  /* Bar items */
+  .bar-list {
+    display: flex;
+    flex-direction: column;
+    gap: 13px;
+    flex: 1;
+  }
+
+  .bar-item {
+    display: flex;
+    flex-direction: column;
+    gap: 5px;
+  }
+
+  .bar-meta {
+    display: flex;
+    align-items: baseline;
+    justify-content: space-between;
+  }
+
+  .bar-label {
+    font-size: 12px;
+    font-weight: 600;
+    color: #AAAAAA;
+    letter-spacing: 0.3px;
+  }
+
+  .bar-weight {
+    font-size: 22px;
+    font-weight: 900;
+    color: #FFFFFF;
+    line-height: 1;
+  }
+
+  .bar-weight.orange {
+    color: #D4532B;
+    font-size: 28px;
+  }
+
+  .bar-track {
+    width: 100%;
+    height: 6px;
+    background: #222222;
+    position: relative;
+  }
+
+  .bar-fill {
+    height: 100%;
+    background: #CCCCCC;
+    transition: none;
+  }
+
+  .bar-fill.orange {
+    background: linear-gradient(90deg, #D4532B 0%, #FF7A4D 100%);
+  }
+
+  /* Right panel: larger items */
+  .bar-item.large .bar-label {
+    font-size: 13px;
+    color: #AAAAAA;
+  }
+
+  .bar-item.large .bar-track {
+    height: 8px;
+  }
+
+  /* Bottom total */
+  .bottom {
+    margin-top: 28px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    gap: 16px;
+    border-top: 1px solid #222222;
+    padding-top: 18px;
+  }
+
+  .total-label {
+    font-size: 13px;
+    font-weight: 700;
+    color: #666666;
+    letter-spacing: 3px;
+    text-transform: uppercase;
+  }
+
+  .total-score {
+    font-size: 38px;
+    font-weight: 900;
+    color: #FFFFFF;
+    line-height: 1;
+  }
+
+  .total-unit {
+    font-size: 13px;
+    color: #666666;
+    font-weight: 600;
+    letter-spacing: 2px;
+  }
+
+  .dot {
+    width: 4px;
+    height: 4px;
+    background: #D4532B;
+    display: inline-block;
+    margin: 0 6px 2px 6px;
+    vertical-align: middle;
+  }
+</style>
+</head>
+<body>
+<div class="container">
+
+  <!-- Header -->
+  <div class="header">
+    <div>
+      <div class="rubric-label">EVALUATION RUBRIC</div>
+      <div class="title">Auto Skill Optimizer — 8 维度评估体系</div>
+      <div class="subtitle">Automated quality scoring framework for Claude skill optimization</div>
+    </div>
+  </div>
+
+  <!-- Main -->
+  <div class="main">
+
+    <!-- Left: Structure -->
+    <div class="panel">
+      <div class="panel-header">
+        <div class="panel-title">结构维度</div>
+        <div class="panel-score">60分</div>
+      </div>
+      <div class="bar-list">
+
+        <div class="bar-item">
+          <div class="bar-meta">
+            <span class="bar-label">Frontmatter 质量</span>
+            <span class="bar-weight">8</span>
+          </div>
+          <div class="bar-track">
+            <div class="bar-fill" style="width: calc(8/15*100%)"></div>
+          </div>
+        </div>
+
+        <div class="bar-item">
+          <div class="bar-meta">
+            <span class="bar-label">工作流清晰度</span>
+            <span class="bar-weight">15</span>
+          </div>
+          <div class="bar-track">
+            <div class="bar-fill" style="width: 100%"></div>
+          </div>
+        </div>
+
+        <div class="bar-item">
+          <div class="bar-meta">
+            <span class="bar-label">边界条件覆盖</span>
+            <span class="bar-weight">10</span>
+          </div>
+          <div class="bar-track">
+            <div class="bar-fill" style="width: calc(10/15*100%)"></div>
+          </div>
+        </div>
+
+        <div class="bar-item">
+          <div class="bar-meta">
+            <span class="bar-label">检查点设计</span>
+            <span class="bar-weight">7</span>
+          </div>
+          <div class="bar-track">
+            <div class="bar-fill" style="width: calc(7/15*100%)"></div>
+          </div>
+        </div>
+
+        <div class="bar-item">
+          <div class="bar-meta">
+            <span class="bar-label">指令具体性</span>
+            <span class="bar-weight">15</span>
+          </div>
+          <div class="bar-track">
+            <div class="bar-fill" style="width: 100%"></div>
+          </div>
+        </div>
+
+        <div class="bar-item">
+          <div class="bar-meta">
+            <span class="bar-label">资源整合度</span>
+            <span class="bar-weight">5</span>
+          </div>
+          <div class="bar-track">
+            <div class="bar-fill" style="width: calc(5/15*100%)"></div>
+          </div>
+        </div>
+
+      </div>
+    </div>
+
+    <!-- Vertical divider -->
+    <div class="divider"></div>
+
+    <!-- Right: Effect -->
+    <div class="panel">
+      <div class="panel-header">
+        <div class="panel-title">效果维度</div>
+        <div class="panel-score orange">40分</div>
+      </div>
+      <div class="bar-list">
+
+        <div class="bar-item large">
+          <div class="bar-meta">
+            <span class="bar-label">整体架构</span>
+            <span class="bar-weight">15</span>
+          </div>
+          <div class="bar-track">
+            <div class="bar-fill" style="width: calc(15/25*100%)"></div>
+          </div>
+        </div>
+
+        <div class="bar-item large" style="margin-top: 12px;">
+          <div class="bar-meta" style="margin-bottom: 2px;">
+            <span class="bar-label" style="color:#D4532B; font-size:14px; font-weight:700; letter-spacing:0.5px;">实测表现</span>
+            <span class="bar-weight orange">25</span>
+          </div>
+          <!-- Accent line above bar -->
+          <div style="width:100%; height:1px; background:#D4532B; opacity:0.25; margin-bottom:6px;"></div>
+          <div class="bar-track" style="height:14px; background:#1A0E0A;">
+            <div class="bar-fill orange" style="width:100%; height:100%;"></div>
+          </div>
+          <div style="font-size:11px; color:#D4532B; margin-top:5px; font-weight:600; letter-spacing:1px;">HIGHEST WEIGHT</div>
+        </div>
+
+      </div>
+    </div>
+
+  </div>
+
+  <!-- Bottom total -->
+  <div class="bottom">
+    <span class="total-label">TOTAL</span>
+    <span class="dot"></span>
+    <span class="total-score">100</span>
+    <span class="total-unit">PTS</span>
+  </div>
+
+</div>
+</body>
+</html>

BIN
assets/chart-rubric.png