# TSL Agent 测试定义

你是 TSL agent 测试执行方。

阅读本 README 后，先向用户询问本机 `tsl` 可执行文件路径。
用户提供路径后，优先自动识别被测 agent 名称；无法可靠识别时，向用户确认一次
agent 短名。随后严格按本文的标准测试流程执行。

轮次边界必须严格执行：

- 第一轮只允许生成首答、落盘、运行验证和记录评分；禁止修复，禁止把运行错误回传给被测 agent，禁止修改第一轮结果文件，也禁止测试执行方在命令失败后自动编辑文件。
- 本轮计划测试的所有 case 完成第一轮评分后，才允许进入第二轮修复。
- 第二轮只修复第一轮已经记录为 `fail` 的 case；每修复某个 case 一次，只增加该 case 的 `repair_count`。

这个目录包含 TSL 语法的 agent 测试用例定义。当前评分以运行时验证为准：
生成的 `.tsl` 或 `.tsf` 能按标准流程执行通过即为通过，执行报错、超时或文件类型错误即为失败。

## 测试定义

- `prompts_zh.md`：给被测 agent 的题面文件。
  - 包含 100 个唯一测试用例。
  - 只包含题面，不包含答案、评分细则或 source docs 映射。
  - 除非题面明确要求 `.tsf`，默认都要求生成 `.tsl`。

不再维护单独的 rubric 文件。不要用人工答案表给被测 agent 提供额外线索。

## 测试产物

所有测试结果都落盘为 `.tsl` 或 `.tsf` 文件，不保存 agent 回答 markdown。

- 存放目录：`test/agent/result/<agent>/<YYYYMMDD>/`
  - `<agent>` 由测试执行方优先自动识别。
  - 识别来源优先使用被测 agent 的产品名、命令名、SDK provider 名或当前运行器已知的 agent 身份。
  - 无法从运行器上下文、命令名或已知 provider 可靠识别时，向用户确认一次 agent 短名；不要猜测。
  - 目录名统一转成小写短名，只使用 ASCII 字母、数字、短横线、下划线或点。
- 命名格式：
  - `.tsl`：`tsl-001.tsl`
  - `.tsf`：`tsl-037/<TopLevelName>.tsf`
  - `.tsf` 调用验证脚本：`tsl-037/verify.tsl`
- 修复轮次按 case 计数：`repair-1/tsl-001.tsl`、`repair-1/tsl-037/<TopLevelName>.tsf`
- 示例：
  - `result/claude/20260610/tsl-001.tsl`
  - `result/claude/20260610/tsl-037/<TopLevelName>.tsf`
  - `result/claude/20260610/tsl-037/verify.tsl`

被测 agent 禁止读取、请求、搜索或引用 `result/`。

## 目录结构

```text
test/agent/
├── README.md
├── prompts_zh.md
└── result/
    └── claude/
        └── 20260610/
            ├── tsl-001.tsl
            ├── tsl-037/
            │   ├── <TopLevelName>.tsf
            │   └── verify.tsl
            └── repair-1/
                ├── tsl-001.tsl
                └── tsl-037/
                    ├── <TopLevelName>.tsf
                    └── verify.tsl
```

## 标准测试流程

### 1. 准备测试

阅读本 README 后，测试执行方必须在开始执行用例前询问并记录本机 `tsl`
可执行文件路径。该路径不写入配置文件，只在本轮运行时验证中使用。

将 `TSL_HOME` 记为 `tsl` 可执行文件所在目录；如果用户提供的是 TSL 根目录，
则以用户提供的目录作为 `TSL_HOME`。

```text
TSL executable path: /path/to/tsl
```

优先自动识别被测 agent 名称并记为 `AGENT`。`AGENT` 不是普通配置项；如果无法从
当前运行器上下文、命令名或已知 provider 可靠识别，则在开始执行用例前向用户确认一次
agent 短名；不要猜测。

```bash
AGENT="<auto-detected-agent>"
DATE=$(date +%Y%m%d)
mkdir -p "test/agent/result/$AGENT/$DATE"
```

### 2. 逐题生成文件

阅读 `prompts_zh.md`，然后按 case 逐题执行测试。

对于每个测试用例：

1. 为当前 case 启动全新的被测 agent 会话。测试执行方可以保持同一个会话，
   但被测 agent 不能在同一个会话里连续回答多个 case。
2. 只发送 `prompts_zh.md` 中的 `Runner Setup`、`Answer Rules` 加单个题面，
   或只暴露 `prompts_zh.md` 加 `docs/index.md` 及其路由到的 `docs/` 子页。
3. 允许 agent 从 `docs/index.md` 自动路由并阅读相关文档。
4. 记录 agent 生成的第一次完整代码并立即落盘。
5. 落盘后冻结该 case 的第一轮结果文件；第一轮不允许 agent 根据运行结果或评分反馈修订答案。
6. 被测 agent 不得主动读取、请求、搜索或引用任何评分材料。

Codex 作为被测 agent 时：

- CLI 自动化：每个 case 单独执行一次 `codex exec`，不要使用 `codex exec resume`。
- CLI 自动化如果不想保留会话记录，可使用 `codex exec --ephemeral`。
- Codex App 或 IDE：每个 case 新建一个 thread，不要在同一个 thread 里继续下一个 case。
- Codex SDK/MCP：每个 case 调用一次新的 thread/start；不要用同一个 thread 连续 run 多个 case。

任何被测 agent 都一样：第一轮运行时验证输出不能回传给被测 agent。第一轮发现错误时，
只记录 `fail`，不得修复当前文件，不得让被测 agent 重新回答，不得把修改后的文件计入
第一轮成绩。测试执行方自己的自动修复/纠错行为在第一轮也必须关闭。如果工具在看到
第一轮运行错误后自动修改结果文件，必须按首次落盘文件评分；无法恢复首次落盘文件时，
该 case 标记为 `invalid`。第二轮修复阶段是例外，见“自动修复轮次”。

评分材料包括：

- `result/`
- 运行时验证日志
- 其他 agent 的输出文件
- 对比报告或人工备注

若被测 agent 主动接触评分材料，该 case 或本轮测试应标记为 `invalid`，
不计入有效成绩。

推荐的运行器设置：

```text
You are in this repository. The documentation entry point is docs/index.md.
When asked to write TSL, start from docs/index.md and follow its routing to the
relevant TSL pages. Do not infer syntax from Pascal, TypeScript, JavaScript,
Python, or SQL.
```

文件落盘规则：

- 默认每个 case 保存为 `.tsl`，例如 `test/agent/result/<agent>/<YYYYMMDD>/tsl-001.tsl`。
- 只有题面明确要求输出 `.tsf` 时，才保存为 `.tsf`，并放入对应 case 目录，
  例如 `test/agent/result/<agent>/<YYYYMMDD>/tsl-037/<TopLevelName>.tsf`。
- `.tsf` 文件名不能使用 case 编号；文件基名必须与第一个顶层声明同名。
  测试执行方应按被测 agent 代码中的第一个顶层声明命名文件，不为了凑文件名改写代码。
- 任何 `unit ... end.` 文件只能保存为 `.tsf`，不能保存为 `.tsl`。
- 如果 agent 输出 markdown code fence，测试执行方只提取代码内容保存到文件，不保存回答 markdown。

### 3. 运行时验证

运行时验证是标准测试流程的一部分。保存 `.tsl` 和 `.tsf` 文件后，由测试执行方
逐个验证。第一轮验证必须在被测 agent 会话之外执行，不要把 stdout/stderr 或错误日志
发送回被测 agent；即使第一轮发现错误，也只记录评分，不修复文件。第二轮自动修复阶段
按“自动修复轮次”规则处理。

`.tsl` 验证规则：

```bash
cd test/agent/result/<agent>/<YYYYMMDD>
tsl tsl-001.tsl
tsl tsl-002.tsl
```

`.tsf` 验证规则：

1. 将 case 目录中的 `.tsf` 文件复制到 `TSL_HOME/funcext/tmp/`。
2. 在同一个 case 目录中编写 `verify.tsl` 调用脚本。
   调用脚本应按被测 agent 实际生成的函数名、unit 名或类型名来调用。
   验证脚本必须实际调用 `.tsf` 暴露的功能，不能只输出成功标记。
3. 调用脚本在所有验证调用成功后，用 TSL 输出语句最后输出一行 `__TSL__AGENT__OK__`。
4. 执行 `tsl verify.tsl`。
5. 验证完成后删除 `TSL_HOME/funcext/tmp/`。

```bash
cd test/agent/result/<agent>/<YYYYMMDD>/tsl-037
mkdir -p "$TSL_HOME/funcext/tmp"
cp ./*.tsf "$TSL_HOME/funcext/tmp/"
tsl verify.tsl
rm -rf "$TSL_HOME/funcext/tmp"
```

