Files
OJ2/docs/ast-rules.md
yuetsh a8408c0bb5 docs: 文档整理,CLAUDE.md 瘦身一半,删掉重写期已完成的 22 份阶段产物
CLAUDE.md 从 490 行降到 228 行:只留日常要当场记住的约束,展开拆成五份专题
文档 —— docs/deploy.md(部署与备份恢复)、database.md(迁移执行器、基线、
drizzle-kit 的坑)、timezone.md(时区口径与那次成就订正)、contract.md
(出参不 parse 的四次故障)、ast-rules.md(AST 规则与 C++ 的调用形态)。

删掉的是阶段 0–5 那批一次性产物:4 份实施计划、10 份评审/核验/修复报告、
endpoint-inventory.md(110 端点是 2026-08 的快照,现在 363 条路由)、
docs/spikes/ 的 spike 与提取脚本(结论早已落进代码)。phase5 切换手册删之前
先把仍然有效的部分提炼进 docs/deploy.md:拓扑、deploy.sh、部署后验证清单、
NPM 那两个不能关的开关、pg_dumpall 恢复的两个坑、镜像体积;演练报告与回滚
两节随旧栈下线一并作废。

两份设计文档保留,补上状态行说明它们是「当初为什么这么定」而不是现状。

apps/web/CLAUDE.md 顺手订正过期内容:PUBLIC_OJ_URL / PUBLIC_WS_URL 两个变量
早已不存在(baseURL 写死 /api,dev 走 vite proxy、线上由 Caddy 同源伺服),
store 与 composable 清单补齐到与目录一致。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-16 08:03:26 -06:00

52 lines
2.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AST 代码规则
规矩在 `CLAUDE.md`「AST 代码规则」一节。这里是加语言、加 target 时要一起看的细节。
## 为什么会有 `check:ast`
契约的 `AST_NODE_TARGETS_BY_LANGUAGE` 是**唯一**一张表,一个 target 一条
`{ label, node }``label` 给后台下拉和题目页,`node` 给判题机比 tree-sitter 节点类型。
运算符表 `AST_OPERATOR_TARGETS_BY_LANGUAGE` 一份两用(它的值既是文案又是要比的 token
判题机侧没有第二张表,解析统一走契约的 `astTargetNodeType()`,所以**加 target 而漏配节点
类型在结构上不可能**。
但**配错**仍然可能,而且完全静默:节点类型对不上就是一个都收不到,于是「必须使用 X」永远
失败、「不能使用 X」永远通过两头不报错只有学生受着。
```bash
bun run --filter '@oj2/api' check:ast # 每个 target 的 node 在语法里是否真实存在
```
**升级 `tree-sitter-*` 依赖之后一定要跑一次** —— 语法改节点名是常事,后果全静默。
加这个检查那天56 个 target 里就抓出一个:`f_string` 一直配的是 `format_string`
而这个版本的 tree-sitter-python 根本没有这种节点f-string 是 `string` 里带
`interpolation`),所以「不能使用 f-string」从上线起就没生效过。
它只验节点类型**存在**,不验语义对不对(把 `while_loop` 配成 `for_statement` 这种两个都
存在,机器看不出来),语义那层还是得实跑。
## 只有三种语言真的会跑
判题机只认 `AST_SUPPORTED_LANGUAGES`C / C++ / Python3。别的语言配了规则一条都不会跑
所以后台不给它们开 tab题目页也不把它们的规则展示成「要求」——
**看得见却不检查**比没有更糟。
## C++ 不是「C 加几条」那么简单
C++ 的语法表是「C 的全集 + C++ 独有的几条」,因为 tree-sitter-cpp 继承 tree-sitter-c
C 那 14 个 target 在 C++ 树里逐个实测通用。但**调用形态两者不同**,加语言时必须一起看:
- `a.push_back()``p->push_back()` 在 C++ 都是 `call_expression` + `field_expression`
不是 Python 的 `attribute`
- `std::sort(...)` 的 function 是 `qualified_identifier` 而不是 `identifier`,所以
`functionCalls` 对 C++ 额外比一次 `::` 末段 —— 否则学生写了 `using namespace std` 与否
会得到不同的判定结果。
## 规则的语义校验为什么不在 zod 上
`astRulesError()`,不在 `astRulesSchema` 的 refine 上:那个 schema 同时用于**读**后台
题目详情,在读路径上抛错会让历史脏数据把整个题目详情打不开(同 `docs/contract.md` 那套教训)。
同理,保存前先 `pickAstRules()` 剔除够不着的分组再校验,否则早年配过 C++ 规则的题会把老师
锁死 —— tab 里看不到那组规则,保存却被拦下。