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
4 changes: 4 additions & 0 deletions doc/architecture/SPEC/knowledge_view.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,7 @@ stdlib + `.sdk._resources`。叶子模块。

## 测试
`test_knowledge_view_routing.py`。

## 2026-09-28 可记录的快照标识
`public_snapshot`:激活快照 ID、`packaged` 或 `unverified`(开发树的绝对路径不外泄);`tree_sha256`:已验证快照
按清单重算的树哈希。`direct_routing` 的 `diagnostics.knowledge_snapshot` 与 SDK 计划都使用它们。
5 changes: 5 additions & 0 deletions doc/architecture/SPEC/sdk.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,8 @@ Direct 1.1 / Strict 1.3 accept typed `CarriedFinding` inputs (unique IDs, source
## 2026-09-28 trace/1 导出
`sdk.v1` 导出 `TraceStore`、`TRACE_SCHEMA`、`trace_context`、`redact`(见 `trace_store.md`),RB 用同一 schema
记录 review 的模型调用、判定与结果;导入它们不加载 `config`/`contract`/`mcp_server` 等私有模块。

## 2026-09-28 计划携带知识快照
`DirectReviewPlan` 新增 `knowledge_snapshot`(激活快照 ID、`packaged` 或 `unverified`,从不暴露开发树路径)
与 `knowledge_tree_sha256`(已验证快照的清单树哈希,否则为空)。同一 `review_context_id` 下的文档读取都来自这份
快照,RB 应随每次 review 记录这两个值。
2 changes: 1 addition & 1 deletion src/infermatrix_copilot/direct_routing.py
Original file line number Diff line number Diff line change
Expand Up @@ -687,7 +687,7 @@ def direct_review_plan(
"if_missing": "partial_review",
},
"diagnostics": {
"knowledge_snapshot": view.snapshot,
"knowledge_snapshot": view.public_snapshot,
"timing_ms": {
"routing": route_ms,
"execution_budget": budget_ms,
Expand Down
16 changes: 16 additions & 0 deletions src/infermatrix_copilot/knowledge_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,22 @@ def current(cls) -> "KnowledgeView":
def verified(self) -> bool:
return self.files is not None

@property
def public_snapshot(self) -> str:
"""The snapshot id safe to record anywhere: the activated snapshot's id,
``packaged``, or ``unverified`` (a development tree's path is never exposed)."""
return "unverified" if self.snapshot.startswith("unverified:") else self.snapshot

@property
def tree_sha256(self) -> str:
"""The manifest tree hash of a verified snapshot ("" otherwise)."""
if self.files is None:
return ""
tree = hashlib.sha256()
for rel in sorted(self.files):
tree.update(f"{rel}\0{self.files[rel]}\n".encode("utf-8"))
return tree.hexdigest()

def relative(self, path: str | Path) -> str:
"""Return the knowledge-relative id of an absolute path inside this view."""
try:
Expand Down
2 changes: 2 additions & 0 deletions src/infermatrix_copilot/sdk/v1/direct.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,8 @@ def plan(self, request: DirectReviewRequest) -> DirectReviewPlan:
completion_gate=completion_gate,
diagnostics=dict(raw.get("diagnostics") or {}),
carried_findings=request.carried_findings,
knowledge_snapshot=view.public_snapshot,
knowledge_tree_sha256=view.tree_sha256,
)
self._remember_context(review_context_id, expected_head, carried, view)
return plan
Expand Down
4 changes: 4 additions & 0 deletions src/infermatrix_copilot/sdk/v1/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,10 @@ class DirectReviewPlan(_Serializable):
completion_gate: dict[str, Any]
diagnostics: dict[str, Any] = field(default_factory=dict)
carried_findings: tuple[CarriedFinding, ...] = ()
# which knowledge this plan (and every document read under its
# review_context_id) was served from: record it with the review
knowledge_snapshot: str = ""
knowledge_tree_sha256: str = ""
Comment on lines +255 to +256

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Bump the Direct protocol version for the new fields

In a rolling or mixed-version deployment, get_capabilities() and each plan still advertise Direct 1.1.0 even though older 1.1 providers do not return these snapshot fields. A ReviewBot relying on the version handshake therefore cannot determine whether it can safely record the required knowledge provenance and may silently receive missing values. Increment DIRECT_API_VERSION and document the new contract version, as was done when the previous public Direct fields were introduced.

Useful? React with 👍 / 👎.


FeedbackStatus = Literal[
"checked", "disabled", "unavailable", "not_applicable"
Expand Down
19 changes: 19 additions & 0 deletions test/test_knowledge_view_routing.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,10 @@ def test_sdk_completion_pins_the_plan_snapshot(tmp_path, monkeypatch):
changed_paths=(ChangedPath(path="vllm_omni/core/sched/a.py"),),
))
assert plan.diagnostics["knowledge_snapshot"] == "e" * 40
assert plan.knowledge_snapshot == "e" * 40
manifest = json.loads((old / "MANIFEST.json").read_text())
assert plan.knowledge_tree_sha256 == manifest["tree_sha256"]
assert plan.to_dict()["knowledge_snapshot"] == "e" * 40

tmp_link = tmp_path / "active.tmp"
tmp_link.symlink_to(new)
Expand All @@ -220,6 +224,21 @@ def test_sdk_completion_pins_the_plan_snapshot(tmp_path, monkeypatch):
assert "provider resources changed after the review context was issued" not in decision.missing


def test_plans_from_a_development_tree_never_expose_its_path(tmp_path, monkeypatch):
from infermatrix_copilot.sdk.v1 import ChangedPath, DirectClient, DirectReviewRequest, RepositoryRef

root = _copy_tree(tmp_path)
monkeypatch.setenv(KNOWLEDGE_ROOT_ENV, str(root))
_load_view.cache_clear()
plan = DirectClient().plan(DirectReviewRequest(
review_id="r3", repository=RepositoryRef(alias="vllm-omni"), pr_number=3,
expected_head_sha="3" * 40, title="scheduler fix", body="",
changed_paths=(ChangedPath(path="vllm_omni/core/sched/a.py"),),
))
assert plan.knowledge_snapshot == "unverified" and plan.knowledge_tree_sha256 == ""
assert str(tmp_path) not in json.dumps(plan.to_dict())


def test_sdk_document_reads_follow_the_plan_snapshot(tmp_path, monkeypatch):
from infermatrix_copilot.sdk.v1 import (
ChangedPath, DirectClient, DirectReviewRequest, RepositoryRef,
Expand Down
Loading