Skip to content

Commit 3bef2dc

Browse files
committed
docs(llmdoc): 同步自 8fbf352 以来的变更
- 新增反思 878-xunicode-symbols-multilevel-fallback:xunicode-symbols.tex 五级逐字符字体回退链 (FreeSerif → Noto Sans Symbols 2 → Symbola → Segoe UI Symbol → DejaVu Sans) 的根因、`\IfFontExistsTF` + `\cs_if_exist_use:N` + `\tex_iffontchar:D` 组合模式与适用边界。 - 新增反思 874-876-agentic-fork-shielding-cron:agentic-*.yml 的两条 边界约束 (job 级 fork 门控 + schedule 每天一次) 与未来扩展规则。 - architecture/xecjk-architecture.md:在 xunicode-addon 节下补 #878 逐字符多级字体回退说明。 - architecture/ctex-architecture.md:在字号系统下补 #871 letterpress 仅为金属活字字号体系之一的勘误说明。 - reference/build-and-test.md:CI 字体策略改写为反映五级回退链; agentic 工作流频率改为每天一次北京时间 08:00 并新增 fork 门控小节; 新增 LaTeX2e 2026-06-01 格式依赖声明 (#883) 小节。 - reference/coding-conventions.md:新增 `.choices:nn` 用 `#1` 替代 `\l_keys_choice_str` 的 expl3 约定 (#806 / PR #881)。 - index.md:刷新 ctex / xeCJK / build-and-test / coding-conventions 描述行,并补两条 reflection 索引。
1 parent 96ba06e commit 3bef2dc

7 files changed

Lines changed: 257 additions & 9 deletions

File tree

llmdoc/architecture/ctex-architecture.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,11 +142,15 @@ pdfTeX 下 ctex 通过 CJK 宏包处理中文字符。UTF-8 编码的多字节
142142
|| 含义 |
143143
|----|------|
144144
| `word` | 默认,现代 Word 字号体系 |
145-
| `letterpress` | 金属活字时代字号(原名 `traditional`#813 更名) |
145+
| `letterpress` | 金属活字排印字号体系**之一**(原名 `traditional`#813 更名) |
146146
| 自定义名 | 尝试加载 `ctex-fontsize-<name>.def` |
147147

148148
自定义字号表通过 `\ctex_save_font_size:nn` 写入数据。
149149

150+
#### `letterpress` 的语义边界(#871 文档勘误)
151+
152+
`letterpress` 仅是历史上多种金属活字字号约定中**一种**严格倍数体系(初号/二号/五号/七号 ×2 等比;一号/四号 ×2;三号/六号/八号 ×2),并**不是**唯一定义。`ctex.dtx` 的字号映射表(标准字号 ↔ 字号名)与中文字号表附近的说明文档都明确提示:默认 `word` 字号与 `letterpress` 字号在「初号/二号/五号/七号」六个尺寸上数值不同,用户切换字号体系时这些字号会变化。该提示通过 #871 的文档补丁加入,对应 `ctex.dtx` `\changes` v2.6.0 2026/06/23。
153+
150154
### 冻结语义
151155

152156
字号表在类/宏包选项解析期冻结为常量 prop,不支持运行时通过 `\ctexset` 切换。后续 `\zihao` 与数学字号声明直接读取这份编译期常量。

llmdoc/architecture/xecjk-architecture.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,18 @@ XeTeX 的 interchar 机制工作在 token 层,无法区分字符来自 Unicode
329329

330330
为 xunicode 补充额外的 Unicode 符号命令定义。
331331

332+
#### `xunicode-symbols.tex` 驱动的逐字符多级字体回退(#878
333+
334+
`xunicode-symbols.tex``xunicode-addon` 用于演示其覆盖字符集合的驱动文件,由 `l3build install --full` 排版生成 `xunicode-symbols.pdf`。该集合横跨多个 Unicode 区段(符号、几何形状、CJK Stroke 等),**不存在**在主流 Windows / Linux / macOS 上都默认装且覆盖完整的单一字体;此前版本采用“整段单字体 if-else”的回退策略时,凡是被选中字体未覆盖的字符都会以 `Missing character` 警告出现。
335+
336+
PR #886(fix #878)将驱动改为“逐字符多级字体回退链”:
337+
338+
1. 用 fontspec 的 `\IfFontExistsTF` 条件声明候选 NFSS 字体家族 `\xunsymNoto``\xunsymSymbola``\xunsymSegoe``\xunsymDejaVu`,主字体仍为 `FreeSerif`
339+
2. `\UnicodeTextSymbol` 在排出每个 codepoint 前,使用 `\reverse_if:N \tex_iffontchar:D \tex_font:D #1 \exp_stop_f:` 测试当前激活字体是否含该字符;不命中则通过 `\cs_if_exist_use:N` 切换到下一级候选家族后再次测试,形成 `FreeSerif → Noto Sans Symbols 2 → Symbola → Segoe UI Symbol → DejaVu Sans` 五级嵌套链。
340+
3. `\cs_if_exist_use:N` 用于在“候选字体在本机不存在 ⇒ `\newfontfamily` 未定义该家族”时静默跳过、由外层 `\reverse_if:N` 继续向下级落,避免 `! Undefined control sequence`
341+
342+
该模式只适用于“演示性符号目录”驱动文件,**不应**推广到 xeCJK 正文 / CJK 字体路径(后者属于字符分类驱动的字体切换,不是 codepoint glyph 级缺失)。详细根因、嵌套顺序选择理由与适用边界见反思 [[878-xunicode-symbols-multilevel-fallback]];驱动新增段对应 `xeCJK.dtx` `\changes` v3.10.0 2026/06/23。
343+
332344
## TECkit 映射
333345

334346
xeCJK 在构建时通过 `xeCJK/build.lua` 中的 `make_teckit_mapping()` 从 Unicode Unihan 数据生成 `.map`/`.tec` 字体映射文件,用于繁简转换和句号形态映射。这部分功能数据在构建阶段动态生成,不完全静态存储。

llmdoc/index.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@
77
## architecture
88

99
- `llmdoc/architecture/package-architecture.md``ctex``xeCJK` 的主干架构、引擎适配策略、第三方包补丁子系统与包间依赖图;现含 xeCJK 对 #407/#800`\xeCJKchar` + 定点补丁策略,以及边界恢复链中 `\lastkern` 标记 kern、whatsit 定点重放(含 `\set@color` / `\reset@color` / `\Hy@BeginAnnot` / `l3color` 后端四类)、#324 宏路径多余 glue 遮蔽、#826 fntef 右侧 glue-on-kern-pair 遮蔽、#831 显式 `}` / `\textcolor` color-pop / `\mbox` hlist 三种变体、#832 l3color `\__color_select:N`/`\__color_backend_reset:` kern 对保护、ecglue 缓存取值四层约束的统一心智模型;fntef 双向 `\g_@@_last_node_tl` 全局状态隔离模式(`\xeCJK_fntef_sbox:n` hbox 隔离 + #830 ulem save/restore 隔离);以及 #859 `experiment/punct-measure-fix` 段落模式下 `\unskip` 吞掉段末标点补偿 glue 的 `para/end` 钩子补偿机制。
10-
- `llmdoc/architecture/xecjk-architecture.md` — xeCJK 独立架构详解:interchar token 机制、字符分类体系、类别转换矩阵(含 CJK→Boundary handler 对 catcode 2 的处理)、边界恢复状态机三层模型(含 `\@@_check_for_glue_skip:` kern 路径 + 非 kern 三分支:hlist / whatsit(`\g_@@_reset_color_pending_bool` 门控)/ fallback;`\g_@@_ulem_pending_bool` 三 set 点)、`\reset@color``l3color` 后端定点补丁(#832 `\__color_select:N`/`\__color_backend_reset:` kern 对保护)、字体管理、标点压缩系统(含 `\@@_punct_boundary_guard:` inner mode penalty 保护与 #859 `experiment/punct-measure-fix` 段落模式 `para/end` 钩子补偿)、间距系统、兼容性补丁模式、`\char` 约束与扩展子包(含 xeCJKfntef 双向全局状态隔离`\xeCJK_fntef_sbox:n` hbox 隔离 + `\xeCJK_ulem_right:` save/restore 隔离)。
11-
- `llmdoc/architecture/ctex-architecture.md` — ctex 独立架构详解:分层加载、键值选项、引擎适配(含 pdfTeX UTF-8 `\DeclareUnicodeCharacter` 优先查找)、字号系统、方案/标题/字体集、命令补丁与实验性接口。
10+
- `llmdoc/architecture/xecjk-architecture.md` — xeCJK 独立架构详解:interchar token 机制、字符分类体系、类别转换矩阵(含 CJK→Boundary handler 对 catcode 2 的处理)、边界恢复状态机三层模型(含 `\@@_check_for_glue_skip:` kern 路径 + 非 kern 三分支:hlist / whatsit(`\g_@@_reset_color_pending_bool` 门控)/ fallback;`\g_@@_ulem_pending_bool` 三 set 点)、`\reset@color``l3color` 后端定点补丁(#832 `\__color_select:N`/`\__color_backend_reset:` kern 对保护)、字体管理、标点压缩系统(含 `\@@_punct_boundary_guard:` inner mode penalty 保护与 #859 `experiment/punct-measure-fix` 段落模式 `para/end` 钩子补偿)、间距系统、兼容性补丁模式、`\char` 约束与扩展子包(含 xeCJKfntef 双向全局状态隔离 + xunicode-symbols.tex 五级逐字符字体回退链 #878)。
11+
- `llmdoc/architecture/ctex-architecture.md` — ctex 独立架构详解:分层加载、键值选项、引擎适配(含 pdfTeX UTF-8 `\DeclareUnicodeCharacter` 优先查找)、字号系统(含 #871 `letterpress` 仅为金属活字字号体系**之一**的勘误说明)、方案/标题/字体集、命令补丁与实验性接口。
1212
- `llmdoc/architecture/cleveref-patch.md` — cleveref 兼容补丁机制、挂钩链、`patch/cleveref` 开关与 Issue #725 根因分析。
1313

1414
## reference
1515

16-
- `llmdoc/reference/build-and-test.md``l3build`、共享构建配置、`ctex` 180 个主回归测试的覆盖簇、多引擎基线策略、LuaTeX 预热与 CI/CD 参考
17-
- `llmdoc/reference/coding-conventions.md` — expl3 命名、e-type 优先约定、`@@` 私有空间、作用域语义、docstrip 标签、`\CTEX@` 遗留接口与文档排版基础设施。
16+
- `llmdoc/reference/build-and-test.md``l3build`、共享构建配置、`ctex` 180 个主回归测试的覆盖簇、多引擎基线策略、LuaTeX 预热、CI/CD、CI 字体策略(含 #878 `xunicode-symbols.tex` 五级逐字符字体回退链最低保证)、agentic 工作流来源与频率约束(#874/#876)、LaTeX2e 2026-06-01 格式依赖声明(#883
17+
- `llmdoc/reference/coding-conventions.md` — expl3 命名、e-type 优先约定、`@@` 私有空间、`.choices:nn``#1` 替代 `\l_keys_choice_str`#806 / #881)、作用域语义、docstrip 标签、`\CTEX@` 遗留接口与文档排版基础设施。
1818
- `llmdoc/reference/ctex-fontset-mac.md``ctex``fontset=mac` / `macnew` / `macold` 的选择逻辑、macOS 15+ 检测后备、XeTeX/LuaTeX 字体探测差异与回退语义。
1919

2020
## guides
@@ -58,4 +58,6 @@
5858
- `llmdoc/memory/reflections/324-boundary-reserve-space-glue.md` — 反思: xeCJK #324 中宏路径提前输出空格 glue 遮蔽 `CJK-space` 标记 kern,破坏 `\lastkern` 边界恢复;修复同时揭示 xeCJK→ctex 的广泛基线联动。
5959
- `llmdoc/memory/reflections/826-fntef-boolean-flag-iteration.md` — 反思: xeCJK #826 fntef glue-on-kern-pair 初始修复后的迭代——`\l_@@_last_skip` 状态污染、`\quad` 误处理、fallback 路径错误的根因与三层过滤收敛过程。
6060
- `llmdoc/memory/reflections/831-reset-color-pending-bool.md` — 反思: #831 colorbox/textcolor 右侧间距修复四轮迭代——从 `\reset@color` 直接插入 kern 对到 `\g_@@_reset_color_pending_bool` 专用布尔延迟处理的收敛过程,核心教训为共享全局布尔的语义过载风险。
61+
- `llmdoc/memory/reflections/878-xunicode-symbols-multilevel-fallback.md` — 反思: xeCJK #878 `xunicode-symbols.tex` 驱动从“整段单字体 if-else”升级为 `FreeSerif → Noto Sans Symbols 2 → Symbola → Segoe UI Symbol → DejaVu Sans` 五级逐字符 `\iffontchar` + `\cs_if_exist_use:N` 链;只适用于演示性符号目录驱动文件,不应推广到正文 / CJK 字体路径。
62+
- `llmdoc/memory/reflections/874-876-agentic-fork-shielding-cron.md` — 反思: #875 / #874 `agentic-*.yml` 同时存在两条边界约束——job 级 `if: github.repository == ...` 把 fork 调度挡在 runner 分配之前,`schedule` 频率回退到每天一次北京时间 08:00;未来新增 agentic 工作流时这两条都应作为默认。
6163
- `llmdoc/memory/reflections/ctex-architecture-doc.md` — 反思: ctex 架构独立文档的创建过程、源码阅读方法与已知文档缺口。
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
---
2+
name: 874-876-agentic-fork-shielding-cron
3+
description: agentic 定时工作流的双重约束——“仅在主仓库运行”与“放大调度间隔”——背后的原因、修复模式与可复用规则
4+
metadata:
5+
type: feedback
6+
---
7+
8+
# 反思: #874 / #876 agentic 定时任务的来源与频率约束
9+
10+
## 起因
11+
12+
仓库的 `.github/workflows/agentic-*.yml` 系列工作流包含 `pull_request_target`
13+
触发的 PR 审查、定时触发的 llmdoc 更新与定时触发的 patrol 巡查。
14+
两个被本轮处理的相关问题:
15+
16+
1. **#875 → PR #876**:定时 `schedule` 触发会在 fork 仓库里****被 GitHub Actions 启动。
17+
fork 通常没有配置 `ANTHROPIC_API_KEY` 等密钥,定时 job 启动后立刻进入鉴权失败、
18+
或更糟:在被 fork 的镜像上发出对真实仓库的 API 调用,污染 issue 时间线。
19+
2. **#874**:patrol 巡查最初配置为每 4 小时一次。这是 Claude Code 自动化早期“尽可能
20+
及时”的默认值。运行一段时间后发现:
21+
- patrol 任务大部分时段只是“扫描,无事可做”;
22+
- 高频运行带来无意义的 token 消耗,对一个志愿者维护的仓库不可持续;
23+
- 在偶发 outage 或瞬时网络错误时,反而放大失败噪声。
24+
25+
## 修复模式
26+
27+
### 仓库归属门控(#876
28+
29+
在所有 `agentic-*.yml` 的定时与手动触发 job 顶部加入:
30+
31+
```yaml
32+
if: ${{ github.repository == 'CTeX-org/ctex-kit' }}
33+
```
34+
35+
这条 `if` 必须挂在 **job 级**而不是某一 step 上:fork 启动 workflow runner
36+
本身就消耗 fork 主用的 Actions 配额,挡在 step 上时 runner 已经被分配。
37+
挂在 job 级时,GitHub Actions 在调度阶段直接判定为跳过,不分配 runner。
38+
39+
同一模式也适用于 `pull_request_target` 类工作流,但那种触发由 PR 行为驱动,
40+
fork 默认就拿不到密钥;本次主要约束的是**纯 `schedule` 触发**与
41+
**`workflow_dispatch` 触发**这两类不会被 PR 来源天然过滤的入口。
42+
43+
### 频率回退(#874)
44+
45+
`agentic-patrol.yml` 的 `schedule` 表达式从“每 4 小时一次”调整为
46+
“每天一次,触发时刻 UTC 0:00 = 北京时间 08:00”:
47+
48+
```yaml
49+
schedule:
50+
- cron: '0 0 * * *'
51+
```
52+
53+
选择 08:00 北京时间的考量是:维护者人活动峰值集中在白天,需要尽快发现并人工
54+
跟进 patrol 报告时,工作时段开始前刚完成的扫描结果最有用;同时也避开了
55+
高峰 GitHub Actions 队列时段(通常工作日 UTC 14:00–18:00)。
56+
57+
## 为什么这两条要一起记
58+
59+
**Why:** 这两个修复看上去独立(“fork 别跑” vs “跑得别那么频繁”),
60+
但都属于“agentic 自动化的运行边界条件”,未来再加 agentic 工作流时应
61+
**同时**考虑这两件事:来源是否需要门控、频率是否需要回退。
62+
63+
**How to apply:**
64+
- 任何新增 `agentic-*.yml`:
65+
1. job 级加 `if: ${{ github.repository == 'CTeX-org/ctex-kit' }}`,除非该 job
66+
的设计就是为了被 fork 复用。
67+
2. `schedule` 触发频率默认走“每天一次北京时间白天”,不要默认 4 小时或 1 小时。
68+
更高频率需要明确的工程动机(如 release notes 实时拼装等不能等一天的场景)。
69+
- 修改已有 agentic 工作流时,**不要顺手把这两条去掉**:
70+
- fork 门控如果出现在 PR diff 里被建议移除,先确认是否真的要让 fork 跑。
71+
- 频率调高时应该附带说明为什么不能再等一天。
72+
73+
## 教训
74+
75+
1. **GitHub Actions 在 fork 上仍会调度 `schedule` workflow**。这是
76+
GitHub Actions 的设计行为,文档上有但实际维护者经常忽略。一旦该
77+
workflow 调用了外部 API,fork 的运行可能产生**真实**的 issue/comment
78+
写入(如果 fork 里 secret 被 fork 拥有者补齐)。
79+
2. **agentic 任务的频率不是“越高越好”**。高频运行会放大瞬时错误、消耗
80+
token 配额、淹没真正有信号的 patrol 输出。每天一次足以覆盖
81+
ctex-kit 这种以周为节奏的维护节拍。
82+
3. **`if` 的位置很重要**:job 级 `if` 才能避免 runner 被分配,step 级
83+
`if` 只是阻止该 step 执行。在 fork 上分配 runner 也算 fork 主消耗。
84+
85+
## 相关引用
86+
87+
- 触发约束实现:`.github/workflows/agentic-patrol.yml`、
88+
`.github/workflows/agentic-llmdoc-updater.yml`
89+
`.github/workflows/agentic-pr-review.yml`(PR #876 的相关 hunk)。
90+
- 频率配置:`.github/workflows/agentic-patrol.yml` 的 `schedule` 段(PR #874)。
91+
- 已有 agentic 工作流定位:参见 [[reference/build-and-test]] 中
92+
“CI/CD 配置”小节列出的三条 agentic 工作流。

0 commit comments

Comments
 (0)