<div align="center">

# TSL Playbook

**面向 AI 编码环境的 TSL 开发指南**

_让 AI 写对 TSL —— 不靠"像 Pascal"的猜测，只靠可核对的文档事实_

<br>

![docs](https://img.shields.io/badge/语法专题-24_篇-2b7489)
![funcs](https://img.shields.io/badge/函数索引-12455_条-3178c6)
![skill](https://img.shields.io/badge/Skill-tsl--syntax--reference-8250df)
![skill](https://img.shields.io/badge/Skill-tsl--api--reference-8250df)
![modules](https://img.shields.io/badge/模块集成-pyTSL_·_回测_·_微信-e37933)

</div>

---

## 目录

- 🛠 **第一部分 · 技术路径**（开发者视角）
  - [项目介绍](#项目介绍)
  - [核心理念](#核心理念)
  - [架构设计](#架构设计)
  - [目录结构](#目录结构)
- 📦 **部署**：把 skill 装到不同 AI Agent
- 👤 **第二部分 · 多环境实测**（用户视角）
  - [统一提示词](#统一提示词)
  - [第一轮实测：Claude Code · Fable 5](#第一轮实测claude-code--fable-5)
  - [第二轮实测：Codex CLI · GPT-5.5](#第二轮实测codex-cli--gpt-55)
  - [第三轮实测：Qwen 3.6-27B](#第三轮实测qwen-36-27b)
  - [横向对比](#横向对比)
  - [三轮小结](#三轮小结)
- 🔭 **第三部分 · 后续升级方向**（演进视角）

---

<div align="center">

## 🛠 第一部分 · 技术路径

**开发者视角 —— playbook 是什么、如何搭建**

</div>

---

### 项目介绍

**TSL**（天软语言）是天软金融分析平台的专用编程语言，语法接近 Pascal，内置海量金融数据仓库函数（行情、财务、板块、选股、回测等）。它的三个特点，让通用大模型很容易写错：

- **语法冷门** —— 类定义要写成 `type Name = class ... end;`、内嵌 TS-SQL 的类 SQL 语句，大模型很容易踩坑。
- **函数量巨大** —— 数据仓库函数上万个，签名各异，模型凭记忆一定会编造参数。
- **文件模型敏感** —— `.tsl`（可执行脚本）与 `.tsf`（可复用声明）选错就直接编译失败。

**TSL Playbook 就是为解决这个问题而生的知识层**。它不是解释器，也不是运行时，而是一套喂给 AI 编码代理的**结构化文档 + 检索工具 + 硬约束路由**，目标只有一个：

> 让 AI 在写 TSL 时，每一处语法和每一个函数签名，都来自**可核对的文档事实**，而不是"看起来像别的语言"的幻觉。

### 核心理念

整个 playbook 建立在四条原则之上，贯穿所有文档——前三条是写进 `AGENTS.md` 的硬约束铁律，第四条是架构设计目标：

| 原则                | 含义                                                                                                                                                                     |
| :------------------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 🚫 **禁止发明语法** | 无文档结论、文件模型不明或执行事实缺失时，**停止并确认**，绝不用 Pascal / Python / JS 的相似写法补全。                                                                   |
| 🎯 **首跳路由**     | 任何 TSL 需求都从 `AGENTS.md` 常驻闸门起步，语法找 `tsl-syntax-reference`、函数找 `tsl-api-reference`、其余回 `docs/tsl/index.md` 分流，**不全目录搜索、不凭空猜路径**。 |
| 🧱 **块级证据**     | 候选摘要与概念地图只做粗判断；落代码时以 `--section` 正文里紧邻代码围栏的 `代码块身份` 为准 —— 只有标注 `可直接照写示例` 的块能当源码外形照抄。                          |
| 💾 **Token 高效**   | 分层索引 + 两段式按需检索，只把命中当前任务的事实载入上下文，不整包灌文档。                                                                                              |

### 架构设计

playbook 分三类构件：常驻的**硬约束**（`AGENTS.md`）、**分层的事实源**（语法与函数已外置为可分发的 skill，命名 / 风格 / 模块仍留在 `docs/` 文件里）、以及 skill 内**可执行的检索工具**（`lookup.py`）。下面先按事实源的职责分层，再逐一拆解两个 skill 的检索方式，最后由「首跳路由」把三类构件串成一条完整链路。

#### 分层知识库

文档按**职责**而非按目录平铺组织，每一层只回答自己那一层的问题：

| 层             | 载体                                    | 负责回答                                  | 不负责                       |
| :------------- | :-------------------------------------- | :---------------------------------------- | :--------------------------- |
| **硬约束层**   | `AGENTS.md`（仓库文件）                 | 铁律、首跳、阻断条件                      | 完整语法（故意不复写）       |
| **语法事实层** | `tsl-syntax-reference`（外置 skill）    | 语言规则、文件模型、控制流、类、TS-SQL    | 具体函数签名                 |
| **函数事实层** | `tsl-api-reference`（外置 skill）       | 12455 个函数的名字 / 签名 / 参数 / 返回值 | 语言语法                     |
| **模块集成层** | `docs/tsl/modules/`（仓库文件）         | pyTSL、策略回测、微信通知 API             | 纯语法、通用取数             |
| **风格偏好层** | `code_style.md` `naming.md`（仓库文件） | 命名与组织偏好                            | 语法事实（明确声明"仅偏好"） |

语法事实层与函数事实层都封装成 **Agent Skill**：由 `SKILL.md` 的 `description` 被模型模糊触发，正文规定"只经 `lookup.py` 检索、不手工通读参考页"的调用契约。以 `tsl-syntax-reference` 为例，检索分两步——先用 `--query` 拿候选与 Section ID，再用 `--section` 取回唯一事实正文：

```bash
# 第一步：--query 只返回紧凑候选 + Section ID（不含事实正文）
python skills/tsl-syntax-reference/scripts/lookup.py --query "命名参数 默认参数" --mode write

# 第二步：--section 精确取回该章节正文，才是可用的语法事实
python skills/tsl-syntax-reference/scripts/lookup.py --section "05_functions_and_calls--可直接照写示例--默认参数"
```

#### TSL 语法体系

`tsl-syntax-reference` skill 的 `references/` 用 **24 个专题**覆盖了 TSL 语言的方方面面，从最短骨架到矩阵深潜：

| 主题簇           | 专题                                                                                  |
| :--------------- | :------------------------------------------------------------------------------------ |
| **入门与模型**   | `01` 快速落代码 · `02` 文件模型（`.tsl`/`.tsf`）· `03` 值与字面量 · `04` 变量常量     |
| **函数与表达式** | `05` 函数与调用 · `06` 表达式运算符 · `07` 控制流                                     |
| **对象与模块**   | `08` 类与对象 · `09` unit 与作用域 · `24` 算符/遍历重载                               |
| **运行时**       | `10` 运行时上下文与 with · `15` 调试与性能 · `20` 对象自省 · `21` 内置运行时对象      |
| **数据结构**     | `12` 数组与集合 · `22` 矩阵深潜 · `23` FMArray · `13` 结果集过滤                      |
| **数据查询**     | `14` TS-SQL                                                                           |
| **底层与互操作** | `16` 词法与编译选项 · `17` 类型转换 · `18` external/DLL/线程 · `19` namespace/Libpath |
| **避坑**         | `11` 高频误写与反例                                                                   |

#### tsl-api-reference Skill

上万个数据仓库函数无法塞进上下文，playbook 把它做成一个**可调用的 Agent Skill**：一个 `function_index.tsv` 加一个 `lookup.py` 检索脚本。

```bash
# 已知函数名 → 精确查签名、参数、返回值、示例
python skills/tsl-api-reference/scripts/lookup.py --name argmax

# 只知道行为 / 中文关键词 → 关键词检索（AND 语义）候选
python skills/tsl-api-reference/scripts/lookup.py --kw 数组 排序
```

检索是**两段式**的：关键词查询先返回候选行（名字 + 一句话摘要），代理挑中后再用 `--name` 拉取该函数的完整文档块。

#### 首跳路由机制

这是 playbook 最核心的设计。`AGENTS.md` 是常驻的硬约束闸门（禁止发明语法、先定文件模型、事实边界与阻断条件始终最先命中）；语法与函数两类事实各自封装成 skill，由 `description` 触发，命中后一律走 `lookup.py` 检索；命名 / 风格 / 模块集成才回到 `docs/tsl/index.md` 分流：

```mermaid
flowchart TD
    A[用户提示词] --> B{AGENTS.md<br/>常驻硬约束 + 事实边界}
    B -->|语法 / 文件模型 / 控制流| D[tsl-syntax-reference<br/>Skill]
    B -->|取金融数据 / 查函数| E[tsl-api-reference<br/>Skill]
    B -->|命名 · 风格 · 模块集成| C[docs/tsl/index.md<br/>文档分流]
    D -->|--map 冷启动<br/>--query 候选 → --section 正文| H[24 篇语法专题]
    E -->|已知名 --name<br/>未知名 --kw| I[12455 条索引]
    C -->|命名/风格| G[naming.md /<br/>code_style.md]
    C -->|模块集成| F[modules/index.md]
    H --> Z[✅ 落 .tsl / .tsf 代码]
    I --> Z
    F --> Z
    G --> Z

    style B fill:#2b7489,color:#fff
    style D fill:#8250df,color:#fff
    style E fill:#8250df,color:#fff
    style Z fill:#2ea043,color:#fff
```

### 目录结构

```
playbook/
├── AGENTS.md                      # 常驻硬约束：铁律 + 事实边界 + fail-closed（不复写语法、不做首跳翻页）
├── docs/tsl/
│   ├── index.md                   # 命名/风格/模块的文档分流入口
│   ├── naming.md                  # 命名偏好（非语法事实）
│   ├── code_style.md              # 代码风格偏好（非语法事实）
│   ├── toolchain.md               # 工具链与验证命令模板
│   └── modules/                   # 模块集成：pyTSL / 回测 / 微信
├── scripts/                       # 第二部分三轮实测产出的 .tsl 存档
└── skills/
    ├── tsl-syntax-reference/      # 语法检索 Skill（原 docs/tsl/syntax/）
    │   ├── SKILL.md               #   ├─ 触发说明 + lookup 调用契约
    │   ├── scripts/lookup.py      #   ├─ 两段式检索脚本（--query/--section/--map）
    │   └── references/            #   └─ 24 篇语法专题（母本）
    │       ├── 01_quickstart.md   #       ├─ 快速落代码 / 最小骨架
    │       ├── 02_core_model.md   #       ├─ .tsl / .tsf 文件模型
    │       ├── ...                #       ├─ 函数/类/控制流/矩阵/TS-SQL...
    │       └── 24_object_overloads#       └─ 算符与遍历重载
    └── tsl-api-reference/         # 函数检索 Skill
        ├── SKILL.md               #   ├─ 触发说明
        ├── scripts/lookup.py      #   ├─ 检索脚本
        ├── data/function_index.tsv#   ├─ 12455 条函数索引
        └── references/codegen/    #   └─ 函数完整文档块
```

---

## 部署

两个 skill 都是**自包含目录**（`SKILL.md` + `scripts/` + `references/` 或 `data/`），没有安装器：把目录整个拷进目标 agent 的个人 skills 目录即可，之后由各 agent 按 `SKILL.md` 的 `description` 自动发现、模糊触发。

| Agent               | 个人 skills 目录    |
| :------------------ | :------------------ |
| Claude Code         | `~/.claude/skills/` |
| Codex CLI           | `~/.codex/skills/`  |
| 通用 `.agents` 约定 | `~/.agents/skills/` |

```bash
# 以 Claude Code 为例，两个 skill 一起装（换成对应目录即可部署到其他 agent）
cp -r skills/tsl-syntax-reference skills/tsl-api-reference ~/.claude/skills/

# 装好自检：无匹配或非零退出即说明目录不完整
python ~/.claude/skills/tsl-syntax-reference/scripts/lookup.py --check
```

要完整的 TSL 能力，两个 skill 需一起部署——`tsl-syntax-reference` 管语法事实，`tsl-api-reference` 管函数事实，缺一个都会在 `AGENTS.md` 的 fail-closed 规则下触发停止。

---

<div align="center">

## 👤 第二部分 · 多环境实测

**用户视角 —— 同一条提示词下的真实行为与产出**

</div>

> **同一条提示词，投给不同的 AI 编码环境，记录真实行为与产出。** 三轮实测：Claude Code · Fable 5、Codex CLI · GPT-5.5、Qwen 3.6-27B。

### 统一提示词

> 💬 _阅读AGENTS.md。写一个tsl策略。获取昨天的主板所有股票涨幅排名，取前50股票代码_

考察点五个，后文的过程回放与横向对比均按编号交叉标注：

- **① 函数真实性** —— 函数敢不敢编，是否逐一经 skill 查证
- **② 语法证据** —— 语法照不照抄，外形是否取自语法页「可直接照写示例」
- **③ 文件模型** —— `.tsl` / `.tsf` 后缀选没选对
- **④ 自主验证** —— 会不会自己验证：运行实测 / 静态检查 / 什么都不做
- **⑤ 边界诚实** —— 拿不准、验不了时，是硬写还是明说

三轮以这条原文为基准：第二、三轮仅在末尾追加了各自的输出文件路径，其余一字未改——代价是「③ 文件模型」在后两轮被显式给定、失去考察效力（对比表已如实标注）。

### 第一轮实测：Claude Code · Fable 5

> 环境：Claude Code（版本未记录）· Fable 5；`tsl-api-reference` skill 已注册；本机装有离线 TSL 解释器（无数据仓库连接）；输出路径未指定，文件名自定。

**真实过程回放**（每一步都能对应第一部分的机制）：

| 步骤            | 考察点 | 实际行为                                                                                                                                        |
| :-------------- | :----: | :---------------------------------------------------------------------------------------------------------------------------------------------- |
| 🧭 首跳照走     |   —    | 读 `AGENTS.md` → 进 `docs/tsl/index.md` 总入口 → 按路由取用快速落代码 / 控制流 / 数组集合三个语法页                                             |
| 🔍 函数全部查证 |   ①    | 调用 `tsl-api-reference` skill 逐一核实 `getAbkbyDate` · `lastTradeDay` · `stockZf8` · `appendArray` · `sortTableByField` —— **五个函数零编造** |
| 📖 语法照抄有据 |   ②    | 落码外形——`for ... in` 遍历、`array("Key": value)` 键表、`begin/end` 块——均见于取用三页的「可直接照写示例」，无文档外写法                       |
| 📄 文件模型判对 |   ③    | 一次性取数任务 → 按规则判为 `.tsl`，文件名自定，存档于 `scripts/main_board_top50_zf_claude.tsl`                                                 |
| ✅ 主动验证     |   ④    | 本机解释器实测：键表构造、循环截断、排序等 builtin 逻辑全部跑通，整个文件编译通过                                                               |
| 🗣 诚实报告边界 |   ⑤    | 数据仓库函数离线环境没有（`function not found`），**如实说明需在天软客户端端到端确认，而不是谎称全部跑通**                                      |

**产出代码**（原样，已存档：[scripts/main_board_top50_zf_claude.tsl](scripts/main_board_top50_zf_claude.tsl)）：

```tsl
// 主板股票昨日涨幅排名前 50
// 主板成分：上证A股 + 深证A股（getAbkbyDate 支持分号分隔多板块）
// “昨天”取当前日期的前一个交易日，避开周末/节假日

setSysParam(pn_cycle(), cy_day());

yday := lastTradeDay(date());      // 昨日（最近一个已收盘交易日）
prevday := lastTradeDay(yday);     // 昨日的前一个交易日

stocks := getAbkbyDate('上证A股;深证A股', yday);

result := array();
for i, stockid in stocks do
begin
    setSysParam(pn_stock(), stockid);
    zf := stockZf8(prevday, yday);  // prevday 收盘 -> yday 收盘的涨幅(%)，即昨日涨幅
    appendArray(result, array("StockID": stockid, "Zf": zf));
end

sortTableByField(result, "Zf", 0);  // 按涨幅逆序

top50 := array();
n := length(result);
if n > 50 then
begin
    n := 50;
end
for i := 0 to n - 1 do
begin
    appendArray(top50, result[i]["StockID"]);
end

return top50;
```

**亮点：** "昨天"没有偷懒写成日历昨天，而是用 `lastTradeDay(date())` 取**最近一个已收盘交易日**——周一运行会正确落在上周五；"主板 = 上证A股 + 深证A股"这个组合也是从函数文档示例里查证的，不是想当然。

**成本（token 为模型自估）：** 总耗时 16 分 57 秒；输入约 15–20 万（多数命中提示缓存），输出约 0.5–1 万。

### 第二轮实测：Codex CLI · GPT-5.5

> 环境：OpenAI Codex CLI v0.142.5 · gpt-5.5（reasoning xhigh）；提示词在第一轮基础上追加指定了输出路径 `scripts/main_board_top50_zf_codex.tsl`。注意：运行时仓库内已有本 README 的第一轮同题示例，模型读到过该片段（其后仍逐一核对了函数事实）。

**真实过程回放：**

| 步骤                      | 考察点 | 实际行为                                                                                                                                                        |
| :------------------------ | :----: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 🧭 首跳照走               |   —    | 读 `AGENTS.md` → 进 `docs/tsl/index.md` → 按路由取用 TS-SQL / 控制流 / 数组集合语法页，并核对 `toolchain.md` 确认验证入口仍是占位                               |
| 🧗 Skill 未注册，自行接通 |   —    | `tsl-api-reference` 不在其会话技能清单里 —— 没有放弃也没有瞎编，循索引找到仓库内 `skills/tsl-api-reference/SKILL.md`，直接用 `python` 调起 `lookup.py` 完成检索 |
| 🔍 函数全部查证           |   ①    | `--kw` 圈定候选后逐一 `--name` 核实 `getAbkbyDate` · `stockZf3` · `yesterday` · `spec` · `specDate` · `sortTableByField` · `min` · `length` · `writeLn`         |
| 📖 语法转页核对           |   ②    | 查 `MarketTable` 无此函数 → 正确判断它是数据表名，转 TS-SQL 语法页核对 `select ... end` 写法                                                                    |
| 🚫 证据驱动的弃用         |   ①    | 查到 `getTopN` 存在，但其文档记录示例运行报 `not found` —— **主动弃用**，改用文档已证明的 `order by ... desc` + 手动循环取前 50                                 |
| 🗣 诚实报告边界           |  ④ ⑤   | PATH 中无 `tsl`/`tslcli`，无法真实运行 → 只做静态检查（无裸 `=` 赋值、无声明区、关键语句在位），并如实说明"没法做真实 TSL 运行验证"                             |

**产出代码**（原样，已存档：[scripts/main_board_top50_zf_codex.tsl](scripts/main_board_top50_zf_codex.tsl)）：

```tsl
end_t := yesterday();

stocks := getAbkbyDate('上证A股;深证A股', end_t);

data := select ['StockID'] as "Code",
    spec(specDate(stockZf3(), ['date']), ['StockID']) as "Zf"
    from markettable datekey end_t to end_t of stocks end;

sorted := select ["Code"] from data order by ["Zf"] desc end;

n := min(50, length(sorted));
result := array();
if n > 0 then
begin
    for i := 0 to n - 1 do
    begin
        result[i] := sorted[i]["Code"];
        writeLn(result[i]);
    end;
end;

return result;
```

**亮点：** `getTopN` 的弃用是「块级证据」规则的教科书式执行——函数在索引里存在不等于能用，文档里的负向记录同样是事实；Skill 未注册时循 `AGENTS.md` 路由自行找到本地脚本，说明**硬约束层的兜底指路生效了**。

**对照差异：** "昨天"用的是 `yesterday()` 日历昨天，未处理周末/节假日——第一轮用 `lastTradeDay` 规避了周一取到周日的问题。

**成本（token 为 `/status` 实测）：** 本轮工作 9 分 21 秒；**总量 18.5 万 = 输入 15.9 万 + 输出 2.57 万**（上下文余量 42%）。

### 第三轮实测：Qwen 3.6-27B

> 环境：qwen3.6-27b（27B 开源模型，代理框架 vscode-tsl）；提示词同样追加指定了输出路径 `scripts/main_board_top50_zf_qwen3.6-27b.tsl`；耗时未记录。

**真实过程回放：**

| 步骤                    | 考察点 | 实际行为                                                                                                                                                                                             |
| :---------------------- | :----: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 🧭 首跳照走             |   —    | 读 `AGENTS.md` → 进 `docs/tsl/index.md` → 取用快速落代码 / TS-SQL 语法页，并直接调用 `lookup.py` 检索（其环境中文输出乱码，带病工作）                                                                |
| 🌀 文档缺口处反复打转   |   ①    | 盯上 `StockZf_No`（区间涨幅排名），但该函数的 `sort_by` / `return_type` 文档确实没给取值 —— 数十轮反复检索、重读同一页，**期间明确引用铁律"无文档结论……不发明语法"，始终拒绝猜参数**，最终绕开该函数 |
| ⚠️ 起念假设，又自行回撤 |   ②    | 中途多次想按"惯例"假设 `MarketTable` 的 `pre_close` 等字段名与 `refof`/`refsof` 用法，推演后自行放弃该路线，改用全部经查证的 `stockZf` 循环方案                                                      |
| 🔍 最终函数全部有据     |   ①    | 落码只用查证过的 `yesterday` · `getAbkbyDate` · `setSysParam`/`PN_Stock` · `stockZf` · `drange` · `dateToStr` · `echo`                                                                               |
| 🤐 收尾缺验证与边界声明 |  ④ ⑤   | 产出后仅回读文件自查"逻辑看起来正确"，未做静态检查，也未声明"未经运行验证" —— 三轮中唯一没交代验证边界的                                                                                             |

**产出代码**（原样，已存档：[scripts/main_board_top50_zf_qwen3.6-27b.tsl](scripts/main_board_top50_zf_qwen3.6-27b.tsl)）：

```tsl
#! 获取昨天主板所有股票涨幅排名，取前50股票代码

dt := yesterday();
dt_prev := dt - 1;

stocks := getAbkbyDate('上证A股;深证A股', dt);
n := length(stocks);

gains := array();
for i := 0 to n - 1 do
begin
    setSysParam(PN_Stock(), stocks[i]);
    zf := stockZf(dt_prev, dt);
    gains[i] := array("code": stocks[i], "zf": zf);
end;

top50 := select * from gains
         order by ["zf"] desc
         end;
top50 := select drange(0 to 49) * from top50 end;

echo "昨天(" $ dateToStr(dt) $ ")主板涨幅前50：";
for i := 0 to length(top50) - 1 do
begin
    echo (i + 1) $ ". " $ top50[i]["code"] $ "  涨幅:" $ top50[i]["zf"] $ "%";
end;
```

**亮点：** 铁律对 27B 小模型同样有约束力——面对文档缺口，它宁可绕路几十轮也没编造参数；还反向暴露了知识库自己的洞：`StockZf_No` 的参数取值枚举确实没写——正是「后续升级方向 · 检索质量 / 分类治理」要补的文档债。

**对照差异：** 代价是收敛效率的巨大差距，收尾也少了前两轮的验证动作与诚实边界；交易日处理三轮中最弱——`yesterday()` 与 `dt - 1` 全按日历日，周末/节假日双双踩空。

**成本（模型自估，口径偏小）：** 约 1.5–2.5 万 token。其事后自查归因：**20+ 次无效检索全耗在 `StockZf_No` 没写的参数枚举上**；9252 行的 `equity/misc.md` 被反复载入约 15 次；`lookup.py` 输出 GBK/UTF-8 乱码又加剧了关键词重试。注意：该自估按"读到的内容量"计，未计 30+ 次工具调用的上下文重复携带，实际消耗应显著更高。

### 横向对比

**五个考察点：**

| 考察点       | Claude Code · Fable 5                       | Codex CLI · GPT-5.5                          | Qwen 3.6-27B                                              |
| :----------- | :------------------------------------------ | :------------------------------------------- | :-------------------------------------------------------- |
| ① 函数真实性 | skill 逐一查证 5/5，零编造                  | 全部查证，并依据文档负向记录弃用 `getTopN`   | 全部查证；面对 `StockZf_No` 文档缺口拒绝编参数，绕路重来  |
| ② 语法证据   | 外形均见于取用三页的可照写示例              | `MarketTable` 判为表名后转 TS-SQL 页核对写法 | 拒绝按"惯例"假设字段名与 `refof` 用法，回撤改走已查证路线 |
| ③ 文件模型   | `.tsl` 判定正确（文件名自定）               | `.tsl`（文件名由提示词给定，未构成考察）     | `.tsl`（文件名由提示词给定，未构成考察）                  |
| ④ 自主验证   | 本机解释器实测 builtin 跑通、整文件编译通过 | 环境无解释器，静态检查                       | 仅回读文件自查，无静态/运行验证                           |
| ⑤ 边界诚实   | 明说 dotnet 函数需客户端确认                | 明说无法真实运行验证，列出静态证据           | 收尾未声明未验证状态                                      |

**额外观察与成本：**

| 维度       | Claude Code · Fable 5                           | Codex CLI · GPT-5.5                            | Qwen 3.6-27B                                    |
| :--------- | :---------------------------------------------- | :--------------------------------------------- | :---------------------------------------------- |
| Skill 接入 | 已注册，直接调用                                | 未注册 → 循路由自行找到 `lookup.py` 手动调用   | 未注册 → 手动调用（检索输出乱码，带病工作）     |
| 交易日处理 | `lastTradeDay` 取最近交易日，周一跑正确落上周五 | `yesterday()` 日历昨天，逢周末可能取到无行情日 | `yesterday()` 与 `dt-1` 全日历日，三轮中最弱    |
| 检索效率   | 一次路由到位                                    | 一次路由到位 + 证据驱动取舍                    | 在同一文档缺口反复打转数十轮                    |
| 总耗时     | 16m57s                                          | 9m21s                                          | 未记录                                          |
| token      | 自估：输入 15–20 万 / 输出 0.5–1 万             | 实测：18.5 万 = 15.9 万入 + 2.57 万出          | 自估：约 1.5–2.5 万（未计上下文重复，口径偏小） |

> **对照说明：** ① 第二、三轮提示词在第一轮基础上各自追加了输出文件名，文件命名被显式给定；第一轮产出原名 `main_board_top50_zf.tsl`，存档时加 `_claude` 后缀以区分三轮；② 第二轮运行时仓库内已有本 README 的同题示例，模型读到过该片段（其后仍逐一核对了函数事实）；③ 三轮本地条件不同——第一轮机器装有离线 TSL 解释器，第二轮 PATH 无解释器，第三轮未尝试任何运行验证；④ 第三轮的耗时未记录，token 为模型按"内容量"事后自估、未计多轮上下文重复携带——三轮 token 口径各不相同（实测 / 含缓存自估 / 内容量自估），不可直接横比。以上数字与行为仅作真实记录，不构成严格受控对比。

### 三轮小结

- **机制得到验证** —— skill 已注册、未注册自行接通、检索乱码带病工作三种接入条件下，三轮全部零函数编造；「禁止发明语法 + 首跳路由 + 块级证据」对 27B 开源小模型同样有约束力。
- **验证与诚实呈梯度** —— 三轮收尾分别是解释器实测、静态检查、无验证亦无声明；在 `toolchain.md` 执行入口实体化之前，「必须验证」写不成硬约束，收尾质量只能靠模型自觉。
- **实测暴露的文档债均已入计划** —— `StockZf_No` 参数取值缺失 →「检索质量 · 参数类型实证」；`equity/misc.md` 兜底堆积拖慢检索 →「分类治理」。

---

<div align="center">

## 🔭 第三部分 · 后续升级方向

**演进视角 —— 已到哪一步、下一步往哪走**

</div>

> 语法层已完成 Skill 化（`docs/tsl/syntax/` 24 篇搬入 `tsl-syntax-reference` skill，与 `tsl-api-reference` 对齐成统一的 lookup 调用模型）。playbook 已覆盖语法、函数、模块三大知识面，下一步围绕**分类治理、覆盖广度、检索质量、Agent Loop**四大方向推进。

### 🗂 分类治理 · codegen 归类校准与全量可用性核验

- **方向** — 复核 codegen 母本（builtin 10 类 / dotnet 21 类）的函数归类，纠正错分与 `misc` 兜底堆积（如 `equity/misc.md` 单页已累至 9252 行、759 个函数），填充或裁撤 builtin `finance` / `market` 两个空壳类目，让类目边界清晰；并对全部 12455 个函数逐一探针实测，给每个函数标注真实可用性状态。
- **目的** — 一方面让 `--kw` 关键词检索落在符合直觉的类目、候选更准；另一方面用实测的「可用 / 真缺失 / 参数不对」三态，取代"索引里有就默认能用"的假设，从源头杜绝把不可用函数写进生成代码。
- **难点**
  - **规模大、纯手工** — 上万个函数逐一复核归类，只能手工搬运并同步维护索引一致性，工作量大且易漏。
  - **可用性须真解释器** — 「可用」无法静态判定，须接真实 TSL 解释器对上万函数逐一探针（`toolchain.md` 的执行入口目前仍是模板占位），规模大、成本高。
  - **假阴性要甄别** — 探针报错可能是"函数真缺失"，也可能只是"参数没给对"；两者须隔离区分（`special/pending` vs `special/unknown`），否则会把本可用的函数误标为不可用。

### 📚 覆盖广度

- 扩充 `modules/`：补充更多平台模块（比如 TS-OPI）的 API 事实页；整个 `modules/` 以后还需迁移到 `tsl-api-reference`。
- 沉淀**场景配方库**（Recipe）：把"选股 → 回测 → 通知"这类高频端到端流程做成可照写的组合骨架。
- 为常见报错建立**反例 → 正确写法**的快速跳转索引，让避坑更即时。

### 🔍 检索质量

- 为 `function_index.tsv` 增加**参数类型实证**：当前仍有约 2600 个函数（builtin 246 / dotnet 2382）的参数声明为 `any`/`object`，需用 `dataType()` 逐一收紧。
- 引入**语义检索**（embedding），让"我想算个动量因子"这类模糊意图也能命中相关函数。
- 为函数打**标签 / 近义词**（场景 · 资产 · 操作维度），降低 `--kw` 空命中率、让检索更精准更细致。

### 🔁 Agent Loop（规划中）

- 把「写 TSL → 跑解释器 → 拿报错 → 回查语法 / 函数 → 改 → 再跑」闭成自动循环，让验证成为流程本身，而不是靠模型自觉（详见 [AGENT_PRIMER.md](AGENT_PRIMER.md) 对 Loop 的说明）。
- 尚未规划落地方案，先作为方向记录。

---

<div align="center">

_TSL Playbook —— 不是让 AI "会写代码"，而是让 AI "只写有据可查的代码"。_

</div>
