Skip to content

Commit cc9f903

Browse files
committed
Add resumable feature knowledge deepening with independent depth metrics
1 parent 6779a53 commit cc9f903

13 files changed

Lines changed: 1236 additions & 25 deletions

File tree

‎doc/architecture/SPEC/engine/steps/knowledge.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,7 @@ PR,且只在 `ALLOW_PUSH=1` 与 `ALLOW_POST=1` 同时成立、非 dry run、
2929

3030
`pr-history` 阶段另接收可选 `pr_count` 与 `budget_usd`,转成整数/浮点后传入 `run_stage`;非法值返回 BLOCKED。
3131
历史 PR 的完整选择、逐 PR checkpoint、commit 串和 Codex 审阅均由 `kb_service.init_history` 负责。
32+
33+
`knowledge-deepen` 另接收 `budget_usd` 与 `retry_unfinished`,逐功能保存七维实现知识、
34+
累计预算与草稿。`from_existing` 允许 knowledge/knowledge-deepen 从已合并 KB 开始。
35+
`kb widen` / `kb deepen` 经同一 playbook/step 指定这两个知识阶段,旧规则 deepen 保持原契约。

‎doc/architecture/SPEC/kb_service.md‎

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,7 @@ architecture 页并更新最近索引,已有正文保留。阶段不切换生
487487
旧路由未覆盖的文件可由清单的显式 feature owner 接管;只有唯一 owner 才补齐本次提炼输入,
488488
冲突或没有归属的文件继续单列为 unrouted,不改写持久路由。
489489

490-
`--from-existing` 只适用于 knowledge:没有本地 skeleton/modules record 时,显式从已合并的仓库
490+
`--from-existing` 适用于 knowledge 与 knowledge-deepen:没有本地 skeleton/modules record 时,显式从已合并的仓库
491491
索引和 owner 路由开始增补;每个路由页须存在且属于本仓库。已有 record 的 review/merge 门禁保持生效。
492492
不创建或伪造前置阶段记录,输入摘要绑定该模式和 main 的固定 SHA。
493493

@@ -516,6 +516,35 @@ token、served model 和调用结果照常记录,judge 的固定记账与预
516516
可独立复核;上游必须是干净的固定 HEAD。`--write-contracts` 只追加缺少的结构性记录,
517517
保留过期记录供人工刷新;`--report` 把逐功能/逐文件结果写入 eval 或本地临时文件。
518518

519+
## kb widen / kb deepen:功能广度与实现深度
520+
521+
`kb widen REPO` 经同一 playbook 指定 `knowledge --from-existing`;`kb deepen REPO`
522+
指定 `knowledge-deepen --from-existing`。支持 `--dry-run`、`--pin`、`--subscription-generator`。
523+
旧 `--stage deepen` 继续提炼规则和处理 shadow 开关;新知识深读不生成规则、不修改生命周期或旧阶段链。
524+
525+
knowledge-deepen 需要显式 feature/production coverage policy,逐项访问全部功能,包含已有规则的 owner。
526+
每项提炼 flow、api、configuration、dependencies、failure_modes、tradeoffs、validation 七维,
527+
只保存有证据的内容到最近 owner 的 `feature-depth-<id>.md`,链接功能概览与 owner 索引。
528+
源码按定义切片,可检索文件前缀之外的实现,并补充可静态解析的第一方被调函数与相关测试。
529+
flow 至少包含两个不同定义的直接调用;Python 校验限定符号、词法 owner 和导入目标,其它
530+
语言检查去除注释/字符串后的声明和调用。动态对象分派不能靠同名猜测,语义仍由模型裁判复核。
531+
532+
每维用 `kb:depth` 绑定 feature、facet、完整 pin 与正文哈希,`kb:depth-proof` 绑定精确证据
533+
区间及其哈希、flow trace。区间必须完整展示给生成器,不允许跨缺口。页面必须是无规则的
534+
architecture/guide;整页 advisory pass 后才写入,拒绝或证据不足的草稿保留在本地 checkpoint/trace。
535+
来源引用、符号、L1 与知识树校验仍需通过。
536+
537+
`coverage.semantic_depth` 单列完整功能数、七维槽位数和有语义证据的生产文件;
538+
`coverage.breadth` 保留原功能/文件指标。静态接口卡、旧 owner/facet 标记、规则和路由不能
539+
增加新深度。七维齐全只说明各有代表性实现知识,不声称全行为或执行测试覆盖。
540+
`tools/audit_knowledge_depth.py` 在干净的固定上游 HEAD 上独立重算两组指标。
541+
542+
先遍历全部功能,再修复缺口,每项每批最多两次尝试。逐项保存预算预留、生成草稿、裁判
543+
结果与已接受正文;中断裁判可复用完成的生成。恢复固定 KB baseline 与 upstream pin,
544+
输入变化则拒绝串用。`--budget-usd N` 可提高同批累计 ceiling;`--retry-unfinished` 显式
545+
重试缺口并保留花费。已发布批次不再修改,合并后用新 state directory。missing facets
546+
保持明确;订阅生成器 USD 为 unreported,judge 固定记账不等于账单实付。
547+
519548
## 2026-09-30 kb init:校准集收割(harvest-calibration)
520549
- 各阶段的 `InitRecord.verdicts[rule_id]` 除 verdict/reasons/model/text_sha/page 外还保存**判定时的规则全文**
521550
(`section`)与钉点证据(`evidence`),被判 fail 剥离或被 owner 删除的规则也能复原成用例;缺这两项的旧记录使收割

