Skip to content

Commit 48e6651

Browse files
tzhouamclaude
andcommitted
Let L1 accept new-directory indexes in bootstrap mode, and check index links
kb init (design v3 §9.2/§9.3) must create repos/<repo>/_index.md and components/<group>/_index.md, which check_changeset refuses outright ("index files are never created or deleted by a change set"). check_changeset gains a keyword `bootstrap` (default False, behaviour unchanged). When set it relaxes exactly two rules: - an _index.md may be created in a directory that had no files at base; it must link every page and child-directory index in its directory, and an existing parent index must link it. Creating an index in an existing directory and deleting any index stay refused. - the shared knowledge/repos/_index.md may be modified (listing a new repository); adding or deleting it stays refused. check_index_links(base, head) is the init-side check for index edits that L1 only classifies as prose (tables, cross-directory links): links a change adds must resolve inside the knowledge tree, a changed index keeps its base links, and every new page or child index is linked from its parent index. A test pins that only kb_service/init_stages.py (kb init, a later PR) may pass bootstrap=True. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 507deed commit 48e6651

4 files changed

Lines changed: 595 additions & 9 deletions

File tree

‎doc/architecture/SPEC/knowledge_service.md‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# knowledge_service/ — provider curation components
22

3-
<!-- verified-against: 2026-09-29 -->
3+
<!-- verified-against: 2026-09-30 -->
44

55
The provider owns knowledge curation beneath the public SDK v1 facade.
66
`KnowledgeCurator` composes four domain components over one explicit work
@@ -48,6 +48,11 @@ library only.
4848
## 2026-09-28 T1 索引修复
4949
L1 的索引检查允许为目录中已存在但未列入索引的页面补链接(巡检 T1 修复),新页面仍必须被链接。
5050

51+
## 2026-09-30 kb init 的 L1 bootstrap 模式
52+
`l1.check_changeset(..., bootstrap=)` 只供 `kb init`(`kb_service/init_stages.py`):允许在新目录新建
53+
`_index.md`、修改共享的 `repos/_index.md`;`l1.check_index_links(base, head)` 检查 init 改动的索引链接。
54+
细节见 [l1](knowledge_service/l1.md)。服务门禁与发布器从不传 `bootstrap`。
55+
5156
## 2026-09-28 知识验证器(v8:发布器本地门禁)
5257
`gate_verifier.verify_change(ctx, pr=, head_sha=, pre=, post=, final=, effective_base=, verdict=)` 是发布器本地门禁
5358
(`kb_service.local_gate`)在合并前与合并后运行的检查;v7 的仓库端 `kb-gate` 工作流、`.github/kb-gate/` 验证包、

‎doc/architecture/SPEC/knowledge_service/l1.md‎

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# knowledge_service/l1.py —— 规范
22

3-
<!-- verified-against: 2026-09-29 -->
3+
<!-- verified-against: 2026-09-30 -->
44

5-
`LOC ~420 · 知识质量门的确定性一层(L1) · refactor-status: stable`
5+
`LOC ~600 · 知识质量门的确定性一层(L1) · refactor-status: stable`
66

77
## 职责
88
- `check_tree(files)`:尾注合法、supersede 双向一致、tombstone ID 未被复用、
@@ -24,11 +24,39 @@
2424
同目录 `_index.md` 出现。
2525
- purge 时序:tombstone 的 `purged_at` 不得等于该规则的 `retired_at`;传入可信的
2626
`release` 时 `purged_at` 必须等于它。
27+
- `check_changeset(..., bootstrap=)`:仅供 `kb init`(唯一允许的调用方是
28+
`kb_service/init_stages.py`,测试扫描源码钉住)。只放宽两条:
29+
- 新目录(base 中该目录下没有任何文件)可以**新建** `_index.md`,产出一个 prose 块;新索引必须
30+
链接本目录的每个页面和每个子目录的 `_index.md`,已存在的父目录索引必须链接它
31+
(父索引也是本次新建时由父索引自己报告)。在已有目录新建索引、删除索引仍然拒绝。
32+
- 共享的 `knowledge/repos/_index.md` 可以被**修改**(登记新仓库),新增/删除仍拒绝。
33+
其余规则(尾注、frontmatter、`sources`、白名单其余部分、保护规则)不变;默认 `False`
34+
时行为与原来逐字节一致。
35+
- `check_index_links(base, head)`:init 侧的索引链接检查(索引改成表格或跨目录链接时
36+
L1 只把它当 prose 块)。对每个新增或改动的 `_index.md`:本次新增的相对链接必须解析到
37+
head 中的文件或目录、不得逃出知识树(issue `index_link_broken` / `index_link_escapes`;
38+
URL、纯锚点不算链接,base 已有的链接不重新判定——有些指向 `doc/`);链接识别行内链接
39+
(可带 `<尖括号>` 目标与 `"标题"`/`'标题'`/`(标题)`)和引用式链接(定义 `[r]: target` 只在被 `[文本][r]`、`[r][]`、`[r]` 实际使用时才算链接,
40+
标签不区分大小写),其余无法解析
41+
的 `](` 一律报 `index_link_unparsed`,不静默跳过;改动的索引不得丢掉
42+
base 的链接(`index_link_dropped`);head 中每个新页面、新子目录索引都必须被父索引链接
43+
(`index_unlinked`,知识树根没有索引)。
44+
- 代码处理按方向 fail-closed,不实现 Markdown 解析器:解析/逃逸/无法解析检查看**所有**像链接的
45+
文本(藏在代码里的也查);“是否链接了新页面”“是否保留了原链接”只认**确定可见**的链接——它之前
46+
(含本行)没有任何类围栏行(容器前缀后的 ```` ``` ```` / `~~~`),且在所在块(段落、列表项、标题、
47+
引用,或真表格——空行后开始、第二行是分隔行——正文行的单元格,代码段跨不过单元格)内它之前没有
48+
反引号。引用式链接:解析检查查该标签的**每一个**定义(哪个生效取决于哪个在代码里);导航只认只有
49+
一个定义且该定义确定可见的标签。“保留”也 fail-closed:base 的链接只有在 head 中确定可见,或它所在的
50+
每个块在 head 中原样存在、且该块之前的类围栏行也相同时,才算保留;否则报 `index_link_dropped`(把链接挪进代码 =
51+
丢链接)。
52+
在真实知识树的 142 个索引上逐一追加一行,无误报。
2753

2854
## 不变量
2955
纯函数;标准库 + PyYAML + `lifecycle`/`ops`,验证包原样携带。段比较忽略尾部空行
3056
(追加段落时前一段多出的分隔空行不算改动)。
3157

3258
## 测试
59+
`test_kb_init_l1.py`(bootstrap 新目录索引、父子链接、已有目录仍拒绝、删除拒绝、`repos/_index.md`
60+
只允许修改、链接检查各类 issue、仅 `init_stages.py` 可传 `bootstrap=True`);
3361
`test_knowledge_ops_l1.py`(伪造的 sources/frontmatter/删除 active 规则/重复 ID、白名单与
3462
模式、prose 分块、外部引用、真实知识树上执行各类操作后两个既有校验器均通过)。

0 commit comments

Comments
 (0)