# Mad Hatter 🎩

**为 AI agent runtime 而生的 Rust 框架——你声明意图，帽子守住边界。**

你写 agent runtime 时最怕的那些错——忘了处理错误、直接 `.unwrap()`、用 `let _ =` 吞掉 IO 失败、在事务外做 IO、重试次数失控——Mad Hatter 会在**编译期**或**运行期**直接拦下，不让它们进生产。

```rust
// 你这么写：
let content = fs::read_to_string("config.json")?;  // ❌ E301: IO 未进 TxScope

// 帽子要求你这么写：
let scope = TxScope::new(StartupTx::new());
let content = scope.fs().read_to_string("config.json")
    .propagate(&scope, StartupFatal::ConfigMissing);  // ✅ 错误路径必须声明
```

---

## 30 秒明白帽子是什么

| 问题 | 传统 Rust | Mad Hatter |
|------|----------|-----------|
| 忘处理错误 | `let _ = fs::write(...)` 编译通过 | `E401` 编译拦截 |
| 直接 unwrap | panic 在生产 | `Critical<T>` 强制 propagate/suppress |
| 重试失控 | for 循环可能跑 1000 次 | `concept-map.json` 声明 `retry_count: 3`，超限 abort |
| 事务语义漂移 | 代码和文档各说各话 | `concept-map.json` 双向锁定代码 |
| HTTP/RPC 样板代码 | 手写几百行 | 一个 `bind_http!` 或 `#[tunnel_service]` 搞定 |

---

## 60 秒跑起来

**1. 新建项目**
```bash
cargo new my-agent
cd my-agent
```

**2. Cargo.toml**
```toml
[dependencies]
mad-hatter = "0.2"

[build-dependencies]
mad-hatter-guardian = "0.1"
```

**3. build.rs**（激活编译期防御）
```rust
fn main() {
    mad_hatter_guardian::activate(
        mad_hatter_guardian::DefenseConfig::new("src")
    );
}
```

**4. concept-map.json**（声明事务）
```json
{
  "version": 2,
  "transactions": [
    {
      "name": "greet",
      "transactional": false,
      "failures": []
    }
  ]
}
```

**5. src/main.rs**（一个最小可运行示例）
```rust
use mad_hatter::*;

#[mad_hatter::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    println!("Hello from Mad Hatter 🎩");
    Ok(())
}
```

**6. 跑起来**
```bash
cargo run
```

就这样。写更多代码，Guardian 会在 `cargo build` 时即时提示哪些地方违反了契约（配合 `target/mad-hatter-guide.md` 一键定位修法）。

---

## 核心概念（5 分钟）

### 1. TxScope：所有 IO 的作用域

每个 IO 操作（读文件、调 LLM、发 HTTP、写 DB）必须在一个 `TxScope<T>` 里执行。`T` 是事务类型，决定了哪些错误是 fatal、哪些可 suppress。

```rust
let scope = TxScope::new(CheckUserTx::new());
let user = scope.db().query_one::<User>("...")
    .propagate(&scope, CheckUserFatal::DbRead)?;
```

### 2. Critical<V>：错误传播容器

所有 IO 方法返回 `Critical<V>`——一个编译器强制你处理的容器。不允许 `let _ = ...` 静默丢弃。

- `.propagate(&scope, token)` → 失败则中止事务并记录 fatal token
- `.suppress(token, reason)` → 显式声明"这个错误我接受，原因是..."
- `.suppress_with(token, reason, default)` → 同上但提供默认值

### 3. Guardian：编译期 + 运行期两道防线

| 时机 | 机制 | 例子 |
|------|------|------|
| **编译期** | AST 静态扫描 + concept-map 双向锁定 | 用了未声明的事务 token → `E306` |
| **运行期** | `process::abort()`（不可被 catch_unwind 吞） | retry 超限 → `R101` abort |

防御规则**只加固不退让**——开发者遇到 violation 必须改代码，绝不通过降级规则放行。

### 4. 声明式宏：样板代码归零

| 你声明什么 | 帽子生成什么 |
|------------|-------------|
| `bind_http! { GET "/users" => list_users : UsersTx }` | axum router + auth middleware + TxScope 集成 |
| `#[tunnel_service(FileTx)] trait FileApi { ... }` | `FileApiProxy`（客户端）+ `FileApiDispatcher`（服务端） |
| `bind_loops! { "beat" [batch] => BeatHandler : BeatTx }` | 后台循环 + notify_refresh + 优雅关闭 |
| `dao! { MyDb, "data.db", schema = "schema.json" }` | DB pool + startup reconcile（无需手写 migration） |
| `i18n! { Hi { en: "Hi {name}!", zh: "你好{name}！" } }` | `Hi::render("en", name) -> Sealed<String>` |

---

## 学习路径

**👋 第一次接触**
1. 本 README 的"60 秒跑起来"
2. [`docs/quickstart.md`](docs/quickstart.md) — 完整的最小项目骨架
3. [`docs/philosophy.md`](docs/philosophy.md) — 为什么要这么设计

**🛠 开始写代码**
- 任何时候遇到 Guardian warning/error：看 `target/mad-hatter-guide.md`（build 时生成，30 个错误码都有"怎么改"）
- 事务声明参考：[`mad-hatter-guardian/suggestions/GUIDE.md`](mad-hatter-guardian/suggestions/GUIDE.md)（唯一真相，由 `include_str!` 编译进 guardian）

**🔍 深入理解**
- [`docs/guardian-guide.md`](docs/guardian-guide.md) — 30 个错误码全解
- [`docs/attack-stories.md`](docs/attack-stories.md) — 真实攻防案例（为什么帽子加这条规则）
- [`docs/transaction-atomicity-design-report.md`](docs/transaction-atomicity-design-report.md) — 事务原子性设计

---

## 帽子为你打理的边界

| 边界 | API | 一句话 |
|------|-----|--------|
| LLM 推理 | `infer()` / `stream_infer()` | 自动 retry + resume（Truncated 时让模型续写） |
| Prompt 契约 | `#[derive(Promptable, Parseable)]` | Rust struct ↔ markdown 双向映射 |
| HTTP 服务 | `bind_server!` + `bind_http!` | 声明式路由 + session auth |
| Tunnel RPC | `#[tunnel_service]` | 远端调用如同本地，强制错误处理 |
| 数据库 | `dao!` + `FormatEnum` + `FormatStruct` | JSON schema 代替 migration + sqlx 衍生链 |
| 配置 | `json_store!` / `unified_params!` | 原子写 + env/JSON/default 三级优先 |
| 后台循环 | `bind_loops!` | batch/cron/plain 三种模式声明式 |
| 日志 | `log_service!` | 多文件分流 + 大小滚动 |
| 错误 | `erase_error!` + `Sealed<T>` | end user 看干净 id，ops 看完整链 |
| I18n | `i18n!` | 多语言输出都是 `Sealed<String>` |

---

## 为什么叫 Mad Hatter？

"You're entirely bonkers. But I'll tell you a secret. All the best people are."
—— Alice in Wonderland

疯帽子替茶会守规矩——谁不守就把他拖出去。帽子替你的 runtime 守边界，谁不守编译就过不了。

---

## 安装

```toml
[dependencies]
mad-hatter = "0.2"

[build-dependencies]
mad-hatter-guardian = "0.1"
```

依赖：tokio · axum · sqlx (SQLite) · reqwest · tokio-tungstenite · tracing · serde

## License

MIT

---

*Mad Hatter — 每一个 IO 边界都值得一位守门人。* 🎩