‎doc/knowledge/SCHEMA.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ validation 六个维度。它生成的非规则段使用 `kb:knowledge` HTML 注
3535
不产生规则,也不承诺整文件行为或测试覆盖。功能页和源码记录按最近代码 owner 组织;
3636
达标报告属于 `eval/`,不能作为产品知识正文保存或通过新增索引增加覆盖率。
3737

38+
`kb deepen`(`knowledge-deepen`)的 `kb:depth` 标记另绑定 feature、七维 facet、完整 pin
39+
与正文哈希,`kb:depth-proof` 保存精确证据区间及其内容哈希、调用 trace。只用于复核代表性
40+
实现知识;旧标记、静态接口卡、规则和索引不计入此深度。正文或证据改变、pin 不符或重复
41+
facet 均失效。页面仍使用既有 architecture/guide 类型,设计推断与未验证测试明确标出。
42+
3843
`check_wiki_lint.py` 强制的只有前五项(`title`、`created`、`updated`、`type`、
3944
非空 `tags`);其余为约定字段,写了就必须合法(`confidence` 只能取三值)。
4045

‎playbooks/kb-init.yaml‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@ repos: []
1313
requires: []
1414
params:
1515
repo: "knowledge repository name"
16-
stage: "skeleton | modules | knowledge | deepen | pr-history | harvest-calibration"
16+
stage: "skeleton | modules | knowledge | deepen | pr-history | harvest-calibration | knowledge-deepen (independent)"
1717
dry_run: "true (default): write the tree and PR body locally; false needs ALLOW_PUSH=1 and ALLOW_POST=1"
1818
pin: "upstream commit to pin (default: the default branch head)"
1919
pr_count: "pr-history only: merged upstream PRs to replay (default: adapter pr_history_count or 1000)"
20-
budget_usd: "pr-history only: cumulative spend ceiling; increasing it resumes the same window"
21-
from_existing: "knowledge only: explicitly enrich a merged index and owner routes without local earlier-stage records"
20+
budget_usd: "pr-history/depth: cumulative spend ceiling; increasing it resumes the same pinned batch"
21+
from_existing: "explanatory knowledge: enrich a merged index and owner routes without local earlier-stage records"
22+
retry_unfinished: "knowledge-deepen only: retry unsupported facets while retaining accepted work and cumulative spend"
2223
subscription_generator: "explicit subscription backend; generator USD unreported, fees outside stage USD accounting"
2324
steps:
2425
- {id: init, step: knowledge.init}

‎src/infermatrix_copilot/engine/steps/knowledge.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ async def init_stage(ctx: StepContext) -> StepResult:
182182
ceiling = ctx.params.get("budget_usd")
183183
if ceiling not in (None, ""):
184184
kwargs["budget_usd"] = float(ceiling)
185-
for option in ("from_existing", "subscription_generator"):
185+
for option in ("from_existing", "subscription_generator", "retry_unfinished"):
186186
if str(ctx.params.get(option, "false")).lower() in ("1", "true", "yes"):
187187
kwargs[option] = True
188188
record = run_stage(rt, lifecycle, stage, dry_run=dry_run, pin=pin, **kwargs)

