From 0b4a7de1b6837fb71e965b587fe791f1744855ca Mon Sep 17 00:00:00 2001 From: ThreeFish Date: Sun, 18 Oct 2026 11:12:44 +0800 Subject: [PATCH 1/8] =?UTF-8?q?docs(profile):=20=E4=B8=BB=E9=A1=B5?= =?UTF-8?q?=E6=89=8B=E5=86=99=E9=87=8D=E5=A4=8D=E6=94=B6=E6=95=9B=E2=80=94?= =?UTF-8?q?=E2=80=94=E4=B9=9D=E5=8E=82=E5=95=86=E6=B8=85=E5=8D=95=E4=B8=8E?= =?UTF-8?q?=20no-Redis=20=E7=9F=AD=E8=AF=AD=E5=90=84=E5=BD=92=E5=94=AF?= =?UTF-8?q?=E4=B8=80=E6=9D=83=E5=A8=81=E4=BD=8D;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - coding-proxy 九厂商清单曾两处全文手写且已实际漂移过一次(PR #7 仅单侧补 Xiaomi):项目卡定为唯一权威清单,深潜块收敛为回指,消除双清单结构; - 故障转移 doctrine 句去掉第三处 no Redis/no queue 点名(权威位保留项目卡与总栈行),因果链改由 SQLite-WAL 本地性直接引出; - 中英两份 README 逐行镜像同步;13 FIG + 75 DATA 标记流、锚点三方契约、全部冻结面零触碰,31 用例与 --lint 全绿。 🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang --- README.md | 4 ++-- docs/i18n/zh-CN/README.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a6f24b7..70821f6 100644 --- a/README.md +++ b/README.md @@ -212,7 +212,7 @@ - **`give-me-a-break`** — the state machine's `evaluate` has zero time dependency. It takes the clock as an argument, so the entire rest/work/AFK lifecycle is testable against a virtual clock: sleep, crash recovery with fast-forward, a display unplugged mid-break. Three modules, one of which knows nothing about macOS. - **`hyper-git`** — `engine/` contains no `vscode` import. That single constraint is why 403 unit tests exist: changelist grouping, DAG swimlane layout, and Conventional Commits validation are all testable without an editor host. The architecture note calls it "Path B" — consume the stable `vscode.git` API and hand-render everything above it, rather than fork. - **`hyper-git`, again** — five AI seams (`ILlmProvider`, `ICommitMessageProvider`, `IPreCommitInspector`, `IChangelistGrouper`, `IConflictResolver`) are wired in as null implementations, modeled on JetBrains' `CheckinHandler` lifecycle. The interfaces ship; the intelligence is deferred to M5. Declaring the seam early is cheap and declaring it late is not. -- **`coding-proxy`** — the failover chain is policy, not plumbing: circuit breaker state and quota accounting are per-vendor and local, in SQLite-WAL. No Redis, no queue, so a single process is the whole deployment and a restart loses nothing that matters. +- **`coding-proxy`** — the failover chain is policy, not plumbing: circuit breaker state and quota accounting are per-vendor and local, in SQLite-WAL — so a single process is the whole deployment, and a restart loses nothing that matters. - **`negentropy`** — the default path runs on the cheapest of its pluggable backends with **no cloud credentials at all**; if the cheapest configuration is not runnable, nobody runs the expensive one either. Stated as a virtue, this is testability. Stated honestly, it is what a single maintainer has to do to survive his own codebase: nothing here has a second pair of eyes, so the design has to make the mistakes cheap to find. And the null AI seams are still null — the interfaces are a plan, not a feature. @@ -290,7 +290,7 @@ sequenceDiagram P-->>C: SSE stream, in Anthropic's shape ``` -The client is told nothing. That is the whole product: one line of configuration, and the failure mode changes from *stop working* to *work slower on someone else's model*. Nine vendors are wired — Claude plans, GitHub Copilot, Google Antigravity, Z AI's GLM, MiniMax, Qwen, Xiaomi, Kimi, Doubao — with a per-vendor circuit breaker and quota guard, and a local SQLite-WAL dashboard so the burn is visible before the bill is. +The client is told nothing. That is the whole product: one line of configuration, and the failure mode changes from *stop working* to *work slower on someone else's model*. Each of the nine vendors named on the card above gets its own circuit breaker and quota guard, and a local SQLite-WAL dashboard makes the burn visible before the bill is. FastAPI and httpx. 12 releases, the latest still alpha-tagged — translation fidelity across three request shapes is the part that keeps not being finished. Chained failover also means a request can succeed on a model you did not choose; the dashboard exists partly so that is auditable. diff --git a/docs/i18n/zh-CN/README.md b/docs/i18n/zh-CN/README.md index e398b21..7de2289 100644 --- a/docs/i18n/zh-CN/README.md +++ b/docs/i18n/zh-CN/README.md @@ -212,7 +212,7 @@ - **`give-me-a-break`** —— 状态机的 `evaluate` 零时间依赖。时钟由参数传入,于是整套休息/工作/AFK 生命周期都能在虚拟时钟下测试:睡眠、崩溃后快进恢复、休息中途被拔掉的显示器。三个模块,其中一个对 macOS 一无所知。 - **`hyper-git`** —— `engine/` 里没有一处 `vscode` import。仅这一条约束,就是 403 个单元测试之所以存在的原因:变更列表分组、DAG 泳道布局、Conventional Commits 校验,全都不需要编辑器宿主即可测试。架构说明称之为「Path B」——消费稳定的 `vscode.git` API,其上一切手绘,而不去 fork。 - **`hyper-git`,再一次** —— 五个 AI 接缝(`ILlmProvider`、`ICommitMessageProvider`、`IPreCommitInspector`、`IChangelistGrouper`、`IConflictResolver`)以空实现预先接入,形制取自 JetBrains 的 `CheckinHandler` 生命周期。接口先交付,智能延到 M5。早声明接缝很便宜,晚声明就不便宜了。 -- **`coding-proxy`** —— 故障转移链是策略,不是管道:熔断状态与配额记账按厂商分离、且是本地的,落在 SQLite-WAL 里。没有 Redis、没有队列,于是单进程就是整个部署,重启不会丢掉任何要紧的东西。 +- **`coding-proxy`** —— 故障转移链是策略,不是管道:熔断状态与配额记账按厂商分离、且是本地的,落在 SQLite-WAL 里——于是单进程就是整个部署,重启不会丢掉任何要紧的东西。 - **`negentropy`** —— 默认路径跑在可插拔后端中最便宜的那档上,**完全不需要云凭据**;如果最便宜的配置跑不起来,也就没人会去跑贵的那个。 说得好听,这叫可测性。说得诚实,这是一个单人维护者为了在自己的代码库里活下来必须做的事:这里没有第二双眼睛,所以设计必须让错误便宜到能被找出来。而那五个空的 AI 接缝,至今仍然是空的——接口是一份计划,不是一个功能。 @@ -290,7 +290,7 @@ sequenceDiagram P-->>C: SSE 流,仍是 Anthropic 的形状 ``` -客户端什么都不知道。这就是产品的全部:一行配置,把失败模式从「停止工作」改成「用别人的模型慢一点工作」。已接入九家——Claude 套餐、GitHub Copilot、Google Antigravity、Z AI 的 GLM、MiniMax、Qwen、小米、Kimi、豆包——每家独立熔断与配额守卫,另有本地 SQLite-WAL 看板,让消耗在账单之前就可见。 +客户端什么都不知道。这就是产品的全部:一行配置,把失败模式从「停止工作」改成「用别人的模型慢一点工作」。上方卡片点名的九家厂商,每家独立熔断与配额守卫,另有本地 SQLite-WAL 看板,让消耗在账单之前就可见。 FastAPI 与 httpx。12 个 release,最新仍带 alpha 标——三种请求形状之间的转译保真度,正是那个一直没做完的部分。链式转移也意味着请求可能在你没选的模型上成功;看板的存在,一部分就是为了让这件事可审计。 From 327cd59d338fcf131a4d8a23308bf48383f45039 Mon Sep 17 00:00:00 2001 From: ThreeFish Date: Sun, 18 Oct 2026 11:12:52 +0800 Subject: [PATCH 2/8] =?UTF-8?q?docs(agents):=20=E6=96=B0=E5=BB=BA=E7=9F=A5?= =?UTF-8?q?=E8=AF=86=E7=B4=A2=E5=BC=95=E4=B8=8E=20Issue=20=E5=8F=B0?= =?UTF-8?q?=E8=B4=A6=EF=BC=8C=E6=B2=89=E6=B7=80=E5=8F=8C=E8=AF=AD=E9=95=9C?= =?UTF-8?q?=E5=83=8F=E7=BC=96=E8=BE=91=E5=A5=91=E7=BA=A6;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - knowledge-map.md:文档索引 + 双语镜像编辑契约卡(机器领地/标记即契约/锚点三方同名同序/冻结面绕行/编辑后验证/重复收敛原则); - issue.md:登记 I-001 九厂商清单单侧漂移(本次结构性收敛)与 I-002 语义级镜像漂移、锚点死链无机器门(lab gate 护航,上收 tests 为后续路径)。 🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang --- docs/.agents/issue.md | 32 ++++++++++++++++++++++++++++++++ docs/.agents/knowledge-map.md | 29 +++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 docs/.agents/issue.md create mode 100644 docs/.agents/knowledge-map.md diff --git a/docs/.agents/issue.md b/docs/.agents/issue.md new file mode 100644 index 0000000..e0c1098 --- /dev/null +++ b/docs/.agents/issue.md @@ -0,0 +1,32 @@ +# Issue 台账 + +| ID | 标题 | 状态 | 完成时间 | 详情 | +|---|---|---|---|---| +| I-001 | 九厂商清单双层手写漂移:单侧修复未除根,结构性收敛为卡片单一事实源 | ✅ | 2026-10-18 | [详情](#I-001) | +| I-002 | 语义级镜像漂移与锚点死链无机器门:lint 仅护 marker 级 | 🔄 | — | [详情](#I-002) | + + +## I-001:九厂商清单双层手写漂移 + +**问题描述**:coding-proxy 九家厂商清单在项目卡(`README.md:163`)与深潜块(`README.md:293`)两处全文手写,中英共四份拷贝,无同步机制。PR #7 曾发现卡片侧漏写 Xiaomi(8 家对 9 家),修复方式为只补卡片侧数据——漂移根因(双清单结构)未除。 + +**表因根因**:v5 重建时同一事实一次性写入两处;两清单命名形不同(Copilot/GitHub Copilot 等),肉眼 diff 困难;lint 只校验 marker 流,散文重复不在守护范围。 + +**处理方式**(2026-10-18,preening-substrate 结构性熵减):`README.md:163` 定为唯一权威清单(承诺性陈述,加厂商先改这里);`:293` 深潜句收敛为「上方卡片点名的九家厂商」回指,保留每家熔断/配额守卫的增量叙述;中英同步镜像。验证:31 用例 + `--lint` 全绿,残留扫描确认厂商名仅存 :163。 + +**后续防范**:改厂商清单只动 :163;新增手写事实清单时先指定权威位置(编辑契约见 [knowledge-map.md](knowledge-map.md#双语镜像编辑契约卡) 第 7 条)。 + +**同类影响**:其余手写数字面(`403` 三处、`:249` 的 1,378、`:36` 年度序列 prose)已登记为漂移面,按 C4(角色不同)暂保留,未动。 + + +## I-002:语义级镜像漂移与锚点死链无机器门 + +**问题描述**:CI lint 与测试只守护 marker 级契约(75/13 流、parity、assets 闭包);三类承重面无机器守护——① 中英两文件 marker 外文本的语义级镜像漂移;② `` 锚点 / `#user-content-` 导航链接 / FIG key 三方一致性(破坏即静默死链);③ `tests/` 31 用例未接 CI(仅本地跑)。 + +**表因根因**:PR #8 建立 tests 时按最小护栏取舍;锚点前缀是 GitHub 渲染侧行为,仓库内工具不感知。 + +**处理方式**(2026-10-18):本次重构以 lab 级 gate 脚本护航(锚点三方一致 + marker 行号镜像 + 骨架行号镜像 + 行数相等);编辑契约沉淀至 [knowledge-map.md](knowledge-map.md#双语镜像编辑契约卡)。 + +**后续防范 / 根治路径**:将 gate 脚本检查上收为 `tests/test_readme_structure.py`(零依赖纯正则),并在 `refresh-profile-data.yml` lint job 中补跑 `python -m unittest discover tests`——两项均为小改 PR,待单独实施。 + +**注意事项**:本地 Markdown 预览不加 `user-content-` 前缀,导航链接在本地必显死链——这是设计使然,以 GitHub 渲染为准。 diff --git a/docs/.agents/knowledge-map.md b/docs/.agents/knowledge-map.md new file mode 100644 index 0000000..4ac0848 --- /dev/null +++ b/docs/.agents/knowledge-map.md @@ -0,0 +1,29 @@ +# Knowledge Map + +本仓文档索引与跨文档编辑契约的唯一入口。 + +## 文档索引 + +| 文档 | 职责 | +|---|---| +| [`README.md`](../../README.md) | 英文 profile 主页(月度构建产物:13 FIG + 75 DATA 标记) | +| [`docs/i18n/zh-CN/README.md`](../i18n/zh-CN/README.md) | 中文镜像主页(与英文版逐行结构镜像) | +| [`docs/motion-constraints.md`](../motion-constraints.md) | SVG 动效/布局闸门的「为什么」层(闸门机械强制在 `scripts/build_profile_svgs.py`,冲突时以闸门为准) | +| [`docs/.agents/issue.md`](issue.md) | Issue 台账(头部索引 + 详情锚点) | + +## 双语镜像编辑契约卡 + +改任一 README 前必读。两份文件是**逐行结构镜像**:marker 行号、结构骨架行号(details/summary/锚点/表格/代码块)、总行数必须逐位一致;合法差异仅三类——正文语言、img `src` 绝对化(中文版仓库外渲染所需)、语言切换行相对路径。 + +1. **机器领地,永不手改**:`…` 体(img/alt/src 每次刷新从零重建,手改必被覆盖);`值` 的值。生成器为 [`scripts/build_profile_svgs.py`](../../scripts/build_profile_svgs.py)。 +2. **标记即契约**:key 必须 ∈ `FACT_KEYS`/`FIG_SPEC`;两文件 (kind,key) 有序流必须全等且非空(`audit_parity`);增删/换序标记须两文件同步,且计数变化需同步 `tests/test_contract.py` 的 75/13 硬编码断言。 +3. **含 marker 的行谨慎编辑**:值以外的行内文字可改,但 marker 本身与其相对顺序不可动;`DATA:cur_year`/`DATA:cur_total` 是月度刷新「当年数字不回退」守卫的状态源,永不删除。 +4. **锚点三方同名同序**(无机器守卫,纯人工契约):`` ×13、两条簇导航 `` 行的 `#user-content-X` 链接、FIG key `X` 三者集合与顺序一致;GitHub 对手写 `name` 自动加 `user-content-` 前缀,链接侧必须手写该前缀。 +5. **冻结面绕行**:mermaid 块、upstream/census/道法术表格、IEEE 脚注、recompute 命令块承载既有契约,结构性重构一律绕行。 +6. **编辑后验证**(仓库根): + ```bash + python3 -m unittest discover tests # 31 用例(含 Golden Master) + python3 scripts/build_profile_svgs.py --lint # 零网络,同 PR CI lint job + ``` + 另以行号镜像检查护航第 4 条人工契约(marker 行号 diff、骨架行号 diff、行数相等)。 +7. **散文重复收敛原则**:同一事实多处手写 = 漂移风险(先例:九厂商清单曾单侧漏一家,PR #7 只修了数据);收敛时指定唯一权威位置(如承诺性陈述放项目卡),其余降为回指;机器供数(DATA/alt)的重复无漂移风险,不做收敛。 From 0a00b1e6b71d7f92e48131e24845c1ea2313af27 Mon Sep 17 00:00:00 2001 From: ThreeFish Date: Sun, 18 Oct 2026 11:25:59 +0800 Subject: [PATCH 3/8] =?UTF-8?q?test(readme):=20=E9=94=9A=E7=82=B9=E4=B8=89?= =?UTF-8?q?=E6=96=B9=E4=B8=80=E8=87=B4=E4=B8=8E=E5=8F=8C=E8=AF=AD=E8=A1=8C?= =?UTF-8?q?=E7=BA=A7=E9=95=9C=E5=83=8F=E4=B8=8A=E6=94=B6=E4=B8=BA=E7=BB=93?= =?UTF-8?q?=E6=9E=84=E6=B5=8B=E8=AF=95;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 tests/test_readme_structure.py:锚点序 == FIG 簇序、导航链接集 == 锚点集(两份 README 各查)、marker 与结构骨架行号镜像、行数相等、cur_year/cur_total 单调性状态源存续; - 此前三项承重面仅靠人工契约(破坏即 GitHub 静默死链),现并入零依赖特征化套件(31 → 35 用例)。 🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang --- tests/test_readme_structure.py | 69 ++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 tests/test_readme_structure.py diff --git a/tests/test_readme_structure.py b/tests/test_readme_structure.py new file mode 100644 index 0000000..f0323ba --- /dev/null +++ b/tests/test_readme_structure.py @@ -0,0 +1,69 @@ +"""Machine guards for the README contracts that --lint cannot see (Section B2). + +The marker stream, its parity and the assets closure are audited by +scripts/build_profile_svgs.py --lint on every PR. Three load-bearing surfaces +used to rest on human discipline only; these tests lock them: + +1. Anchor triple-consistency — every anchor, every + #user-content-X link in the two cluster-nav rows, and every FIG key + must be the same set, anchors in FIG-cluster order. A broken link here + fails silently on GitHub (the user-content- prefix is renderer-side). +2. Bilingual line-mirror — the two READMEs must carry their markers and their + structural skeleton (details/summary/anchors/tables/code fences) at + identical line numbers, and stay the same length. Prose may differ; the + shape may not. +3. Monotonicity state source — DATA:cur_year/DATA:cur_total must survive in + both files: the monthly refresh reads them back from disk as its only + state (see main() in the generator). +""" +import re +import unittest + +from tests._bps import ROOT + +EN, ZH = "README.md", "docs/i18n/zh-CN/README.md" + +MARKER = re.compile(r"") +FIG_OPEN = re.compile(r"") +ANCHOR = re.compile(r'') +NAV = re.compile(r"#user-content-([a-z]+)") +SKELETON = re.compile( + r"\d{4}") + self.assertRegex(text, r"[\d,]+") + + +if __name__ == "__main__": + unittest.main() From 499022ad3224d216a19c2ead4a7072e0e722852e Mon Sep 17 00:00:00 2001 From: ThreeFish Date: Sun, 18 Oct 2026 11:26:22 +0800 Subject: [PATCH 4/8] =?UTF-8?q?ci(lint):=20PR=20lint=20job=20=E6=8E=A5?= =?UTF-8?q?=E5=85=A5=E5=85=A8=E5=A5=97=20unittest=20=E6=8A=A4=E6=A0=8F;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - refresh-profile-data.yml 的 lint job 新增静态步骤 python -m unittest discover tests; - 35 用例(Golden Master、结构守卫、SVG 闸门金样)由本地自觉变 PR 强制门,零网络、亚秒级。 🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang --- .github/workflows/refresh-profile-data.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/refresh-profile-data.yml b/.github/workflows/refresh-profile-data.yml index 7473236..61c8cdc 100644 --- a/.github/workflows/refresh-profile-data.yml +++ b/.github/workflows/refresh-profile-data.yml @@ -31,6 +31,12 @@ jobs: - name: Marker and parity lint run: python scripts/build_profile_svgs.py --lint + # The characterization suite is zero-dependency and sub-second: make the + # contract tests, README structure guards and SVG golden masters as + # mandatory as the lint instead of local-only. + - name: Contract and structure tests + run: python -m unittest discover tests + refresh: if: github.event_name != 'pull_request' runs-on: ubuntu-latest From 3808105d73444772969ae03d449917254e1dc3e8 Mon Sep 17 00:00:00 2001 From: ThreeFish Date: Sun, 18 Oct 2026 11:26:22 +0800 Subject: [PATCH 5/8] =?UTF-8?q?refactor(pipeline):=20cadence=5Falt=20?= =?UTF-8?q?=E7=A7=BB=E5=87=BA=20refresh=20=E8=87=B3=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=E7=BA=A7=EF=BC=8C=E4=B8=8E=E5=85=B6=E4=BD=99=20alt=20=E5=AF=B9?= =?UTF-8?q?=E9=BD=90;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 原嵌套于 refresh() 内(唯一非模块级的 *_alt),闭包变量 rel_total 改为显式参数穿入; - 函数体除缩进与签名外逐 token 不变(独立 Verifier 经 AST 比对确认),EN/ZH 合成输入行为冒烟一致; - 附带收益:tests/_bps.py 按名加载器现可直接加载 cadence_alt,为后续可测铺路。 🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang --- scripts/build_profile_svgs.py | 73 ++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/scripts/build_profile_svgs.py b/scripts/build_profile_svgs.py index 3a534a8..81da44f 100644 --- a/scripts/build_profile_svgs.py +++ b/scripts/build_profile_svgs.py @@ -1655,6 +1655,41 @@ def upstream_alt(f, items, pub_prs): ledger, format(pub_prs, ","), len(rows) / pub_prs * 100)) +def cadence_alt(f, rel_lists, domain, trunk_commits, rel_total): + lanes = sorted(((n, sorted(v, key=lambda r: r["published_at"])) + for n, v in rel_lists.items() if v), + key=lambda kv: (-len(kv[1]), kv[0])) + # The trunk sentence carries two numbers that MOVE — negentropy is the + # active repo, so a literal here would have the alt contradict the + # neg_commits marker rendered beside it within a month. + trunk_rels = len(rel_lists.get(TRUNK, ())) + if f == EN: + rows = "; ".join( + "%s: %d releases, %s on %s through %s on %s%s" % ( + n, len(v), v[0]["tag_name"], v[0]["published_at"][:10], + v[-1]["tag_name"], v[-1]["published_at"][:10], + "" if not all(r["prerelease"] for r in v) else ", all pre-releases") + for n, v in lanes) + return ("Dot timeline of %d public releases across %d repositories on one shared " + "date axis, %s to %s. %s. Hollow dots are pre-releases. %s shows only its " + "%d release candidates against %s commits because it is a deployed " + "service, not a distributed package — its shipping unit is the merged " + "pull request, not the tag. Data: GitHub." + % (rel_total, len(lanes), domain[0], domain[1], rows, + TRUNK, trunk_rels, format(trunk_commits, ","))) + rows = ";".join( + "%s %d 个 release,%s(%s)至 %s(%s)%s" % ( + n, len(v), v[0]["tag_name"], v[0]["published_at"][:10], + v[-1]["tag_name"], v[-1]["published_at"][:10], + "" if not all(r["prerelease"] for r in v) else ",全部为预发布") + for n, v in lanes) + return ("各仓库公开 release 的点式时间线(共用日期轴,%s 至 %s)。%s。空心点为预发布。" + "%s 在 %s 条提交面前只有 %d 个 rc,因为它是部署型服务而非分发包——" + "它的交付单元是已合并 PR,不是 tag。数据:GitHub。" + % (domain[0], domain[1], rows, + TRUNK, format(trunk_commits, ","), trunk_rels)) + + LAT_EDGES = [1, 2, 5, 15, 60, 240, 1440, float("inf")] LAT_LABELS = ["<1m", "1-2", "2-5", "5-15", "15-60m", "1-4h", "4-24h", ">24h"] @@ -1862,41 +1897,6 @@ def windowed_run(dom): die(f"release roster {sorted(rel_counts)} != source roster " f"{sorted(repo_commits)} — a repo's releases would render as 0, refusing") - def cadence_alt(f, rel_lists, domain, trunk_commits): - lanes = sorted(((n, sorted(v, key=lambda r: r["published_at"])) - for n, v in rel_lists.items() if v), - key=lambda kv: (-len(kv[1]), kv[0])) - # The trunk sentence carries two numbers that MOVE — negentropy is the - # active repo, so a literal here would have the alt contradict the - # neg_commits marker rendered beside it within a month. - trunk_rels = len(rel_lists.get(TRUNK, ())) - if f == EN: - rows = "; ".join( - "%s: %d releases, %s on %s through %s on %s%s" % ( - n, len(v), v[0]["tag_name"], v[0]["published_at"][:10], - v[-1]["tag_name"], v[-1]["published_at"][:10], - "" if not all(r["prerelease"] for r in v) else ", all pre-releases") - for n, v in lanes) - return ("Dot timeline of %d public releases across %d repositories on one shared " - "date axis, %s to %s. %s. Hollow dots are pre-releases. %s shows only its " - "%d release candidates against %s commits because it is a deployed " - "service, not a distributed package — its shipping unit is the merged " - "pull request, not the tag. Data: GitHub." - % (rel_total, len(lanes), domain[0], domain[1], rows, - TRUNK, trunk_rels, format(trunk_commits, ","))) - rows = ";".join( - "%s %d 个 release,%s(%s)至 %s(%s)%s" % ( - n, len(v), v[0]["tag_name"], v[0]["published_at"][:10], - v[-1]["tag_name"], v[-1]["published_at"][:10], - "" if not all(r["prerelease"] for r in v) else ",全部为预发布") - for n, v in lanes) - return ("各仓库公开 release 的点式时间线(共用日期轴,%s 至 %s)。%s。空心点为预发布。" - "%s 在 %s 条提交面前只有 %d 个 rc,因为它是部署型服务而非分发包——" - "它的交付单元是已合并 PR,不是 tag。数据:GitHub。" - % (domain[0], domain[1], rows, - TRUNK, format(trunk_commits, ","), trunk_rels)) - - # ------------------------------------------------- figure derivations ---- # Degenerate-but-reachable shapes die cleanly here instead of raising a bare # traceback further down; the write-nothing contract holds either way. @@ -2078,7 +2078,8 @@ def ecdf_points(): "accrual": {f: accrual_alt(f, monthly, DOMAIN, grad_events, commits_total) for f in README_FILES}, "lifecycles": {f: lifecycles_alt(f, spans, DOMAIN) for f in README_FILES}, - "cadence": {f: cadence_alt(f, rel_lists, DOMAIN, len(repo_commits.get(TRUNK, ()))) + "cadence": {f: cadence_alt(f, rel_lists, DOMAIN, + len(repo_commits.get(TRUNK, ())), rel_total) for f in README_FILES}, "streak": {f: streak_alt(f, rug_act, RUG_DAYS - rug_act, rug_run, rug_dom, RUG_DAYS) for f in README_FILES}, From 06b8f2539fb03a2483cb5a1148293ed1318b0952 Mon Sep 17 00:00:00 2001 From: ThreeFish Date: Sun, 18 Oct 2026 11:26:22 +0800 Subject: [PATCH 6/8] =?UTF-8?q?docs(agents):=20=E5=A5=91=E7=BA=A6=E5=8D=A1?= =?UTF-8?q?=E4=B8=8E=20Issue=20=E5=8F=B0=E8=B4=A6=E7=8E=B0=E8=A1=8C?= =?UTF-8?q?=E6=80=81=E5=90=8C=E6=AD=A5;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - knowledge-map:锚点三方契约标注机器强制、编辑后验证命令更新为 35 用例双命令(与 CI 同款); - issue:I-002 根治闭环(结构测试上收 + CI 接入),状态置已完成。 🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang --- docs/.agents/issue.md | 6 +++--- docs/.agents/knowledge-map.md | 9 ++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/docs/.agents/issue.md b/docs/.agents/issue.md index e0c1098..635873c 100644 --- a/docs/.agents/issue.md +++ b/docs/.agents/issue.md @@ -3,7 +3,7 @@ | ID | 标题 | 状态 | 完成时间 | 详情 | |---|---|---|---|---| | I-001 | 九厂商清单双层手写漂移:单侧修复未除根,结构性收敛为卡片单一事实源 | ✅ | 2026-10-18 | [详情](#I-001) | -| I-002 | 语义级镜像漂移与锚点死链无机器门:lint 仅护 marker 级 | 🔄 | — | [详情](#I-002) | +| I-002 | 语义级镜像漂移与锚点死链无机器门:lint 仅护 marker 级 | ✅ | 2026-10-18 | [详情](#I-002) | ## I-001:九厂商清单双层手写漂移 @@ -25,8 +25,8 @@ **表因根因**:PR #8 建立 tests 时按最小护栏取舍;锚点前缀是 GitHub 渲染侧行为,仓库内工具不感知。 -**处理方式**(2026-10-18):本次重构以 lab 级 gate 脚本护航(锚点三方一致 + marker 行号镜像 + 骨架行号镜像 + 行数相等);编辑契约沉淀至 [knowledge-map.md](knowledge-map.md#双语镜像编辑契约卡)。 +**处理方式**(2026-10-18,两步闭环):第一步重构时以 lab 级 gate 脚本护航(锚点三方一致 + marker 行号镜像 + 骨架行号镜像 + 行数相等),编辑契约沉淀至 [knowledge-map.md](knowledge-map.md#双语镜像编辑契约卡);第二步将检查上收为 [`tests/test_readme_structure.py`](../../tests/test_readme_structure.py)(零依赖纯正则,35 用例之一),并在 `refresh-profile-data.yml` lint job 中接入 `python -m unittest discover tests`,全套护栏由本地自觉变 PR 强制门。 -**后续防范 / 根治路径**:将 gate 脚本检查上收为 `tests/test_readme_structure.py`(零依赖纯正则),并在 `refresh-profile-data.yml` lint job 中补跑 `python -m unittest discover tests`——两项均为小改 PR,待单独实施。 +**后续防范**:改任一 README 后跑 knowledge-map 契约卡第 6 条两条命令(与 CI 同款);新增结构元素(details/锚点/表格)时行级镜像约束由测试自动拦截。 **注意事项**:本地 Markdown 预览不加 `user-content-` 前缀,导航链接在本地必显死链——这是设计使然,以 GitHub 渲染为准。 diff --git a/docs/.agents/knowledge-map.md b/docs/.agents/knowledge-map.md index 4ac0848..bdf2ad0 100644 --- a/docs/.agents/knowledge-map.md +++ b/docs/.agents/knowledge-map.md @@ -18,12 +18,11 @@ 1. **机器领地,永不手改**:`…` 体(img/alt/src 每次刷新从零重建,手改必被覆盖);`值` 的值。生成器为 [`scripts/build_profile_svgs.py`](../../scripts/build_profile_svgs.py)。 2. **标记即契约**:key 必须 ∈ `FACT_KEYS`/`FIG_SPEC`;两文件 (kind,key) 有序流必须全等且非空(`audit_parity`);增删/换序标记须两文件同步,且计数变化需同步 `tests/test_contract.py` 的 75/13 硬编码断言。 3. **含 marker 的行谨慎编辑**:值以外的行内文字可改,但 marker 本身与其相对顺序不可动;`DATA:cur_year`/`DATA:cur_total` 是月度刷新「当年数字不回退」守卫的状态源,永不删除。 -4. **锚点三方同名同序**(无机器守卫,纯人工契约):`` ×13、两条簇导航 `` 行的 `#user-content-X` 链接、FIG key `X` 三者集合与顺序一致;GitHub 对手写 `name` 自动加 `user-content-` 前缀,链接侧必须手写该前缀。 +4. **锚点三方同名同序**:`` ×13、两条簇导航 `` 行的 `#user-content-X` 链接、FIG key `X` 三者集合与顺序一致(`tests/test_readme_structure.py` 机器强制);GitHub 对手写 `name` 自动加 `user-content-` 前缀,链接侧必须手写该前缀。 5. **冻结面绕行**:mermaid 块、upstream/census/道法术表格、IEEE 脚注、recompute 命令块承载既有契约,结构性重构一律绕行。 -6. **编辑后验证**(仓库根): +6. **编辑后验证**(仓库根,两命令即 PR CI lint job 全部门禁): ```bash - python3 -m unittest discover tests # 31 用例(含 Golden Master) - python3 scripts/build_profile_svgs.py --lint # 零网络,同 PR CI lint job + python3 -m unittest discover tests # 35 用例:Golden Master + 锚点三方一致 + 双文件行级镜像 + 单调性状态源 + python3 scripts/build_profile_svgs.py --lint # 零网络,marker 流与 assets 闭包审计 ``` - 另以行号镜像检查护航第 4 条人工契约(marker 行号 diff、骨架行号 diff、行数相等)。 7. **散文重复收敛原则**:同一事实多处手写 = 漂移风险(先例:九厂商清单曾单侧漏一家,PR #7 只修了数据);收敛时指定唯一权威位置(如承诺性陈述放项目卡),其余降为回指;机器供数(DATA/alt)的重复无漂移风险,不做收敛。 From d920e9cb58aa5d8aee8e472422012eb2652ccccf Mon Sep 17 00:00:00 2001 From: ThreeFish Date: Sun, 18 Oct 2026 13:34:48 +0800 Subject: [PATCH 7/8] =?UTF-8?q?test(readme):=20=E5=88=A0=E9=99=A4=E8=87=86?= =?UTF-8?q?=E9=80=A0=E5=88=86=E5=8C=BA=E5=8F=B7=E5=B9=B6=E5=BC=BA=E5=8C=96?= =?UTF-8?q?=E5=AF=BC=E8=88=AA=E9=93=BE=E6=8E=A5=E9=A1=BA=E5=BA=8F=E6=96=AD?= =?UTF-8?q?=E8=A8=80;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - docstring 去掉「Section B2」——全仓仅存在 Section A/C/C/D/A/C/E 的非正式引用,B/B2 无出处; - 簇导航链接断言由 sorted 集合比较强化为「文档序 == FIG 簇序」,与 knowledge-map 契约卡第 4 条「集合与顺序一致」宣称同口径;变异自证换序可判红。 🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang --- tests/test_readme_structure.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/test_readme_structure.py b/tests/test_readme_structure.py index f0323ba..ea4fbcb 100644 --- a/tests/test_readme_structure.py +++ b/tests/test_readme_structure.py @@ -1,4 +1,4 @@ -"""Machine guards for the README contracts that --lint cannot see (Section B2). +"""Machine guards for the README contracts that --lint cannot see. The marker stream, its parity and the assets closure are audited by scripts/build_profile_svgs.py --lint on every PR. Three load-bearing surfaces @@ -6,8 +6,9 @@ 1. Anchor triple-consistency — every anchor, every #user-content-X link in the two cluster-nav rows, and every FIG key - must be the same set, anchors in FIG-cluster order. A broken link here - fails silently on GitHub (the user-content- prefix is renderer-side). + must be the same set in the same order (nav links read across the two + rows follow the FIG cluster order). A broken link here fails silently on + GitHub (the user-content- prefix is renderer-side). 2. Bilingual line-mirror — the two READMEs must carry their markers and their structural skeleton (details/summary/anchors/tables/code fences) at identical line numbers, and stay the same length. Prose may differ; the @@ -36,14 +37,14 @@ def _lines(rel): class TestAnchorTripleConsistency(unittest.TestCase): - def test_anchors_fig_keys_and_nav_links_are_one_set_per_file(self): + def test_anchors_fig_keys_and_nav_links_match_in_order_per_file(self): for rel in (EN, ZH): lines = _lines(rel) figs = [m.group(1) for l in lines for m in FIG_OPEN.finditer(l)] anchors = [m.group(1) for l in lines for m in ANCHOR.finditer(l)] - navs = sorted(m.group(1) for l in lines for m in NAV.finditer(l)) + navs = [m.group(1) for l in lines for m in NAV.finditer(l)] self.assertEqual(figs, anchors, f"{rel}: anchor order != FIG order") - self.assertEqual(sorted(anchors), navs, f"{rel}: nav links != anchors") + self.assertEqual(figs, navs, f"{rel}: nav link order != FIG order") class TestBilingualLineMirror(unittest.TestCase): From 569bace506f47aec9b6c53c224854a86b9f5c1b3 Mon Sep 17 00:00:00 2001 From: ThreeFish Date: Sun, 18 Oct 2026 13:34:48 +0800 Subject: [PATCH 8/8] =?UTF-8?q?ci(lint):=20paths=20=E5=A2=9E=E8=A1=A5=20te?= =?UTF-8?q?sts/**=EF=BC=8C=E6=B6=88=E9=99=A4=E7=BA=AF=E6=B5=8B=E8=AF=95=20?= =?UTF-8?q?PR=20=E7=9A=84=E9=97=A8=E7=A6=81=E7=9B=B2=E5=8C=BA;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 此前仅改 tests/ 的 PR 会整体跳过 lint job,新接入的 unittest 步骤对其不生效,与 issue.md I-002「全套护栏变 PR 强制门」宣称相悖; - 坏测试可无 CI 合入的缺口闭合。 🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist) Co-Authored-By: Aurelius Huang --- .github/workflows/refresh-profile-data.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/refresh-profile-data.yml b/.github/workflows/refresh-profile-data.yml index 61c8cdc..f10d96e 100644 --- a/.github/workflows/refresh-profile-data.yml +++ b/.github/workflows/refresh-profile-data.yml @@ -9,6 +9,7 @@ on: - "docs/i18n/zh-CN/README.md" - "scripts/build_profile_svgs.py" - "assets/**" + - "tests/**" workflow_dispatch: permissions: