Skip to content

Commit eb61f23

Browse files
feat: land ambitious KB roadmap waves 0–6 (retrieval-A floor + moonshots)
Close the credibility floor with a live MCP gateway, wired kb_* tools, chunker/HNSW, and retrieval-A on this stack; add VectorStore/receipt protocols, TurboVec sidecar, advisory PR gate, and governed memory tools. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 35b1fa7 commit eb61f23

144 files changed

Lines changed: 7393 additions & 388 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/boundary.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,6 @@ jobs:
5959

6060
- name: make check-boundary
6161
run: make check-boundary
62+
63+
- name: Orphaned crate-path check (ADR-0002a)
64+
run: make check-orphaned-crate-paths

.github/workflows/eval.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ jobs:
5353
# Hard rule #3 (AGENTS.md): kb-engine cannot import chio_*.
5454
run: python3 ops/ci/check-imports.py
5555

56+
- name: Orphaned crate-path check (ADR-0002a)
57+
# Fail closed on crates/chio-receipts/ — actual home is
58+
# crates/core/chio-core-types (+ chio-eval-receipt).
59+
run: python3 ops/ci/check-orphaned-crate-paths.py
60+
5661
- name: kb-engine unit tests
5762
# Plugin protocol contracts, registry dispatch, dataclass behavior.
5863
run: |
@@ -69,6 +74,11 @@ jobs:
6974
uv sync --group dev
7075
uv run python -m pytest tests/ -v
7176
77+
- name: Synthetic second-pack smoke
78+
# Wave 2: generate demo-pack, install it, and prove the generic
79+
# Registry entry-point path can load more than chio-pack.
80+
run: make smoke-second-pack
81+
7282
# === INFORMATIONAL gates ===
7383

7484
- name: Run outcome evals (Phase 0 — non-blocking)

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,4 @@ Thumbs.db
6767
.idea/
6868
*.swp
6969
.vscode/settings.json
70+
.worktrees/

AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,4 @@ This repo lives at `/Users/connor/Medica/backbay/standalone/chio-developer-base/
5050

5151
- PR #599 `codex/chio-kb-a-grade-dogfood` — the origin stack. Will be replaced by a thin Make wrapper or submodule reference once Phase 1 lands.
5252
- arc's `tests/conformance/` — source of truth for SDK conformance fixtures used by the `conformance-harness-recall` outcome eval.
53-
- arc's `crates/chio-receipts/` — used by signed-retrieval verification (Phase 2).
53+
- arc's `crates/core/chio-core-types/` (receipt types) and `crates/sdk/chio-eval-receipt/` (bundle verifier) — used by signed-retrieval verification (Phase 2B). There is no `crates/chio-receipts/` crate.

Makefile

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@
99
# Phase 2+ (bigger blocks):
1010
# kb-bench, kb-verify, kb-gate-backtest
1111

12-
.PHONY: help check-boundary \
12+
.PHONY: help check-boundary check-orphaned-crate-paths smoke-second-pack \
1313
kb-status kb-migrate-seeds kb-harvest-fixtures kb-eval-outcomes-baseline \
1414
kb-up kb-down kb-reset kb-reseed kb-update kb-live kb-seed-memory kb-smoke \
1515
kb-eval kb-eval-retrieval kb-eval-outcomes kb-dogfood \
16-
kb-bench kb-verify kb-gate-backtest
16+
kb-bench kb-verify kb-gate-backtest kb-peer-cell
1717

1818
ARC_REPO ?= ../arc
1919
COMPOSE_FILE := infra/docker-compose.yml
@@ -35,6 +35,15 @@ help: ## list targets
3535
check-boundary: ## Phase 0: AGENTS.md hard rule #3 — engine ↔ pack and pack ↔ pack
3636
@python3 ops/ci/check-imports.py
3737

38+
check-orphaned-crate-paths: ## Wave 0: fail on orphaned crates/chio-receipts/ refs (ADR-0002a)
39+
@python3 ops/ci/check-orphaned-crate-paths.py
40+
41+
check-demo-pack: ## Wave 2: init-pack demo + assert load_entry_points() >= 2
42+
@python3 ops/ci/check-demo-pack.py
43+
44+
smoke-second-pack: ## Wave 2: install generated demo pack + assert plugin discovery
45+
@ops/ci/smoke-second-pack.sh
46+
3847
kb-status: ## Phase 0: report what exists vs what's expected
3948
@echo "== chio-developer-base status =="
4049
@echo "Phase 0 dependencies:"
@@ -126,9 +135,12 @@ kb-smoke: ## Phase 1: health + tools/list smoke
126135
kb-eval: kb-eval-retrieval kb-eval-outcomes ## Phase 1+: full eval gate
127136

128137
kb-eval-retrieval: ## Phase 1: retrieval eval (PR #599 fixtures, A floor)
129-
@test -f $(COMPOSE_FILE) || { echo "blocked: Phase 1 — $(COMPOSE_FILE) missing"; exit 1; }
130-
docker compose -f $(COMPOSE_FILE) exec -T chio-kb-mcp \
131-
chio-kb-eval --suite retrieval --fail-below-a
138+
@if docker compose -f $(COMPOSE_FILE) ps --status running 2>/dev/null | grep -q chio-kb-mcp; then \
139+
docker compose -f $(COMPOSE_FILE) exec -T chio-kb-mcp \
140+
chio-kb-eval --suite retrieval --fail-below-a; \
141+
else \
142+
cd chio-pack && uv run chio-kb-eval --suite retrieval --fail-below-a; \
143+
fi
132144

133145
kb-eval-outcomes: ## Phase 0+: outcome evals (time-to-fix, repeated-mistake, …)
134146
@test -f chio-pack/pyproject.toml || { echo "blocked: Phase 1.2 — chio-pack/ package not built"; exit 1; }
@@ -143,12 +155,18 @@ kb-dogfood: ## Phase 1: regenerate DOGFOOD-REVIEW.md
143155

144156
# == Phase 2+ moonshots ==
145157

146-
kb-bench: ## Phase 4: latency + memory + 200-file-PR gate benchmarks
147-
@echo "blocked: Phase 4 — bench harness not implemented"; exit 1
158+
kb-bench: ## Wave 4: pgvector vs TurboVec dual-index bench
159+
cd chio-pack && uv run python -m chio_pack.bench.dual_index
148160

149161
kb-verify: ## Phase 2B: verify a retrieval receipt
150-
@echo "blocked: Phase 2B — kb-engine/receipt/envelope.py not implemented"; exit 1
162+
@test -n "$(RESPONSE)" || { echo "usage: make kb-verify RESPONSE=path/to/response.json"; exit 2; }
163+
cd chio-pack && uv run chio-dev verify "$(RESPONSE)"
151164

152165
kb-gate-backtest: ## Phase 2A: backtest PR-impact gate against last N arc PRs
153-
@test -d "$(ARC_REPO)" || { echo "ERROR: ARC_REPO=$(ARC_REPO) missing"; exit 1; }
154-
@echo "blocked: Phase 2A — chio-pr-gate/ not implemented"; exit 1
166+
cd chio-pr-gate && uv run python -m chio_pr_gate.backtest \
167+
--arc-repo "$(abspath $(ARC_REPO))" --limit 50 \
168+
--out ../vault/_meta/dashboards/pr-gate-backtest.json
169+
170+
kb-peer-cell: ## Wave 6: run local KB MCP conformance peer cell
171+
PYTHONPATH=kb-engine:ops/ci python3 ops/ci/run_kb_peer_cell.py
172+
cd kb-engine && uv run --no-project pytest ../vault/_meta/conformance/kb-mcp/ -q

PLAN.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ class RetrievalReceipt:
324324
def wrap(response, gateway_capability) -> SignedResponse: ...
325325
```
326326

327-
**Eval.** A new eval category `signed-retrieval` in `chio_pack/eval/outcomes.yml`. Every fixture must produce a verifiable receipt. Receipt verification uses Chio's own `chio-receipts` crate — if the format ever drifts, the eval breaks.
327+
**Eval.** A new eval category `signed-retrieval` in `chio_pack/eval/outcomes.yml`. Every fixture must produce a verifiable receipt. Receipt verification uses `chio-core-types` (receipt types) and/or `chio-eval-receipt` (bundle verifier) — if the format ever drifts, the eval breaks. Default path for the KB gateway is a self-signed `DevSelfSignedSigner` in `kb-engine`; the Chio-capability signer is a `chio-pack` adapter.
328328

329329
---
330330