‎src/infermatrix_copilot/kb_service/cli.py‎

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
knowledge, deepen, pr-history, harvest-calibration);
2121
never touches kb.db
2222
kb init REPO --suggest-seeds rank existing knowledge pages worth seeding from (no model call)
23+
kb widen REPO [--dry-run] enrich existing feature and file knowledge
24+
kb deepen REPO [--dry-run] deepen implementation knowledge per feature
2325
kb publish (--remote HOST:/STATE_DIR | --local DIR) [--once]
2426
the publisher (GPU box, owner's gh login): perform
2527
the signed outbox items; writes need ALLOW_POST=1
@@ -135,12 +137,17 @@ def _init_command(args, state_dir: Path) -> int:
135137

136138
params = {"stage": args.stage, "dry_run": "true" if args.dry_run else "false", "pin": args.pin or ""}
137139
if args.from_existing:
138-
if args.stage != "knowledge":
139-
print("--from-existing is for --stage knowledge only", file=sys.stderr)
140+
if args.stage not in ("knowledge", "knowledge-deepen"):
141+
print("--from-existing is for --stage knowledge or knowledge-deepen only", file=sys.stderr)
140142
return 2
141143
params["from_existing"] = "true"
142144
if args.subscription_generator:
143145
params["subscription_generator"] = "true"
146+
if args.retry_unfinished:
147+
if args.stage != "knowledge-deepen":
148+
print("--retry-unfinished is for knowledge-deepen only", file=sys.stderr)
149+
return 2
150+
params["retry_unfinished"] = "true"
144151
if args.pr_count is not None:
145152
if args.stage != "pr-history" or args.pr_count < 1:
146153
print("--pr-count is a positive integer for --stage pr-history only", file=sys.stderr)
@@ -149,8 +156,8 @@ def _init_command(args, state_dir: Path) -> int:
149156
if args.budget_usd is not None:
150157
import math
151158

152-
if args.stage != "pr-history" or not math.isfinite(args.budget_usd) or args.budget_usd <= 0:
153-
print("--budget-usd is a finite positive ceiling for --stage pr-history only", file=sys.stderr)
159+
if args.stage not in ("pr-history", "knowledge-deepen") or not math.isfinite(args.budget_usd) or args.budget_usd <= 0:
160+
print("--budget-usd is a finite positive ceiling for pr-history or knowledge-deepen", file=sys.stderr)
154161
return 2
155162
params["budget_usd"] = str(args.budget_usd)
156163
outcome, run_dir = run_playbook(Settings(), "kb-init", args.repo, state_dir=state_dir, params=params)
@@ -199,19 +206,31 @@ def main(argv: list[str] | None = None) -> int:
199206
export.add_argument("--role", default="judge", choices=("judge", "generator"))
200207
init = sub.add_parser("init")
201208
init.add_argument("repo")
202-
from .init_support import STAGES
209+
from .init_support import INDEPENDENT_STAGES, STAGES
203210

204-
init.add_argument("--stage", choices=STAGES)
211+
init.add_argument("--stage", choices=STAGES + INDEPENDENT_STAGES)
205212
init.add_argument("--pr-count", type=int, help="PR-history window (default: adapter pr_history_count or 1000)")
206-
init.add_argument("--budget-usd", type=float, help="PR-history cumulative spend ceiling; may be raised to resume")
213+
init.add_argument("--budget-usd", type=float, help="incremental history/depth cumulative ceiling; may be raised to resume")
207214
init.add_argument("--dry-run", action="store_true",
208215
help="write the tree and PR body under the state directory instead of opening a PR")
209216
init.add_argument("--pin", help="upstream commit to pin (default: the default branch head)")
210217
init.add_argument("--suggest-seeds", action="store_true")
211218
init.add_argument("--from-existing", action="store_true",
212-
help="enrich a merged KB without local skeleton/modules records (knowledge only)")
219+
help="enrich a merged KB without local skeleton/modules records (knowledge stages)")
213220
init.add_argument("--subscription-generator", action="store_true",
214221
help="explicit subscription generator; unreported fees outside stage USD accounting")
222+
init.add_argument("--retry-unfinished", action="store_true", help="retry missing depth facets, preserving prior spend")
223+
for name, stage in (("widen", "knowledge"), ("deepen", "knowledge-deepen")):
224+
cmd = sub.add_parser(name, help="feature breadth" if name == "widen" else "feature implementation depth")
225+
cmd.add_argument("repo")
226+
cmd.add_argument("--dry-run", action="store_true")
227+
cmd.add_argument("--pin")
228+
cmd.add_argument("--subscription-generator", action="store_true")
229+
if name == "deepen":
230+
cmd.add_argument("--budget-usd", type=float)
231+
cmd.add_argument("--retry-unfinished", action="store_true")
232+
cmd.set_defaults(stage=stage, from_existing=True, suggest_seeds=False, pr_count=None,
233+
**({"budget_usd": None, "retry_unfinished": False} if name == "widen" else {}))
215234
publish = sub.add_parser("publish")
216235
where = publish.add_mutually_exclusive_group(required=True)
217236
where.add_argument("--remote", help="host:/absolute/path of the service state directory (over ssh)")
@@ -233,7 +252,7 @@ def main(argv: list[str] | None = None) -> int:
233252
return _publish(args)
234253
if args.command in {"traces", "replay", "export"}:
235254
return _traces_command(args, _state_dir(args.state_dir))
236-
if args.command == "init":
255+
if args.command in ("init", "widen", "deepen"):
237256
# before any ledger is opened: kb init never touches the service's kb.db
238257
return _init_command(args, _state_dir(args.state_dir))
239258

0 commit comments

Comments
 (0)