Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 26 additions & 18 deletions doc/architecture/SPEC/direct_routing.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
# direct_routing.py —— 规范

<!-- verified-against: 2026-09-10 -->
<!-- verified-against: 2026-09-28 -->

`LOC ~917 · Direct 模式完整策略包与知识路由 · refactor-status: known-debt`
`LOC ~880 · Direct 模式完整策略包与仓库中立的知识路由 · refactor-status: stable`

## 职责
Direct 模式的知识路由:owner/model 路由表和选路机制。从
`thin_mcp_server.py` **逐字迁出**(下游曾经 `importlib` 拿它的私有名),
公开面由 `contract.py` 再导出。它显式携带仓库专属知识 —— 这正是
`contract.py` 必须保持中立而这里不必的原因;把表外置到
`adapters/<repo>/` 是**未被这次搬迁改变的既有欠账**。
Direct 模式的知识路由**机制**。模块中不出现任何被服务仓库的名字:每个仓库的
owner/model 路由表是知识数据 `knowledge/repos/<repo>/_routes.yaml`,仓库别名
来自 `adapters/<repo>/manifest.yaml` 的 `repo.full_name`/`repo.aliases`。
公开面由 `contract.py` 再导出。

## 公开契约
经 `contract.py` 再导出的五个名字:`direct_review_plan`(完整、一次性的
Expand All @@ -29,9 +28,15 @@ Direct policy bundle)、`direct_knowledge_routes`、
又不许看"不是)。
- adapter-backed changed-file 路由同样拆开 `(quick_map, status)`,绝不把 tuple
当成文本跨边界,也绝不把 unavailable 误报成无需读取。
- knowledge/adapters 根由 `sdk._resources` 的 `importlib.resources` 解析,editable
source 与安装 wheel 走同一标记校验;仓库路径只留在本模块内部的旧版 dict,
`sdk.v1.DirectClient` 对外转换为 document ID。
- **每请求一个 `KnowledgeView`**:入口函数在开始时解析一次视图(未设置
`KNOWLEDGE_ROOT` 时为打包知识;设置时为激活快照的真实目录并按清单校验),
本请求内所有读取经同一视图。模块不再在导入期缓存知识根;`_KNOWLEDGE` 只保留
为模块级 `__getattr__` 惰性别名。
- **路由选择按数据而非仓库名**:仓库有非空 `_routes.yaml` → title/body owner
路由 + 模型路由 + scope fallback;否则有 adapter → changed-file 路由;否则
`unsupported_exact_router`。`_routes.yaml` 引用的页面不存在时 fail-closed。
- `repo` 必填:空值抛 `ValueError`,不再默认某个仓库;形似路径的仓库名直接
视为不支持。
- **changed files 校验选择、绝不静默替换选择**:title/body 选 owner,
diff 只报告支持或矛盾;scope-fallback 是最后手段且永远显式
(`status="scope_fallback"`)。
Expand All @@ -46,23 +51,26 @@ Direct policy bundle)、`direct_knowledge_routes`、
(`test_contract.py::test_direct_routing_does_not_import_a_server_module`)。

## 边界 —— 不属于这里
不执行、不调模型;只有路由表 + 机制。多 adapter 桥接经
不执行、不调模型;只有机制,路由表在知识数据里。多 adapter 桥接经
`_normalize_repo`/`_adapter_for_repo` 走 `adapters/`。

## 依赖(允许)
stdlib + `.adapters`(AdapterError / AdapterRegistry / RepoAdapter)+
`.sdk._resources`。
stdlib + PyYAML + `.adapters`(AdapterError / AdapterRegistry / RepoAdapter)+
`.knowledge_view` + `.sdk._resources`。
位于 `contract.py` 和 `thin_mcp_server.py` 之下。

## 扩展点
新 owner 路由/模型规则 → 表数据;跨仓库通用化 → 外置进
`adapters/<repo>/routing`(既有欠账的正解,不是在这里再长表)。
新 owner 路由/模型规则 → 改对应仓库的 `_routes.yaml`(schema_version 1:
`owners[{owner, path, signals, scope_prefixes}]`、可选 `models{dir, page}`);
新仓库 → 提供 adapter 与 `_routes.yaml`,不改 `src/`。

## 测试
`test_contract.py`(公开家、import 方向、中立性豁免);
`test_knowledge_view_routing.py`(150 个真实 vllm-omni PR 的黄金路由输出、
第二仓库经自身 `_routes.yaml` 路由、快照切换下一请求生效、快照篡改 fail-closed、
SDK 完成校验钉住计划时快照、模块源码不含仓库名);`test_contract.py`(公开家、import 方向、中立性豁免);
`test_thin_mcp_server.py` / `test_thin_mcp.py`(经新家继续锻炼全部
下划线函数:路由、预算、完成门)。

## 重构备注
768 行里约 500 行是表数据。`known-debt` 指的就是表:机制是稳定的,
表的归宿在 adapter 数据面(见结构重组计划 Stage 8 的 routing.yaml 方案)。
原 `_DIRECT_OWNER_ROUTES`/`_REPO_ALIASES` 已外置(`known-debt` 清零),
`test_v2_p0.py` 与 `test_repo_vocabulary.py` 中本模块的泄漏上限随之移除。
5 changes: 4 additions & 1 deletion doc/architecture/SPEC/knowledge_docs.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# knowledge_docs.py —— 规范

<!-- verified-against: 2026-08-18 -->
<!-- verified-against: 2026-09-28 -->

`LOC ~122 · 供 MCP 面使用的只读知识检索 · refactor-status: ok`

Expand Down Expand Up @@ -30,3 +30,6 @@
## 重构备注
**保持它不含模型**:这是 Direct MCP 路径与工具桥共用的**唯一**知识读取器,
在这里加一次模型调用,等于把第二个模型塞进了"server 不跑模型"这条保证里面。

## 2026-09-28 快照校验
可选 `verify(rel)` 回调在 `read`/`search` 读取每个文件前调用;MCP 传入 `KnowledgeView.path`,快照中缺失或被改动的文件使读取/搜索 fail-closed。
33 changes: 33 additions & 0 deletions doc/architecture/SPEC/knowledge_view.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# knowledge_view.py —— 规范

<!-- verified-against: 2026-09-28 -->

`LOC ~170 · 每请求的知识树视图(打包知识或激活快照) · refactor-status: stable`

## 职责
为每个请求解析**一个**知识根,并让本请求内所有读取经过它。知识服务通过原子
切换符号链接激活新快照;导入期常量会一直服务旧树(包括已退役规则)直到进程
重启,因此视图必须在请求开始时解析。

## 公开契约
- `KnowledgeView.current()`:`KNOWLEDGE_ROOT` 未设置 → 打包知识,
`snapshot="packaged"`;已设置 → 对其 `realpath` **只取一次**。含
`MANIFEST.json` 的目录是激活快照,根为其 `knowledge/`;只含 `AGENTS.md` 的
目录作为开发用未校验树(`snapshot="unverified:<path>"`);其余 fail-closed。
- `view.path(rel)` / `view.read_text(rel)`:拒绝逃逸与缺失;快照模式下文件必须
在清单中且 sha256 一致,否则抛 `KnowledgeViewError`。
- `view.relative(path)`:绝对路径 → 知识相对 id。
- `build_manifest(root, snapshot)`:生成 schema_version 1 清单
(`files` 逐文件 sha256、`tree_sha256`)。

## 不变量
- 一个请求不混用两棵树:解析后使用真实目录,不再经过符号链接。
- 快照首次加载时校验:磁盘文件集合与清单完全一致、`tree_sha256` 与文件列表
一致;每次读取再校验单文件 sha256。
- 快照不可变,因此按解析后的目录缓存加载结果是安全的:新激活是另一个目录。

## 依赖(允许)
stdlib + `.sdk._resources`。叶子模块。

## 测试
`test_knowledge_view_routing.py`。
5 changes: 4 additions & 1 deletion doc/architecture/SPEC/sdk.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# sdk/ —— 规范

<!-- verified-against: 2026-09-26 -->
<!-- verified-against: 2026-09-28 -->


`Python SDK v1 · 跨仓库唯一 typed 边界 · refactor-status: ok`
Expand Down Expand Up @@ -118,3 +118,6 @@ knowledge checkout,不改仓库真实 `knowledge/`。
## Carried finding rechecks

