# UTF-8 字节序列异常修复报告

## 🎯 问题描述

**错误信息**:
```
IllegalArgumentException: Invalid utf8 byte sequence.
at codelin.io.StatusBar::render()(/Users/galileo/IdeaProjects/codex/src/io/status_bar.cj:295)
at codelin.app.CliApp::startInteractive()(/Users/galileo/IdeaProjects/codex/src/app/cli_app.cj:1147)
```

## 🔍 根本原因分析

### 问题链路

1. **数据源问题**: 
   - `GitUtils.getCurrentBranch()` 从 `.git/HEAD` 文件读取分支名时，如果文件包含无效的 UTF-8 字节序列，`String.fromUtf8()` 会抛出 `IllegalArgumentException`
   - 虽然代码中有 try-catch，但异常可能在某些情况下未被正确捕获

2. **字符串处理问题**:
   - `StatusBar.render()` 中调用 `statusLine.toRuneArray()` 时，如果字符串包含无效 UTF-8，会抛出异常
   - `PrintUtils.printString()` 在打印字符串时，如果字符串包含无效 UTF-8，底层 print 函数可能抛出异常

3. **数据验证缺失**:
   - 在设置 `agentName`、`currentFile`、`currentOperation` 等值时，没有验证 UTF-8 有效性
   - 在构建状态栏字符串时，没有过滤掉无效的 UTF-8 部分

## ✅ 修复方案

### 1. GitUtils.getCurrentBranch() - 安全 UTF-8 解码

**文件**: `src/utils/git_utils.cj`

**修复内容**:
- 使用 `Utf8Utils.decode()` 替代直接调用 `String.fromUtf8()`
- `Utf8Utils.decode()` 会安全处理无效 UTF-8，返回 `None` 而不是抛出异常
- 如果解码失败，返回 "-" 作为安全默认值

**代码变更**:
```cangjie
// 修复前
let content = String.fromUtf8(File.readFrom(headPath)).trimAscii()

// 修复后
let bytes = File.readFrom(headPath)
match (Utf8Utils.decode(bytes, label: Some("GitUtils.getCurrentBranch"))) {
    case Some(contentRaw) => 
        let content = contentRaw.trimAscii()
        // ... 处理逻辑
    case None => 
        return "-"  // 安全默认值
}
```

### 2. StatusBar.render() - 多层防御验证

**文件**: `src/io/status_bar.cj`

**修复内容**:
- **输入验证**: 在设置值时验证 UTF-8（`updateOperation`, `updateAgentName`, `updateCurrentFile`, `updateMetricsSummary`）
- **构建时过滤**: 在构建状态栏字符串时，过滤掉所有无效 UTF-8 的 parts
- **处理时保护**: 在调用 `toRuneArray()` 时使用 try-catch 保护
- **打印时验证**: 在调用 `PrintUtils.printString()` 前进行最终验证

**代码变更**:
```cangjie
// 1. 输入验证（示例：updateOperation）
this.currentOperation = if (Utf8Utils.validate(operation)) {
    Some(operation)
} else {
    Some("Operation")  // 安全默认值
}

// 2. 构建时过滤
let safeParts = ArrayList<String>()
for (part in parts) {
    if (Utf8Utils.validate(part)) {
        safeParts.add(part)
    }
    // 静默跳过无效部分
}

// 3. 处理时保护
let runeCount = try {
    safeStatusLine.toRuneArray().size
} catch (e: Exception) {
    safeStatusLine.size  // 字节级回退
}

// 4. 打印时验证
try {
    PrintUtils.printString(displayLine)
} catch (e: IllegalArgumentException) {
    if (e.message.contains("utf8") || e.message.contains("UTF-8")) {
        PrintUtils.printString("Status")  // 安全回退
    } else {
        throw e
    }
}
```

### 3. PrintUtils.printString() - 最终安全网

**文件**: `src/io/print_utils.cj`

**修复内容**:
- 在打印前验证 UTF-8 有效性
- 如果无效，使用安全替代字符串
- 在 print 调用时添加 try-catch 作为最终保护

**代码变更**:
```cangjie
static public func printString(str: String, withIndent!: Bool = false): Unit {
    // 验证 UTF-8
    let safeStr = if (Utf8Utils.validate(str)) {
        str
    } else {
        "[Invalid UTF-8]"  // 安全替代
    }
    
    try {
        print(safeStr, flush: true)
    } catch (e: IllegalArgumentException) {
        if (e.message.contains("utf8") || e.message.contains("UTF-8")) {
            print("[Encoding Error]", flush: true)  // 最终回退
        } else {
            throw e
        }
    }
}
```

## 🛡️ 防御层次

修复采用了**多层防御策略**：

1. **第一层 - 数据源**: `GitUtils.getCurrentBranch()` 使用安全解码
2. **第二层 - 输入验证**: 所有 `StatusBar` 的 setter 方法验证 UTF-8
3. **第三层 - 构建过滤**: 在构建状态栏字符串时过滤无效部分
4. **第四层 - 处理保护**: 在字符串处理操作时使用 try-catch
5. **第五层 - 打印验证**: `PrintUtils.printString()` 最终验证和保护

## 📊 修复效果

### 修复前
- ❌ 遇到无效 UTF-8 字节序列时直接崩溃
- ❌ 错误信息不明确，难以定位问题
- ❌ 没有恢复机制

### 修复后
- ✅ 自动过滤无效 UTF-8，使用安全默认值
- ✅ 多层保护确保不会崩溃
- ✅ 优雅降级，程序继续运行
- ✅ 错误日志记录（通过 `Utf8Utils.decode()` 的日志）

## 🔧 测试建议

1. **测试无效分支名**: 创建一个包含无效 UTF-8 字节的 `.git/HEAD` 文件
2. **测试无效文件名**: 设置包含无效 UTF-8 的文件路径
3. **测试无效操作名**: 设置包含无效 UTF-8 的操作名称
4. **测试混合数据**: 同时包含有效和无效 UTF-8 的多个数据源

## 📝 相关文件

- `src/utils/git_utils.cj` - Git 工具类，修复 UTF-8 解码
- `src/io/status_bar.cj` - 状态栏类，添加多层验证
- `src/io/print_utils.cj` - 打印工具类，添加最终保护
- `src/core/utils/utf8_utils.cj` - UTF-8 工具类（已存在，被复用）

## 🎯 总结

通过实施多层防御策略，我们彻底解决了 `Invalid utf8 byte sequence` 异常问题。修复不仅解决了当前问题，还提高了整个系统的健壮性，确保即使遇到意外的无效 UTF-8 数据，程序也能优雅地处理并继续运行。