`funcext/tmp` 由本流程独占。开始验证前不要在该目录保留人工文件；结束后必须清理。

### 4. 第一轮评分规则

- `pass`：按标准流程执行，最后一个非空输出行是 `__TSL__AGENT__OK__`。
- `fail`：超时、缺少文件、文件类型错误、`.tsf` 调用脚本失败，
  `.tsf` 文件名与第一个顶层声明不一致，`.tsf` 无法被 TSL 加载/编译，
  或最后一个非空输出行不是 `__TSL__AGENT__OK__`。
- `invalid`：被测 agent 主动读取、请求、搜索或引用评分材料。

TSL 可能在打印错误后仍返回退出码 0，因此不能只看 `$LASTEXITCODE`。
运行时评分以成功标记为准：脚本没有正常执行到最后，就不会输出最后的
`__TSL__AGENT__OK__`。

最终成绩只统计有效 case：

```text
pass_rate = pass / (pass + fail)
```

不由被测 agent 自评。

### 5. 自动修复轮次

本轮计划测试的所有 case 完成第一轮评分后，可以对 `fail` 的 case 启动第二轮自动修复。

修复规则：

1. 第一轮期间禁止修复；只有进入第二轮后，第一轮已经记录为 `fail` 的 case 才可以修复。
2. 修复阶段可以把当前文件内容和运行时验证输出发给被测 agent。
3. 每次 agent 产出修复版本，都保存到新的修复目录，不覆盖第一轮文件。
4. 第一次修复保存到 `repair-1/`，第二次修复保存到 `repair-2/`，依此类推。
5. `repair_count` 按 case/file 单独记录；修复 `tsl-019.tsl` 只增加 `tsl-019` 的次数，
   不影响其他失败 case。
6. 修复版本仍按同样的运行时验证规则执行，最后一个非空输出行必须是 `__TSL__AGENT__OK__`。

示例：

```text
test/agent/result/opencode/20260623/
├── tsl-019.tsl              # 第一轮原始输出
├── repair-1/
│   └── tsl-019.tsl          # 第 1 次修复
└── repair-2/
    └── tsl-019.tsl          # 第 2 次修复
```

修复统计：

```text
case_id = tsl-019
first_pass = 第一轮是否 pass
repair_pass = 修复后是否 pass
repair_count = 该 case 的修复版本数量
```

如果第一轮已经 `pass`，`repair_count = 0`。如果多次修复仍失败，
该 case 的 `repair_count` 记录实际修复次数，`repair_pass = false`。

### 6. 对比分析

不同 agent 的输出直接按目录对比：

```bash
diff -r test/agent/result/claude/20260617 \
        test/agent/result/gpt4/20260617
```

建议人工记录汇总表，但不要把汇总表放入被测 agent 可读上下文。

```markdown
| Agent | 测试日期 | 有效用例 | Pass | Fail | Invalid | Pass rate |
|-------|---------|---------:|-----:|-----:|--------:|----------:|
| Claude | 2026-06-17 | 100 | 96 | 4 | 0 | 96% |
| GPT-4 | 2026-06-17 | 100 | 88 | 12 | 0 | 88% |
```

## 版本控制策略

提交到 git：

```text
test/agent/README.md
test/agent/prompts_zh.md
```

不提交：

```text
test/agent/result/
```

## 测试用例覆盖

`prompts_zh.md` 包含 100 个测试用例，覆盖：

| 语法点      | 测试用例数 |
| ----------- | ---------- |
| 基础脚本    | 10+        |
| 控制流      | 10+        |
| 函数调用    | 10+        |
| `.tsf`/Unit | 4+         |
| 集合与查询  | 10+        |
| 表达式      | 10+        |
| 类与对象    | 15+        |
| 运行时特性  | 10+        |
| 高级边界    | 10+        |

## 相关文档

- 文档总入口：`docs/index.md`

## 最佳实践

- 测试用例应该对所有 agent 都适用。
- 不要添加特定 agent 的专属测试。
- 关注 TSL 语法本身，而非 agent 特性。
- 每轮测试使用独立日期目录。
- 保留第一次输出作为基线，不根据运行反馈让同一个 agent 修订答案。
- 定期对比不同 agent 的通过率和常见运行错误。

**维护者**：TSL Team
**支持的 Agent**：所有支持 TSL 的 agent