Direct 1.1 / Strict 1.3 accept typed `CarriedFinding` inputs (unique IDs, source head, severity, location, title and evidence). Direct binds the carried set into its issued context and validates `FindingRecheck` answers. Strict passes the set through the policy allowlist, performs a read-only recheck against the frozen PR head, and persists answers for the public structured result. Every carried ID needs an explicit outcome: `fixed`, `still_affected`, or `unverified`. Missing evidence is never a fix.

## 2026-09-28 知识视图
`DirectClient` 每次 `plan` 解析一个 `KnowledgeView`,文档引用与 `resource_revision` 均取自该视图;`validate` 按计划时钉住的知识根校验资源未变,激活新快照不会使进行中的 review 失效;`diagnostics.knowledge_snapshot` 报告所用快照。`read_document(..., review_context_id=...)` 从该 review 计划时钉住的知识树读取(含分页),未签发的 context id 被拒绝;不带 context id 时读当前激活树。
5 changes: 4 additions & 1 deletion doc/architecture/SPEC/thin_mcp_server.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# thin_mcp_server.py —— 规范

<!-- verified-against: 2026-08-31 -->
<!-- verified-against: 2026-09-28 -->

`LOC ~490 · 默认 MCP:Direct 门面 + Strict 入口 · refactor-status: ok`

Expand Down Expand Up @@ -82,3 +82,6 @@ stdlib + `mcp` extra + `.direct_routing`(下划线别名 re-import)+
迁到 `direct_routing`,避免 MCP 和 Python SDK 各拼一份协议。
拆分保住了"server 不跑模型"—— 它仍是 Direct 模式的产品承诺;
后续增长优先落到 `direct_routing`/adapter 数据面,不回到这里。

## 2026-09-28 知识视图
知识根改为每次调用经 `KnowledgeView.current()` 解析;`_KNOWLEDGE` 仅为惰性别名。
37 changes: 37 additions & 0 deletions knowledge/repos/vllm-omni/_routes.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Direct-mode owner routing for vllm-omni. Read by the repo-neutral router in
# src/infermatrix_copilot/direct_routing.py; nothing in src/ names this repo.
#
# owners: the PR's title/body is matched against `signals` (word-bounded, case-
# and separator-insensitive) to pick owner pages; `scope_prefixes` report which
# owners the changed files touch, and select them only as a last resort.
# models: every <dir>/<page> under `dir` is a model route matched by name.
# Order of `owners` is the tie-break order and must stay stable.
schema_version: 1
owners:
- owner: configuration
path: repos/vllm-omni/components/configuration/rules.md
signals: [config, configuration, yaml, registry, deploy, pipeline, override, default, cli flag, topology]
scope_prefixes: [vllm_omni/config/, vllm_omni/deploy/]
- owner: serving
path: repos/vllm-omni/components/serving/rules.md
signals: [serving, server, endpoint, openai, request, response, http, chat completion, completion endpoint, speech api, sse, websocket, sleep, wake, partial wake, engine lifecycle, idempotency, ack]
scope_prefixes: [vllm_omni/entrypoints/openai/, vllm_omni/entrypoints/api_server.py, vllm_omni/entrypoints/async_omni.py]
- owner: model-executor
path: repos/vllm-omni/components/model-executor/rules.md
signals: [model executor, loader, checkpoint, tokenizer, processor, stage input, stage handoff, runtime info, runtime_info, batch, sampling]
scope_prefixes: [vllm_omni/model_executor/, vllm_omni/inputs/]
- owner: diffusion
path: repos/vllm-omni/components/diffusion/rules.md
signals: [diffusion, image generation, text to image, image to image, lora, vae, dit, ulysses, cache dit]
scope_prefixes: [vllm_omni/diffusion/, vllm_omni/model_executor/models/diffusers/]
- owner: distributed
path: repos/vllm-omni/components/distributed/_index.md
signals: [distributed, tensor parallel, data parallel, replica, collective, rpc]
scope_prefixes: [vllm_omni/distributed/, vllm_omni/worker/, vllm_omni/entrypoints/async_omni.py]
- owner: scheduler
path: repos/vllm-omni/components/scheduler/rules.md
signals: [scheduler, scheduling, prefix cache, token budget, queue, side stream]
scope_prefixes: [vllm_omni/core/sched/]
models:
dir: repos/vllm-omni/models
page: rules.md
Loading
Loading