@@ -410,7 +410,7 @@ These exist to gate the carve-out's value, not just retrieval quality.
410410
|---|------|-----------|
411411
| 2B.1 | `kb_engine/receipt/envelope.py`: `RetrievalReceipt` type + signing | Unit tests pass |
412412
| 2B.2 | Wire into MCP gateway: every response wrapped | `signed-retrieval` eval = 1.0 |
413-
| 2B.3 | Verifier in `chio_pack/tools/verify_retrieval.py` using `chio-receipts` crate (via PyO3 or shell) | `chio-dev verify <response>` returns ✓ |
413+
| 2B.3 | Verifier in `chio_pack/tools/verify_retrieval.py` using `chio-core-types` / `chio-eval-receipt` (via PyO3 or shell), with engine `DevSelfSignedSigner` as default | `chio-dev verify <response>` returns ✓ |
414414
| 2B.4 | Index/snapshot version emission: pgvector index version, Neo4j snapshot id | Receipts contain reproducible cursors |
415415
| 2B.5 | Capability for the gateway: scoped grant `kb.read.*`, `episodes.write.dev_notes` | Capability minted; gateway boots only with it |
416416

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Benchmark helpers for chio-pack."""
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
"""pgvector vs TurboVec dual-index benchmark.
2+
3+
Default mode is offline/synthetic so CI does not need Postgres or the optional
4+
TurboVec package. When ``turbovec`` + ``numpy`` are installed, the report also
5+
includes a real ``IdMapIndex`` row behind ``KB_VECTOR=turbovec``.
6+
7+
Postgres/pgvector remains the primary CI gate. This bench never promotes
8+
TurboVec.
9+
"""
10+
from __future__ import annotations
11+
12+
import argparse
13+
import os
14+
import random
15+
import resource
16+
import statistics
17+
import time
18+
from pathlib import Path
19+
from typing import Sequence
20+
21+
from kb_engine.store import FakeTurboVecStore, TurboVecStore, create_turbovec_store
22+
23+
24+
def _vectors(n: int, dim: int) -> list[list[float]]:
25+
rng = random.Random(42)
26+
return [[rng.uniform(-1.0, 1.0) for _ in range(dim)] for _ in range(n)]
27+
28+
29+
def _p95(values: Sequence[float]) -> float:
30+
if not values:
31+
return 0.0
32+
ordered = sorted(values)
33+
idx = min(len(ordered) - 1, int(round((len(ordered) - 1) * 0.95)))
34+
return ordered[idx]
35+
36+
37+
def _bench_store(name: str, store, n: int, dim: int, queries: int) -> dict[str, float | str]:
38+
vectors = _vectors(n, dim)
39+
store.add_with_ids(list(range(1, n + 1)), vectors)
40+
latencies: list[float] = []
41+
for query in _vectors(queries, dim):
42+
started = time.perf_counter()
43+
store.search(query, k=8)
44+
latencies.append((time.perf_counter() - started) * 1000)
45+
return {
46+
"backend": name,
47+
"count": n,
48+
"dim": dim,
49+
"p95_ms": _p95(latencies),
50+
"mean_ms": statistics.fmean(latencies) if latencies else 0.0,
51+
"rss_mb": _rss_mb(),
52+
}
53+
54+
55+
def run_bench(n: int = 1000, dim: int = 32, queries: int = 50) -> list[dict[str, float | str]]:
56+
# Align dim to TurboVec's multiple-of-8 constraint for the real path.
57+
real_dim = dim if dim % 8 == 0 else dim + (8 - dim % 8)
58+
rows: list[dict[str, float | str]] = [
59+
# Exact cosine baseline (in-memory Fake) — not live Postgres/pgvector ANN.
60+
_bench_store("exact-cosine-baseline", FakeTurboVecStore(dim=real_dim), n, real_dim, queries),
61+
_bench_store("turbovec-fake-sidecar", FakeTurboVecStore(dim=real_dim), n, real_dim, queries),
62+
]
63+
# Optional real package path (install: uv pip install 'kb-engine[turbovec]')
64+
try:
65+
store = create_turbovec_store(dim=real_dim)
66+
if isinstance(store, TurboVecStore):
67+
rows.append(_bench_store("turbovec-real-idmap", store, n, real_dim, queries))
68+
else:
69+
rows.append({
70+
"backend": "turbovec-real-idmap",
71+
"count": n,
72+
"dim": real_dim,
73+
"p95_ms": 0.0,
74+
"mean_ms": 0.0,
75+
"rss_mb": _rss_mb(),
76+
"note": "skipped: turbovec not installed; Fake used",
77+
})
78+
except Exception as exc: # pragma: no cover - environment-specific
79+
rows.append({
80+
"backend": "turbovec-real-idmap",
81+
"count": n,
82+
"dim": real_dim,
83+
"p95_ms": 0.0,
84+
"mean_ms": 0.0,
85+
"rss_mb": _rss_mb(),
86+
"note": f"skipped: {exc}",
87+
})
88+
return rows
89+
90+
91+
def _rss_mb() -> float:
92+
raw = float(resource.getrusage(resource.RUSAGE_SELF).ru_maxrss)
93+
# Linux reports KiB; macOS reports bytes.
94+
return raw / (1024 * 1024) if raw > 10_000_000 else raw / 1024
95+
96+
97+
def render_markdown(rows: list[dict[str, float | str]]) -> str:
98+
kb_vector = os.environ.get("KB_VECTOR", "pgvector")
99+
lines = [
100+
"# Vector Bench",
101+
"",
102+
"> Dual-index sidecar report. TurboVec is optional; pgvector remains the",
103+
f"> default primary backend (`KB_VECTOR={kb_vector}`). Real TurboVec rows",
104+
"> appear only when `turbovec`+`numpy` are installed (`kb-engine[turbovec]`).",
105+
"> This artifact does **not** promote TurboVec.",
106+
"",
107+
"| Backend | Vectors | Dim | p95 ms | Mean ms | RSS MB | Note |",
108+
"| --- | ---: | ---: | ---: | ---: | ---: | --- |",
109+
]
110+
for row in rows:
111+
note = str(row.get("note", ""))
112+
lines.append(
113+
"| {backend} | {count} | {dim} | {p95_ms:.3f} | {mean_ms:.3f} | {rss_mb:.1f} | {note} |".format(
114+
backend=row["backend"],
115+
count=row["count"],
116+
dim=row["dim"],
117+
p95_ms=float(row["p95_ms"]),
118+
mean_ms=float(row["mean_ms"]),
119+
rss_mb=float(row["rss_mb"]),
120+
note=note,
121+
)
122+
)
123+
lines.append("")
124+
return "\n".join(lines)
125+
126+
127+
def main() -> int:
128+
parser = argparse.ArgumentParser(description=__doc__)
129+
parser.add_argument("--n", type=int, default=1000)
130+
parser.add_argument("--dim", type=int, default=32)
131+
parser.add_argument("--queries", type=int, default=50)
132+
parser.add_argument(
133+
"--out",
134+
default="../vault/_meta/dashboards/vector-bench.md",
135+
help="markdown report path",
136+
)
137+
args = parser.parse_args()
138+
139+
rows = run_bench(n=args.n, dim=args.dim, queries=args.queries)
140+
report = render_markdown(rows)
141+
out = Path(args.out)
142+
out.parent.mkdir(parents=True, exist_ok=True)
143+
out.write_text(report, encoding="utf-8")
144+
print(report)
145+
print(f"wrote {out}")
146+
return 0
147+
148+
149+
if __name__ == "__main__":
150+
raise SystemExit(main())

chio-pack/chio_pack/cli.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,36 @@ def init_pack(name: str, dest: str) -> None:
476476
click.echo(str(pack_dir))
477477

478478

479+
480+
@main.command('verify')
481+
@click.argument('response_json', type=click.Path(exists=True, dir_okay=False, path_type=Path))
482+
def verify_cmd(response_json: Path) -> None:
483+
"""Verify a signed retrieval response (Wave 4 / Phase 2B)."""
484+
from kb_engine.receipt import verify_response
485+
486+
payload = json.loads(response_json.read_text(encoding='utf-8'))
487+
ok, reason = verify_response(payload)
488+
if ok:
489+
click.secho('✓ receipt verified', fg='green')
490+
sys.exit(0)
491+
click.secho(f'✗ verification failed: {reason}', fg='red', err=True)
492+
sys.exit(1)
493+
494+
495+
@main.command('retrieval-eval')
496+
@click.option('--fail-below-a', is_flag=True)
497+
@click.option('--fixtures', 'fixtures_dir', default=None)
498+
def retrieval_eval_cmd(fail_below_a: bool, fixtures_dir: str | None) -> None:
499+
"""Run retrieval fixtures against the live tool runtime."""
500+
from chio_pack.eval.retrieval import run_retrieval_eval
501+
502+
fixtures = Path(fixtures_dir) if fixtures_dir else None
503+
report = run_retrieval_eval(fixtures_dir=fixtures, fail_below_a=fail_below_a)
504+
click.echo(json.dumps(report, indent=2))
505+
if fail_below_a and report.get('grade') != 'A':
506+
sys.exit(1)
507+
508+
479509
# === Session log ===
480510

481511

0 commit comments

Comments
 (0)