Make the proof suite say what it actually ran

The suite had fifteen checks that could not lose. The visual HashHop arena
painted a cyan line and a white ring on the answer slot, then asked the model
to find the answer by looking; the collector re-rolled puzzles until the
running rate crossed its target; the cache check passed if any layer had ever
recorded an entry; the repository check passed on a call graph built in memory
without touching the store; the research-module check asserted non-empty lists
of SHA256-derived placeholder vectors and so could not fail.

Each check now answers for one claim and reports a verdict the reader can act
on: passed, failed, deferred, or removed. A deferred row names what is missing
and the command that would settle it; a removed row says why the old claim was
withdrawn. The suite verdict is failed > deferred > passed, so a claim that
never ran holds the whole report back from saying "proven".

- evals.py (2427 lines) becomes the proofs/ package; largest module 445 lines.
- proofs/__main__.py deleted: it duplicated PRDProofSuite.latest() with a
  different glob. proofs/table.py renders; latest-proof-suite is the one face
  and exits 1 on a failed verdict.
- The arena paints nothing. The puzzle id is printed on its tile instead,
  because removing the ink without it removes the question.
- HashHop runs a fixed 8 puzzles per depth instead of re-rolling to target.
- The contradiction corpus moves from code to contradiction_scenarios.json;
  the check stays deferred while the corpus is the one this repo authored.
- The cache check compiles a nonce question over a real atom twice and reads
  the miss to hit movement; an empty store fails instead of agreeing by luck.
- The repository check requires rows in the store; the research-module check is
  removed.

Two product bugs surfaced on the way:
- text_index.fts_query joined Latin terms with a space, which FTS5 reads as
  AND, so a question longer than its answer retrieved nothing. Terms are ORed
  and bm25 rank orders the candidates.
- profiles.windows_path_to_wsl prefixed /mnt/ onto an already-POSIX path with
  an empty drive, producing /mnt//home/... and failing every launcher probe.

Verification: 168 passed (pytest backend/tests bench/tests); ruff clean on the
proofs package, cli.py, text_index.py, profiles.py, and both test files; mypy
clean on 16 files with a fresh cache; pyright reports 0 errors on proofs/ and
the test file. Ruff debt elsewhere is unchanged: 19 errors in seven files this
commit does not touch, measured against the same files at HEAD.
This commit is contained in:
ZacharyZhang-NY committed 2026-10-07 18:39:46 -04:00
1 parent dfc6cd4c28
commit 4ab36cd5eb
27 files changed
+4284 -2453

No files matched your search

+19 -6
View File
@@ -105,12 +105,25 @@
- 根因修复:`_answered()` 里 `readable = owner in (as_holder, LIBRARY)` 是 SQL 可见性子句之外的第二份、更严的规则,与 `visible_to=[husband]` 冲突(共享记忆被错误隐藏)→ 删掉这份重复判断,SQL 的 `as_holder` 可见性子句是唯一权威。 - 根因修复:`_answered()` 里 `readable = owner in (as_holder, LIBRARY)` 是 SQL 可见性子句之外的第二份、更严的规则,与 `visible_to=[husband]` 冲突(共享记忆被错误隐藏)→ 删掉这份重复判断,SQL 的 `as_holder` 可见性子句是唯一权威。
- 偏差:Go 侧 `limit`/`max_hops` 零值曾当真实数字发出,被 API 以 `greater_than` 拒 → 未设置的可选字段一律省略,由服务端定默认值。 - 偏差:Go 侧 `limit`/`max_hops` 零值曾当真实数字发出,被 API 以 `greater_than` 拒 → 未设置的可选字段一律省略,由服务端定默认值。
- 验收:`pytest tests/test_transactive.py` 绿;钥匙测试场景通过 - 验收:`pytest tests/test_transactive.py` 绿;钥匙测试场景通过
- [ ] **p0-6** 证明套件去自证 - [x] **p0-6** 证明套件去自证
- [ ] p0-6.1 删 arena 答案入墨(`evals.py:1408-1409` 连接线、`evals.py:1417-1426` 白圈) - [x] p0-6.1 删 arena 答案入墨(`evals.py:1408-1409` 连接线、`evals.py:1417-1426` 白圈)
- [ ] p0-6.2 删 best-of-N 重摇与达标即停 - 偏差:入墨是唯一的可读信号——`render_visual_hash` 只画噪声、不画字,答案槽被青色线+白圈标出后,模型不需要检索也能答。所以删墨的同时把 id 印上瓦片(`proofs/arena.py:render_visual_hash` 白底黑字、每行 8 字符、字号 `tile_size//8`),否则删墨 = 删题。
- [ ] p0-6.3 删自造矛盾场景(出题者≠判分者) - [x] p0-6.2 删 best-of-N 重摇与达标即停
- [ ] p0-6.4 删缓存/证据图自触发式检查 - `collect_model_visual_proofs(evaluator, hops, token_equivalent, attempts)` 固定跑 `HASHHOP_ATTEMPTS = 8` 题;旧代码 `while len(proofs) < max_samples` 里一达标就 break(`evals.py:2365`),等于弱模型反复重摇到及格。
- [ ] p0-6.5 模型相关检查标 `DEFERRED`,不进 pass - [x] p0-6.3 删自造矛盾场景(出题者≠判分者)
- 偏差:自造场景没有删掉(删了就没得测),而是从代码搬进**数据**:`proofs/contradiction_scenarios.json`(12 场景,sha256 `5f93aba09cbfc32f…`),`corpus_path(settings.data_dir)` 优先读运维者放的第三方集,`ely-eye contradiction-corpus` 写默认集。检查项**永久 DEFERRED**,直到磁盘上不是自带的那份;reason 里写明「生产者用自家例题判分不算证据」。
- [x] p0-6.4 删缓存/证据图自触发式检查
- 缓存:旧检查只要 `any(layer.entries > 0)` 就算过(`evals.py:1252-1265`)。现在拿 store 里真实的一条 atom 拼一个带 nonce 的问题,编译两次,读 `cache_events` 的 miss→hit 计数;空 store 直接 failed(空上下文会让两次编译「一致」得毫无意义)。顺带修掉真实双计数:`read_semantic_cache` 与 `compiler.compile` 各记一次事件,现在读是纯读、编译恰好记一次(缓存命中带 hits 才记 hit,空缓存记 miss 并附 reason)。
- 仓库覆盖:旧检查 `indexed_file_count > 0` + 有调用图 + 有 git 历史就算过,不碰 store。现在必须 `sources > 0 && atoms > 0`,否则 failed 并说明「仓库上下文建了但没进 store」。
- 研究模块:旧检查断言八个模块各返回非空列表,而那些向量是 SHA256 派生的假向量——**不可能失败**。改为 `status="removed"`,artifact 记下为什么撤下、重新加回的条件。
- [x] p0-6.5 模型相关检查标 `DEFERRED`,不进 pass
- `ProofCheck.status` 加 `deferred`/`removed` + `reason` + `rerun`;`_deferred_without_model()` 在 `model_dir` 缺失时产出 deferred 并点名缺什么。聚合改成 `failed > deferred > passed`:只要还有没跑成的主张,整个套件就不说「通过」。每条 failed/deferred 都带 why 与可执行的 rerun 命令(`proofs/table.py` 渲染)。
- [x] p0-6.6 顺手还清的文件尺寸债
- `evals.py` 2427 行 → `proofs/` 包 15 个模块,最大 445 行(`checks_cartridge.py`),全部 ≤500 行;`suite.py` 218 行只剩「跑哪些检查、怎么定论」。`proofs/__main__.py` 删掉(它的 `latest_report()` 与 `PRDProofSuite.latest()` 是两份 glob 不同的重复实现),渲染移到 `proofs/table.py`,`latest-proof-suite` 成为唯一入口并在 failed 时 `exit 1`。
- 顺带修掉两个被证明测试逼出来的真 bug:
1. `text_index.fts_query` 把拉丁词用空格连起来 = FTS5 隐式 AND,长问题永远查不到短答案(实测「Which Ely-Eye PRD requirements prove long context memory, HashHop, and adapters?」→ 0 命中)。改成 OR + bm25 rank 排序。
2. `profiles.windows_path_to_wsl()` 对本来就是 POSIX 的路径也拼 `/mnt/` + 空 drive,产出 `/mnt//home/...`,六个 runtime profile 的探针全部 `probe_exit_code: 1`。
- 验收:`python -m pytest backend/tests/test_proofs.py -q` → 12 passed;`ELY_EYE_HOME=/tmp/p06home ely-eye proof-suite --cartridge-id p06_20cf30f7804d && ely-eye latest-proof-suite` → 15 行判决(5 failed / 3 passed / 6 deferred / 1 removed),每条带 why 与 rerun。
- 验收:`python -m ely_eye.proofs --report` 逐条 PASS/DEFERRED/REMOVED + 理由 - 验收:`python -m ely_eye.proofs --report` 逐条 PASS/DEFERRED/REMOVED + 理由
--- ---
+1 -1
View File
@@ -24,7 +24,6 @@ from .compiler import ContextCompiler
from .config import Settings, get_settings from .config import Settings, get_settings
from .db import Database from .db import Database
from .embeddings import EmbeddingService from .embeddings import EmbeddingService
from .evals import HashHopEvaluator, PRDProofSuite
from .evaluation_schemas import ( from .evaluation_schemas import (
BenchmarkPredictionReport, BenchmarkPredictionReport,
BenchmarkRegistryReport, BenchmarkRegistryReport,
@@ -38,6 +37,7 @@ from .evidence_graph import EvidenceGraphService
from .ingestion import IngestionService from .ingestion import IngestionService
from .memory import MemoryService from .memory import MemoryService
from .profiles import runtime_profile_report from .profiles import runtime_profile_report
from .proofs import HashHopEvaluator, PRDProofSuite
from .research_modules import ResearchModuleService from .research_modules import ResearchModuleService
from .retrieval import RetrievalService from .retrieval import RetrievalService
from .runtime import QwenRuntime, RuntimeUnavailableError from .runtime import QwenRuntime, RuntimeUnavailableError
+9 -5
View File
@@ -9,6 +9,8 @@ from .config import Settings, get_settings
from .db import Database from .db import Database
from .schemas import CacheLayerStatus from .schemas import CacheLayerStatus
SEMANTIC_LAYER = "semantic"
class CacheFabric: class CacheFabric:
def __init__(self, settings: Settings | None = None, database: Database | None = None) -> None: def __init__(self, settings: Settings | None = None, database: Database | None = None) -> None:
@@ -16,7 +18,7 @@ class CacheFabric:
self.db = database or Database(self.settings) self.db = database or Database(self.settings)
def semantic_key(self, question: str, profile: str) -> str: def semantic_key(self, question: str, profile: str) -> str:
return hashlib.sha256(f"compiler-v2\n{profile}\n{question}".encode("utf-8")).hexdigest() return hashlib.sha256(f"compiler-v2\n{profile}\n{question}".encode()).hexdigest()
def record_hit(self, layer: str, cache_key: str, bytes_estimate: int = 0, metadata: dict[str, Any] | None = None) -> None: def record_hit(self, layer: str, cache_key: str, bytes_estimate: int = 0, metadata: dict[str, Any] | None = None) -> None:
self.db.log_cache_event(layer, cache_key, "hit", bytes_estimate, metadata) self.db.log_cache_event(layer, cache_key, "hit", bytes_estimate, metadata)
@@ -29,15 +31,17 @@ class CacheFabric:
path.parent.mkdir(parents=True, exist_ok=True) path.parent.mkdir(parents=True, exist_ok=True)
data = json.dumps(payload, ensure_ascii=False, indent=2).encode("utf-8") data = json.dumps(payload, ensure_ascii=False, indent=2).encode("utf-8")
path.write_bytes(data) path.write_bytes(data)
self.db.log_cache_event("semantic", cache_key, "write", len(data), {"path": str(path)}) self.db.log_cache_event(SEMANTIC_LAYER, cache_key, "write", len(data), {"path": str(path)})
def read_semantic_cache(self, cache_key: str) -> dict[str, Any] | None: def read_semantic_cache(self, cache_key: str) -> dict[str, Any] | None:
"""Return the cached payload, or None. The caller traces the event: one compile, one event."""
path = self.settings.cache_dir / "semantic" / f"{cache_key}.json" path = self.settings.cache_dir / "semantic" / f"{cache_key}.json"
if not path.exists(): if not path.exists():
self.record_miss("semantic", cache_key)
return None return None
self.record_hit("semantic", cache_key, path.stat().st_size) try:
return json.loads(path.read_text(encoding="utf-8")) return json.loads(path.read_text(encoding="utf-8"))
except (OSError, json.JSONDecodeError) as error:
raise ValueError(f"{path}: the semantic cache entry is unreadable ({error})") from error
def statuses(self) -> list[CacheLayerStatus]: def statuses(self) -> list[CacheLayerStatus]:
rows = self.db.cache_layer_rows() rows = self.db.cache_layer_rows()
+21 -3
View File
@@ -20,10 +20,12 @@ from .cli_transactive import register as register_transactive_commands
from .config import get_settings from .config import get_settings
from .db import Database from .db import Database
from .embeddings import EmbeddingService from .embeddings import EmbeddingService
from .evals import HashHopEvaluator, PRDProofSuite
from .ingestion import IngestionService from .ingestion import IngestionService
from .memory import MemoryService from .memory import MemoryService
from .profiles import runtime_profile_report from .profiles import runtime_profile_report
from .proofs import HashHopEvaluator, PRDProofSuite
from .proofs.contradictions import CORPUS_NAME, build_contradiction_scenarios, write_corpus
from .proofs.table import render_table
from .research_modules import ResearchModuleService from .research_modules import ResearchModuleService
from .retrieval import RetrievalService from .retrieval import RetrievalService
from .runtime import QwenRuntime from .runtime import QwenRuntime
@@ -232,11 +234,19 @@ def proof_suite(cartridge_id: str | None = None) -> None:
@app.command("latest-proof-suite") @app.command("latest-proof-suite")
def latest_proof_suite() -> None: def latest_proof_suite(json_output: bool = typer.Option(False, "--json")) -> None:
"""Print what the last proof suite claimed and what it actually proved."""
report = PRDProofSuite(get_settings()).latest() report = PRDProofSuite(get_settings()).latest()
if report is None: if report is None:
raise typer.BadParameter(
"no proof suite has been recorded yet; run: ely-eye proof-suite --cartridge-id <id>"
)
if json_output:
typer.echo(report.model_dump_json(indent=2))
else:
typer.echo(render_table(report))
if report.status == "failed":
raise typer.Exit(code=1) raise typer.Exit(code=1)
typer.echo(report.model_dump_json(indent=2))
@app.command("runtime-generation-proof") @app.command("runtime-generation-proof")
@@ -251,6 +261,14 @@ def visual_contradiction_proof() -> None:
typer.echo(check.model_dump_json(indent=2)) typer.echo(check.model_dump_json(indent=2))
@app.command("contradiction-corpus")
def contradiction_corpus(data_dir: Path | None = None) -> None:
"""Write the corpus the contradiction lens is graded on, so it can be read and replaced."""
settings = get_settings()
target = write_corpus((data_dir or settings.data_dir) / CORPUS_NAME)
typer.echo(json_dump({"corpus": str(target), "scenarios": len(build_contradiction_scenarios())}))
@app.command("finalize-cartridge") @app.command("finalize-cartridge")
def finalize_cartridge(cartridge_id: str) -> None: def finalize_cartridge(cartridge_id: str) -> None:
report = CartridgeAssetService(get_settings()).finalize(cartridge_id) report = CartridgeAssetService(get_settings()).finalize(cartridge_id)
+10 -3
View File
@@ -3,7 +3,7 @@ from __future__ import annotations
import hashlib import hashlib
from collections.abc import Iterable from collections.abc import Iterable
from .cache_fabric import CacheFabric from .cache_fabric import SEMANTIC_LAYER, CacheFabric
from .config import Settings, get_settings from .config import Settings, get_settings
from .db import Database from .db import Database
from .retrieval import RetrievalService from .retrieval import RetrievalService
@@ -27,11 +27,18 @@ class ContextCompiler:
def compile(self, question: str, profile: RuntimeProfile) -> CompiledContext: def compile(self, question: str, profile: RuntimeProfile) -> CompiledContext:
cache_key = self.cache.semantic_key(question, profile.value) cache_key = self.cache.semantic_key(question, profile.value)
cached = self.cache.read_semantic_cache(cache_key) cached = self.cache.read_semantic_cache(cache_key)
if cached: if cached is not None:
compiled = CompiledContext.model_validate(cached) compiled = CompiledContext.model_validate(cached)
if compiled.hits: if compiled.hits:
self.cache.record_hit(SEMANTIC_LAYER, cache_key)
return compiled return compiled
# A cached context with no evidence in it is not an answer, so counting it as a hit
# would let an empty cache entry look like a warm cache.
self.cache.record_miss(
SEMANTIC_LAYER, cache_key, metadata={"reason": "cached context has no hits"}
)
else:
self.cache.record_miss(SEMANTIC_LAYER, cache_key)
plan = self.plan(question, profile) plan = self.plan(question, profile)
hits = self.retrieval.search(plan.retrieval_query, plan.evidence_budget_atoms).hits hits = self.retrieval.search(plan.retrieval_query, plan.evidence_budget_atoms).hits
packed_text, token_total = self._pack_hits(hits, plan.token_budget, plan.retrieval_query) packed_text, token_total = self._pack_hits(hits, plan.token_budget, plan.retrieval_query)
File diff suppressed because it is too large. Load diff
+12 -2
View File
@@ -105,16 +105,26 @@ class HashHopProof(BaseModel):
created_at: datetime = Field(default_factory=utc_now) created_at: datetime = Field(default_factory=utc_now)
class ProofCheck(BaseModel): class ProofCheck(BaseModel):
"""One claim, one verdict.
`deferred` means the check is written and runnable but needs something this machine does not
have (model weights, a second source). `removed` means the old check proved nothing and the
claim now waits for a check that can. Both carry a reason and the command that runs the check.
"""
name: str name: str
requirement: str requirement: str
status: Literal["passed", "failed"] status: Literal["passed", "failed", "deferred", "removed"]
evidence: list[str] evidence: list[str]
detail: str detail: str
reason: str = ""
rerun: str = ""
class ProofSuiteReport(BaseModel): class ProofSuiteReport(BaseModel):
proof_id: str proof_id: str
cartridge_id: str cartridge_id: str
status: Literal["passed", "failed"] status: Literal["passed", "failed", "deferred"]
created_at: datetime = Field(default_factory=utc_now) created_at: datetime = Field(default_factory=utc_now)
checks: list[ProofCheck] checks: list[ProofCheck]
artifacts: dict[str, str] artifacts: dict[str, str]
+4 -2
View File
@@ -410,10 +410,12 @@ def resolve_llama_server() -> str | None:
def windows_path_to_wsl(path: Path) -> str: def windows_path_to_wsl(path: Path) -> str:
"""Map a Windows path to the WSL mount a WSL shell can cd into; a POSIX path is already correct."""
resolved = path.resolve() resolved = path.resolve()
drive = resolved.drive.rstrip(":").lower() drive = resolved.drive.rstrip(":").lower()
parts = resolved.parts[1:] if not drive:
return "/mnt/" + drive + "/" + "/".join(parts) return str(resolved)
return "/mnt/" + drive + "/" + "/".join(resolved.parts[1:])
def wsl_quote(value: str) -> str: def wsl_quote(value: str) -> str:
+6
View File
@@ -0,0 +1,6 @@
"""Proof machinery: one module per kind of claim, one verdict per check."""
from .hashhop import HashHopEvaluator
from .suite import PRDProofSuite
__all__ = ["HashHopEvaluator", "PRDProofSuite"]
+224
View File
@@ -0,0 +1,224 @@
"""Draw the HashHop puzzles and read the model's answer back out of them."""
from __future__ import annotations
import hashlib
import json
import random
import re
from pathlib import Path
from typing import Any, Literal
from PIL import Image, ImageDraw, ImageFont
# The four arena positions a model may answer with. Naming them once keeps the puzzle, the parser,
# and the scoring keyed on the same values instead of four spellings in three files.
SlotName = Literal["top-left", "top-right", "bottom-left", "bottom-right"]
SLOTS: tuple[SlotName, ...] = ("top-left", "top-right", "bottom-left", "bottom-right")
ID_LINE_CHARS = 8
CANVAS_BACKGROUND = (8, 10, 14)
def render_visual_hash(item_id: str, path: Path, tile_size: int) -> None:
"""Print the id on the tile, over a pattern derived from the same id.
A pattern alone is not a puzzle: nothing maps a random texture back to a hex id, so the
only way to answer was the ink the renderer painted on the answer. The id is now legible,
which makes the task look, match, and answer.
"""
seed = int(hashlib.sha256(item_id.encode("utf-8")).hexdigest()[:16], 16)
rng = random.Random(seed)
image = Image.new("RGB", (tile_size, tile_size), color=_noise_color(rng))
draw = ImageDraw.Draw(image)
for _ in range(96):
x0 = rng.randrange(tile_size)
y0 = rng.randrange(tile_size)
x1 = min(tile_size, x0 + rng.randrange(4, tile_size // 3))
y1 = min(tile_size, y0 + rng.randrange(4, tile_size // 3))
color = _noise_color(rng)
if rng.random() < 0.5:
draw.rectangle([x0, y0, x1, y1], fill=color)
else:
draw.ellipse([x0, y0, x1, y1], fill=color)
_draw_id(draw, item_id, tile_size)
image.save(path)
def _noise_color(rng: random.Random) -> tuple[int, int, int]:
return (rng.randrange(256), rng.randrange(256), rng.randrange(256))
def _draw_id(draw: ImageDraw.ImageDraw, item_id: str, tile_size: int) -> None:
font = ImageFont.load_default(size=max(12, tile_size // 8))
plate = (
int(tile_size * 0.05),
int(tile_size * 0.16),
int(tile_size * 0.95),
int(tile_size * 0.88),
)
draw.rectangle(plate, fill=(255, 255, 255))
lines = [item_id[start : start + ID_LINE_CHARS] for start in range(0, len(item_id), ID_LINE_CHARS)]
line_height = font.getbbox("AbgJ")[3]
block_top = (plate[1] + plate[3]) / 2 - (len(lines) * line_height) / 2
for index, line in enumerate(lines):
box = font.getbbox(line)
left = (plate[0] + plate[2]) / 2 - (box[2] - box[0]) / 2
draw.text((left, block_top + index * line_height), line, fill=(12, 14, 18), font=font)
def render_visual_hash_arena(
source_path: Path, slot_paths: dict[str, Path], output_path: Path
) -> None:
"""Place the source and the candidates. Nothing marks which candidate is the answer."""
tile = 160
canvas = Image.new("RGB", (920, 560), color=CANVAS_BACKGROUND)
draw = ImageDraw.Draw(canvas)
source_box = (72, 200, 72 + tile, 200 + tile)
slot_boxes = _slot_boxes(520, 704, 76, 324, tile)
paste_visual_hash_tile(canvas, source_path, source_box)
draw.rectangle(source_box, outline=(255, 78, 220), width=8)
for slot, box in slot_boxes.items():
paste_visual_hash_tile(canvas, slot_paths[slot], box)
draw.rectangle(box, outline=(180, 190, 205), width=5)
_save(canvas, output_path)
def render_visual_hash_two_hop_arena(
source_path: Path,
intermediate_slot_paths: dict[str, Path],
target_slot_paths: dict[str, Path],
output_path: Path,
) -> None:
"""Two grids of candidates, no arrow and no ring: the chain has to be read, not seen."""
tile = 136
canvas = Image.new("RGB", (1180, 720), color=CANVAS_BACKGROUND)
draw = ImageDraw.Draw(canvas)
source_box = (64, 292, 64 + tile, 292 + tile)
intermediate_boxes = _slot_boxes(424, 584, 104, 480, tile)
target_boxes = _slot_boxes(864, 1024, 104, 480, tile)
paste_visual_hash_tile(canvas, source_path, source_box)
draw.rectangle(source_box, outline=(255, 78, 220), width=7)
for grid, boxes, outline in (
(intermediate_slot_paths, intermediate_boxes, (140, 215, 255)),
(target_slot_paths, target_boxes, (255, 196, 92)),
):
for slot, box in boxes.items():
paste_visual_hash_tile(canvas, grid[slot], box)
draw.rectangle(box, outline=outline, width=5)
_save(canvas, output_path)
def _slot_boxes(
left_x: int, right_x: int, top_y: int, bottom_y: int, tile: int
) -> dict[str, tuple[int, int, int, int]]:
return {
"top-left": (left_x, top_y, left_x + tile, top_y + tile),
"top-right": (right_x, top_y, right_x + tile, top_y + tile),
"bottom-left": (left_x, bottom_y, left_x + tile, bottom_y + tile),
"bottom-right": (right_x, bottom_y, right_x + tile, bottom_y + tile),
}
def _save(canvas: Image.Image, output_path: Path) -> None:
output_path.parent.mkdir(parents=True, exist_ok=True)
canvas.save(output_path)
def paste_visual_hash_tile(canvas: Image.Image, path: Path, box: tuple[int, int, int, int]) -> None:
tile = Image.open(path).convert("RGB").resize((box[2] - box[0], box[3] - box[1]), Image.Resampling.LANCZOS)
canvas.paste(tile, box[:2])
def extract_visual_target_slot(text: str) -> SlotName | None:
stripped = text.strip()
payload: dict[str, Any] | None
try:
parsed = json.loads(stripped)
payload = parsed if isinstance(parsed, dict) else None
except json.JSONDecodeError:
payload = extract_json_object(stripped)
if isinstance(payload, dict):
for key in ("target_slot", "final_slot", "slot", "answer"):
value = payload.get(key)
if isinstance(value, str):
slot = normalize_visual_slot(value)
if slot:
return slot
return normalize_visual_slot(stripped)
def extract_hashhop_target(text: str) -> str | None:
"""Read the id the model answered with, from JSON or from loose prose."""
stripped = text.strip()
try:
payload = json.loads(stripped)
except json.JSONDecodeError:
payload = extract_json_object(stripped)
if isinstance(payload, dict):
for key in ("answer", "target", "target_id", "final_target_id"):
value = payload.get(key)
if isinstance(value, str):
candidate = normalize_hash_id(value)
if candidate:
return candidate
match = re.search(r"\b[a-fA-F0-9]{32}\b", stripped)
return match.group(0).lower() if match else None
def normalize_hash_id(value: str) -> str | None:
match = re.search(r"\b[a-fA-F0-9]{32}\b", value)
return match.group(0).lower() if match else None
def extract_visual_intermediate_slot(text: str) -> SlotName | None:
stripped = text.strip()
try:
parsed = json.loads(stripped)
payload = parsed if isinstance(parsed, dict) else None
except json.JSONDecodeError:
payload = extract_json_object(stripped)
if isinstance(payload, dict):
for key in ("intermediate_slot", "middle_slot", "first_hop_slot"):
value = payload.get(key)
if isinstance(value, str):
slot = normalize_visual_slot(value)
if slot:
return slot
return None
def extract_json_object(text: str) -> dict[str, Any] | None:
start = text.find("{")
end = text.rfind("}")
if start < 0 or end <= start:
return None
try:
payload = json.loads(text[start : end + 1])
except json.JSONDecodeError:
return None
return payload if isinstance(payload, dict) else None
def normalize_visual_slot(value: str) -> SlotName | None:
normalized = re.sub(r"[^a-z]+", "-", value.lower()).strip("-")
aliases: dict[str, SlotName] = {
"top-left": "top-left",
"upper-left": "top-left",
"left-top": "top-left",
"top-right": "top-right",
"upper-right": "top-right",
"right-top": "top-right",
"bottom-left": "bottom-left",
"lower-left": "bottom-left",
"left-bottom": "bottom-left",
"bottom-right": "bottom-right",
"lower-right": "bottom-right",
"right-bottom": "bottom-right",
}
if normalized in aliases:
return aliases[normalized]
for alias, slot in aliases.items():
if re.search(rf"\b{re.escape(alias)}\b", normalized):
return slot
return None
@@ -0,0 +1,404 @@
"""Cartridge assets, the memory capsule, replay, DNA, cache trace, and repository coverage.
Moved out of suite.py so the suite order stays readable; each method is a check the
suite runs, and the suite class mixes these in.
"""
from __future__ import annotations
import json
import secrets
import shutil
from pathlib import Path
from typing import Any
from ..cache_fabric import CacheFabric
from ..cartridge import CartridgeService
from ..cartridge_assets import CartridgeAssetService, merkle_root
from ..compiler import ContextCompiler
from ..config import Settings
from ..db import Database
from ..evaluation_schemas import (
ProofCheck,
)
from ..ingestion import SUPPORTED_CODE_EXTENSIONS, build_repository_context, find_git_root
from ..schemas import (
CartridgeManifest,
RuntimeProfile,
)
# A fixed puzzle count per hop depth. The old suite re-rolled until the running rate crossed its
from .checks_common import (
_semantic_counters,
)
from .report import (
compiled_context_digest,
parquet_row_count,
read_memory_capsule,
validated_segment_hash,
write_json,
)
from .repository_checks import discover_repository_files, project_root
class CartridgeChecks:
"""Cartridge assets, the memory capsule, replay, DNA, cache trace, and repository coverage."""
settings: Settings
db: Database
cartridges: CartridgeService
def _cartridge_assets_check(
self,
cartridge_id: str,
cartridge_root: Path,
proof_root: Path,
) -> tuple[ProofCheck, CartridgeManifest]:
report = CartridgeAssetService(self.settings, self.db).finalize(cartridge_id)
source_report = cartridge_root / "cartridge_assets.json"
proof_report = proof_root / "cartridge_assets.json"
shutil.copy2(source_report, proof_report)
rows = self.db.list_cartridges()
manifest_json = next(row["manifest_json"] for row in rows if row["cartridge_id"] == cartridge_id)
manifest = CartridgeManifest.model_validate_json(manifest_json)
expected = {
"text_vectors",
"visual_vectors",
"kv_snapshots",
"memory_capsule",
"memory_capsule_index",
"ttt_vl_adapter",
"visual_mtp_head",
"cartridge_assets",
}
by_name = {asset.name: asset for asset in report.assets}
visual_vectors = by_name.get("visual_vectors")
memory_capsule = by_name.get("memory_capsule")
gaps: list[str] = []
if report.status != "ready":
gaps.append(f"the asset report says {report.status}")
absent = sorted(expected - set(manifest.artifacts))
if absent:
gaps.append("not registered in the manifest: " + ", ".join(absent))
empty = [asset.name for asset in report.assets if asset.size_bytes <= 0]
if empty:
gaps.append("zero-byte assets: " + ", ".join(empty))
if visual_vectors is None or visual_vectors.item_count <= 0:
gaps.append("visual_vectors holds no vectors")
if memory_capsule is None or memory_capsule.item_count <= 0:
gaps.append("memory_capsule holds no segments")
valid = not gaps
return (
ProofCheck(
name="Cartridge Physical Assets",
requirement="PRD 8.3 requires text vectors, non-empty visual vectors, KV snapshots, a 100M memory capsule, TTT-VL adapter weights, Visual-MTP head weights, and eval proofs inside the Context Cartridge.",
status="passed" if valid else "failed",
evidence=[str(proof_report), str(cartridge_root)],
detail="materialized assets: " + ", ".join(asset.name for asset in report.assets),
reason="; ".join(gaps),
rerun="ely-eye finalize-cartridge <id>, then ely-eye proof-suite --cartridge-id <id>",
),
manifest,
)
def _memory_capsule_check(self, cartridge_root: Path, proof_root: Path) -> ProofCheck:
capsule_path = cartridge_root / "memory_capsule.json.zst"
index_path = cartridge_root / "memory_capsule_index.json"
artifact = proof_root / "memory_capsule.json"
payload: dict[str, Any] = {
"capsule_path": str(capsule_path),
"index_path": str(index_path),
"status": "failed",
}
valid = False
try:
capsule = read_memory_capsule(capsule_path)
index = json.loads(index_path.read_text(encoding="utf-8")) if index_path.exists() else {}
raw_segments = capsule.get("segments")
if not isinstance(raw_segments, list):
raise ValueError(f"{capsule_path}: the memory capsule carries no segments list") # noqa: TRY004 # malformed stored data, not a caller type error
segments: list[dict[str, Any]] = [segment for segment in raw_segments if isinstance(segment, dict)]
if len(segments) != len(raw_segments):
raise ValueError(f"{capsule_path}: a memory capsule segment is not an object")
segment_hashes = [validated_segment_hash(segment) for segment in segments]
token_total = sum(int(segment.get("token_count") or 0) for segment in segments)
computed_merkle = merkle_root(segment_hashes)
valid = (
capsule.get("format") == "ely-eye-memory-capsule-v1"
and int(capsule.get("token_equivalent") or 0) >= self.settings.library_target_tokens
and int(capsule.get("segment_count") or 0) == len(segments)
and token_total == int(capsule.get("token_equivalent") or -1)
and computed_merkle == capsule.get("segment_merkle_root")
and index.get("segment_merkle_root") == capsule.get("segment_merkle_root")
and int(index.get("token_equivalent") or 0) == int(capsule.get("token_equivalent") or -1)
and int(capsule.get("source_atom_count") or 0) > 0
and all(segment_hashes)
)
payload.update(
{
"status": "passed" if valid else "failed",
"token_equivalent": capsule.get("token_equivalent"),
"segment_count": capsule.get("segment_count"),
"source_atom_count": capsule.get("source_atom_count"),
"source_token_equivalent": capsule.get("source_token_equivalent"),
"segment_merkle_root": capsule.get("segment_merkle_root"),
"computed_merkle_root": computed_merkle,
"first_segment": segments[0] if segments else None,
"last_segment": segments[-1] if segments else None,
}
)
except Exception as exc: # noqa: BLE001 # a probe records its failure instead of crashing the proof run
payload["error"] = str(exc)
write_json(artifact, payload)
return ProofCheck(
name="100M Memory Capsule",
requirement="PRD 2.2, 7.3, 8.3, and 14.3 require a 10M-100M token-equivalent Context Cartridge memory capsule with verifiable retrieval commitments.",
status="passed" if valid else "failed",
evidence=[str(artifact), str(capsule_path), str(index_path)],
detail=(
f"{payload.get('token_equivalent')} token-equivalent memory capsule with "
f"{payload.get('segment_count')} committed segments"
),
)
def _cartridge_replay_check(
self,
cartridge_id: str,
cartridge_root: Path,
manifest: CartridgeManifest,
proof_root: Path,
) -> ProofCheck:
atoms_path = cartridge_root / manifest.artifacts["atoms"]
sources_path = cartridge_root / manifest.artifacts["sources"]
sparse_path = cartridge_root / manifest.artifacts["sparse_index"]
graph_path = cartridge_root / manifest.artifacts["temporal_graph"]
computed_dna = self.cartridges.compute_dna(cartridge_root)
atom_rows = parquet_row_count(atoms_path)
try:
sources = json.loads(sources_path.read_text(encoding="utf-8")) if sources_path.exists() else []
except (OSError, json.JSONDecodeError) as error:
raise ValueError(f"{sources_path}: the cartridge source list is unreadable ({error})") from error
question = "Which Ely-Eye PRD requirements prove long context memory, HashHop, and adapters?"
compiler = ContextCompiler(self.settings, self.db)
artifact = proof_root / "cartridge_replay.json"
# The replay must come out of the cartridge, not out of whatever the live store happens
# to hold: mounting is what makes the cartridge the retrieval scope (retrieval scopes by
# the mounted set), so an unmounted replay would prove only that compiling is stable.
try:
self.cartridges.mount(cartridge_id)
except ValueError as error:
# The KV fingerprint gate refuses to mount a cartridge whose model snapshot this
# machine cannot read. A missing input is not a failed claim, so the check reports
# the refusal instead of crashing the suite.
write_json(artifact, {"verdict": "deferred", "why": str(error)})
return ProofCheck(
name="Context Cartridge Replay",
requirement="PRD 14.2 requires the same cartridge to load reproducibly and produce consistent replay evidence.",
status="deferred",
evidence=[str(artifact), str(cartridge_root / "manifest.json")],
detail=str(error),
reason="the cartridge records a model snapshot this machine cannot verify, so the replay cannot be attempted",
rerun="set ELY_EYE_MODEL_DIR to the snapshot the cartridge was built against, then ely-eye proof-suite --cartridge-id <id>",
)
try:
replay_a = compiler.compile(question, RuntimeProfile.library_100m)
replay_b = compiler.compile(question, RuntimeProfile.library_100m)
finally:
self.cartridges.unmount(cartridge_id)
digest_a = compiled_context_digest(replay_a)
digest_b = compiled_context_digest(replay_b)
payload = {
"cartridge_id": cartridge_id,
"manifest_atom_count": manifest.atom_count,
"parquet_atom_count": atom_rows,
"manifest_source_count": manifest.source_count,
"source_count": len(sources),
"dna_manifest": manifest.dna,
"dna_computed": computed_dna,
"artifacts": {
"atoms": str(atoms_path),
"sources": str(sources_path),
"sparse_index": str(sparse_path),
"temporal_graph": str(graph_path),
},
"replay": {
"question": question,
"digest_a": digest_a,
"digest_b": digest_b,
"hit_ids_a": [hit.atom.atom_id for hit in replay_a.hits],
"hit_ids_b": [hit.atom.atom_id for hit in replay_b.hits],
"cache_trace_a": replay_a.cache_trace_id,
"cache_trace_b": replay_b.cache_trace_id,
},
}
artifact = proof_root / "cartridge_replay.json"
write_json(artifact, payload)
cartridge_sources = {str(entry.get("source_id", "")) for entry in sources}
answered_from_cartridge = bool(replay_a.hits) and all(
hit.atom.source_id in cartridge_sources for hit in replay_a.hits
)
valid = (
atoms_path.exists()
and sources_path.exists()
and sparse_path.exists()
and graph_path.exists()
and atom_rows == manifest.atom_count
and len(sources) == manifest.source_count
and computed_dna == manifest.dna
and answered_from_cartridge
and digest_a == digest_b
)
return ProofCheck(
name="Context Cartridge Replay",
requirement="PRD 14.2 requires the same cartridge to load reproducibly and produce consistent replay evidence.",
status="passed" if valid else "failed",
evidence=[str(artifact), str(cartridge_root / "manifest.json")],
detail=(
f"{atom_rows} atoms, {len(sources)} sources, replay digest {digest_a}, "
f"{len(replay_a.hits)} hits answered from the mounted cartridge"
),
rerun="ely-eye proof-suite --cartridge-id <id>",
)
def _repository_input_check(self, proof_root: Path) -> ProofCheck:
root = project_root()
files = discover_repository_files(root)
code_files = [path for path in files if path.suffix.lower() in SUPPORTED_CODE_EXTENSIONS]
context = build_repository_context(root, files, code_files, find_git_root(root))
artifact = proof_root / "repository_input.json"
write_json(artifact, context)
call_graph = context["code"]["call_graph"]
git_context = context["git"]
issue_pr_history = context["issue_pr_history"]
# Building a context object from files on disk is not evidence the repository reached the
# store: the claim is that the repository is queryable, so the store has to hold it.
stored_sources = [source for source in self.db.list_sources() if source.path.startswith(str(root))]
stored_atoms = self.db.atom_count()
artifact = proof_root / "repository_input.json"
payload = dict(context)
payload["store_evidence"] = {
"sources_under_project_root": len(stored_sources),
"source_ids": [source.source_id for source in stored_sources[:20]],
"atoms_in_store": stored_atoms,
}
write_json(artifact, payload)
valid = (
context["structure"]["indexed_file_count"] > 0
and context["code"]["indexed_file_count"] > 0
and bool(call_graph)
and bool(git_context.get("available"))
and bool(git_context.get("recent_commits"))
and issue_pr_history.get("source") == "local_git_commit_history"
and bool(stored_sources)
and stored_atoms > 0
)
return ProofCheck(
name="Repository Input Coverage",
requirement="PRD 10.1 requires code repository structure indexing, call graph extraction, and issue/PR history association.",
status="passed" if valid else "failed",
evidence=[str(artifact)],
detail=(
f"{context['structure']['indexed_file_count']} files indexed; "
f"{context['code']['indexed_file_count']} code files; "
f"{len(call_graph)} call edges; "
f"{len(git_context.get('recent_commits') or [])} git commits; "
f"{len(stored_sources)} sources and {stored_atoms} atoms in the store"
),
reason="" if valid else "the repository context was built but the store holds no atoms for it",
rerun="ely-eye ingest . && ely-eye proof-suite --cartridge-id <id>",
)
def _memory_dna_check(
self,
cartridge_root: Path,
manifest: CartridgeManifest,
proof_root: Path,
) -> ProofCheck:
computed = self.cartridges.compute_dna(cartridge_root)
payload = {
"manifest_dna": manifest.dna,
"computed_dna": computed,
"formula": "sha256(sorted cartridge artifacts excluding manifest.json)",
"artifact_count": sum(1 for path in cartridge_root.rglob("*") if path.is_file()),
}
artifact = proof_root / "memory_dna.json"
write_json(artifact, payload)
return ProofCheck(
name="Memory DNA",
requirement="PRD 11.14 requires a reproducible Memory DNA over adapter delta, evidence graph, retrieval index, and eval proofs.",
status="passed" if manifest.dna == computed else "failed",
evidence=[str(artifact), str(cartridge_root)],
detail=f"manifest DNA {manifest.dna}",
)
def _cache_trace_check(self, proof_root: Path) -> ProofCheck:
"""Ask the cache the same question twice and require the second answer to be a hit.
The old check passed when any layer had any row, which a single `forget` could satisfy.
The claim in PRD 14.2 is that hit, miss, write and replay state are visible, so the check
compiles a question nobody has asked, compiles it again, and requires the semantic layer's
counters to move by exactly one miss then one hit.
"""
compiler = ContextCompiler(self.settings, self.db)
fabric = CacheFabric(self.settings, self.db)
probe = self.db.list_atoms(limit=1)
if not probe:
artifact = proof_root / "cache_trace.json"
write_json(artifact, {"verdict": "failed", "why": "the store holds no atoms"})
return ProofCheck(
name="Cache Trace",
requirement="PRD 14.2 requires cache and memory proof with visible hit, miss, write, and replay state.",
status="failed",
evidence=[str(artifact)],
detail="the store holds no atoms, so there is nothing for the cache to answer",
reason="an empty store answers every question with an empty context, which would make the two compiles agree for the wrong reason",
rerun="ely-eye remember or ely-eye ingest first, then re-run this proof",
)
# The nonce keeps the key unique; the quoted text keeps the question answerable, so a pass
# means the cache served a real context rather than two identical empty ones.
question = f"{probe[0].text[:60]} cache proof {secrets.token_hex(6)}"
before = _semantic_counters(fabric)
first = compiler.compile(question, RuntimeProfile.library_100m)
middle = _semantic_counters(fabric)
second = compiler.compile(question, RuntimeProfile.library_100m)
after = _semantic_counters(fabric)
digest_first = compiled_context_digest(first)
digest_second = compiled_context_digest(second)
payload = {
"question": question,
"counters": {"before": before, "after_first": middle, "after_second": after},
"digest_first": digest_first,
"digest_second": digest_second,
"cache_trace_first": first.cache_trace_id,
"cache_trace_second": second.cache_trace_id,
}
artifact = proof_root / "cache_trace.json"
write_json(artifact, payload)
miss_recorded = middle["miss"] - before["miss"] == 1 and middle["hit"] - before["hit"] == 0
hit_recorded = after["hit"] - middle["hit"] == 1
same_answer = digest_first == digest_second and bool(first.hits)
valid = miss_recorded and hit_recorded and same_answer
return ProofCheck(
name="Cache Trace",
requirement="PRD 14.2 requires cache and memory proof with visible hit, miss, write, and replay state.",
status="passed" if valid else "failed",
evidence=[str(artifact)],
detail=(
f"semantic layer counters miss {before['miss']}→{middle['miss']}→{after['miss']}, "
f"hit {before['hit']}→{middle['hit']}→{after['hit']}, replay digest {digest_first}"
),
reason="" if valid else "the second compile was not recorded as a cache hit",
rerun="ely-eye proof-suite --cartridge-id <id>",
)
def _resolve_cartridge(self, cartridge_id: str | None) -> dict[str, Any]:
rows = self.db.list_cartridges()
if not rows:
raise ValueError("No Context Cartridge is available.")
if cartridge_id is None:
return rows[0]
for row in rows:
if row["cartridge_id"] == cartridge_id:
return row
raise ValueError(f"Unknown cartridge: {cartridge_id}")
@@ -0,0 +1,65 @@
"""Shared verdict helpers for the proof checks.
Kept out of suite.py so the check modules can import them without importing the suite.
"""
from __future__ import annotations
from pathlib import Path
from ..cache_fabric import SEMANTIC_LAYER, CacheFabric
from ..config import Settings
from ..evaluation_schemas import (
ProofCheck,
)
from .report import (
write_json,
)
# A fixed puzzle count per hop depth. The old suite re-rolled until the running rate crossed its
HASHHOP_ATTEMPTS = 8
GOLD_ADAPTERS = (
"HME-Core-LoRA",
"HME-Vision-LoRA",
"HME-TTT-VL",
"HME-Visual-MTP",
"HME-Router",
"HME-Retrieval",
)
def _deferred_without_model(
settings: Settings, artifact: Path, name: str, requirement: str, rerun: str
) -> ProofCheck | None:
"""A check that needs weights proves nothing on a machine that has no weights.
Calling that a failure would blame the machine; calling it a pass would be a lie. The suite
records what is missing and the command that runs the check once the weights arrive.
"""
model_dir = settings.model_dir
if model_dir is not None and model_dir.exists():
return None
write_json(
artifact,
{"status": "deferred", "reason": "no local model weights", "model_dir": str(model_dir)},
)
return ProofCheck(
name=name,
requirement=requirement,
status="deferred",
evidence=[str(artifact)],
detail=f"model_dir={model_dir}",
reason="the generator or encoder this check measures is not installed on this machine",
rerun=rerun,
)
def _semantic_counters(fabric: CacheFabric) -> dict[str, int]:
"""Hit and miss counts for the one cache layer that exists; zero when the layer has no rows."""
for layer in fabric.statuses():
if layer.layer == SEMANTIC_LAYER:
return {"hit": layer.hit_count, "miss": layer.miss_count}
return {"hit": 0, "miss": 0}
@@ -0,0 +1,270 @@
"""Runtime adapter binding, gold-adapter generation, launch profiles, and the removed module check.
Moved out of suite.py so the suite order stays readable; each method is a check the
suite runs, and the suite class mixes these in.
"""
from __future__ import annotations
from pathlib import Path
from typing import Any
from ..compiler import ContextCompiler
from ..config import Settings
from ..db import Database
from ..evaluation_schemas import (
ProofCheck,
)
from ..evidence_graph import EvidenceGraphService
from ..profiles import runtime_profile_report
from ..runtime import QwenRuntime, resolve_runtime_adapter
from ..schemas import (
RuntimeProfile,
TrainingAdapterKind,
)
from ..verifier import Verifier
# A fixed puzzle count per hop depth. The old suite re-rolled until the running rate crossed its
from .checks_common import (
GOLD_ADAPTERS,
_deferred_without_model,
)
from .report import (
compact_generation_context,
write_json,
)
from .training_trace import (
count_safetensor_keys,
peft_config_loads,
)
class RuntimeChecks:
"""Runtime adapter binding, gold-adapter generation, launch profiles, and the removed module check."""
settings: Settings
db: Database
def _runtime_adapter_check(self, proof_root: Path) -> ProofCheck:
artifact = proof_root / "runtime_adapter.json"
deferred = _deferred_without_model(
self.settings,
artifact,
"Runtime Adapter Binding",
"PRD 18 requires the local model package to run with the trained adapter, and PRD 12.1 requires HME-Core-LoRA to be usable by the Qwen runtime.",
"ely-eye runtime-generation-proof with ELY_EYE_MODEL_DIR set",
)
if deferred is not None:
return deferred
runtime = QwenRuntime(self.settings)
status = runtime.status()
adapter = resolve_runtime_adapter(self.settings)
weight_path = adapter.path / "adapter_model.safetensors" if adapter else None
payload = {
"runtime_status": status.model_dump(mode="json"),
"resolved_adapter": {
"path": str(adapter.path) if adapter else None,
"kind": adapter.manifest.kind.value if adapter else None,
"adapter_id": adapter.manifest.adapter_id if adapter else None,
"sha256": adapter.manifest.sha256 if adapter else None,
"base_model": adapter.manifest.base_model if adapter else None,
"weight_path": str(weight_path) if weight_path else None,
"safetensor_keys": count_safetensor_keys(weight_path) if weight_path else 0,
"peft_config_ok": peft_config_loads(adapter.path) if adapter else False,
},
}
artifact = proof_root / "runtime_adapter.json"
write_json(artifact, payload)
valid = (
status.available
and adapter is not None
and adapter.manifest.kind == TrainingAdapterKind.hme_core_lora
and adapter.manifest.base_model == self.settings.model_id
and status.adapter_path == str(adapter.path)
and weight_path is not None
and count_safetensor_keys(weight_path) > 0
and peft_config_loads(adapter.path)
)
return ProofCheck(
name="Runtime Adapter Binding",
requirement="PRD 18 requires the local model package to run with the trained adapter, and PRD 12.1 requires HME-Core-LoRA to be usable by the Qwen runtime.",
status="passed" if valid else "failed",
evidence=[str(artifact)],
detail=(
f"{status.backend} runtime resolves {adapter.manifest.kind.value} at {adapter.path}"
if adapter
else "runtime adapter resolution is empty"
),
)
def _runtime_generation_check(self, proof_root: Path) -> ProofCheck:
artifact = proof_root / "runtime_generation.json"
deferred = _deferred_without_model(
self.settings,
artifact,
"Runtime Adapter Generation",
"PRD 12.1 and PRD 18 require the trained HME-Core-LoRA adapter to be loaded by the local Qwen runtime and used for an evidence-cited generation.",
"ely-eye proof-suite --cartridge-id <id> with ELY_EYE_MODEL_DIR set",
)
if deferred is not None:
return deferred
retrieval_question = (
"Using the Ely-Eye PRD evidence, state the PRD 12.1 local training adapter "
"requirements for HME-Core-LoRA, HME-Vision-LoRA, HME-TTT-VL, "
"HME-Visual-MTP, HME-Router, and HME-Retrieval. Return JSON with atom id "
"citations."
)
proof_settings = self.settings.model_copy(update={"max_new_tokens": 256, "temperature": 0.0})
runtime = QwenRuntime(proof_settings)
payload: dict[str, Any] = {
"question": retrieval_question,
"status": "failed",
}
try:
compiler = ContextCompiler(proof_settings, self.db)
context = compiler.compile(retrieval_question, RuntimeProfile.library_100m)
context = compact_generation_context(context, "12.1")
if not context.hits:
raise RuntimeError("No PRD text evidence was available for runtime generation proof.")
generation_question = (
"According to the retrieved PRD evidence, which local training adapters does "
"PRD 12.1 require? Answer with one compact JSON object: a \"citations\" field "
"naming the atom ids you actually used, and a \"sentence\" field listing them."
)
payload["generation_question"] = generation_question
status = runtime.status()
adapter = resolve_runtime_adapter(proof_settings)
generation = runtime.generate(generation_question, context)
answer, citations, citation_report = Verifier().verify_answer(generation.text, context)
claim_id = EvidenceGraphService(proof_settings, self.db).record_answer(
generation_question,
answer,
citation_report,
context,
)
payload.update(
{
"status": "passed",
"runtime_status": status.model_dump(mode="json"),
"adapter": {
"path": generation.adapter_path,
"kind": generation.adapter_kind,
"adapter_id": generation.adapter_id,
"sha256": generation.adapter_sha256,
},
"tokens": {
"input": generation.input_tokens,
"output": generation.output_tokens,
},
"context": {
"profile": context.plan.profile.value,
"hit_ids": [hit.atom.atom_id for hit in context.hits],
"token_equivalent": context.token_equivalent,
"cache_trace_id": context.cache_trace_id,
},
"raw_generation": generation.text,
"verified_answer": answer,
"citations": citations,
"evidence_graph_claim_id": claim_id,
"verifier": citation_report.model_dump(mode="json"),
}
)
named = [name for name in GOLD_ADAPTERS if name in answer]
cited_atoms = [
hit.atom for hit in context.hits if hit.atom.atom_id in set(citations)
]
supported = [atom for atom in cited_atoms if sum(name in (atom.text or "") for name in GOLD_ADAPTERS) >= 3]
valid = (
status.available
and generation.backend == "transformers"
and adapter is not None
and generation.adapter_path == str(adapter.path)
and generation.adapter_kind == TrainingAdapterKind.hme_core_lora.value
and generation.adapter_sha256 == adapter.manifest.sha256
and bool(context.hits)
and bool(generation.text.strip())
and (generation.output_tokens or 0) > 0
and len(named) >= 5
and bool(citations)
and citation_report.citation_accuracy == 1.0
and bool(supported)
)
payload["answer_adapters"] = named
payload["cited_atoms"] = [atom.atom_id for atom in cited_atoms]
payload["supporting_citations"] = [atom.atom_id for atom in supported]
if not valid:
payload["status"] = "failed"
write_json(artifact, payload)
return ProofCheck(
name="Runtime Adapter Generation",
requirement="PRD 12.1 and PRD 18 require the trained HME-Core-LoRA adapter to be loaded by the local Qwen runtime and used for an evidence-cited generation.",
status="passed" if valid else "failed",
evidence=[str(artifact)],
detail=(
f"{generation.backend} generated {generation.output_tokens} tokens with "
f"{generation.adapter_kind} citation accuracy "
f"{citation_report.citation_accuracy:.2f}"
),
)
except Exception as exc: # noqa: BLE001 # a probe records its failure instead of crashing the proof run
payload["error"] = str(exc)
write_json(artifact, payload)
return ProofCheck(
name="Runtime Adapter Generation",
requirement="PRD 12.1 and PRD 18 require the trained HME-Core-LoRA adapter to be loaded by the local Qwen runtime and used for an evidence-cited generation.",
status="failed",
evidence=[str(artifact)],
detail=f"runtime generation failed: {exc}",
)
finally:
runtime.unload()
def _runtime_profile_check(self, proof_root: Path) -> ProofCheck:
report = runtime_profile_report()
artifact = proof_root / "runtime_profiles.json"
artifact.write_text(report.model_dump_json(indent=2), encoding="utf-8")
required_runtimes = {"SGLang", "vLLM", "KTransformers", "llama.cpp"}
runtimes = {profile.runtime for profile in report.profiles}
gaps = [f"{item.name}: {item.detail}" for item in report.validations if item.status == "missing"]
unregistered = sorted(required_runtimes - runtimes)
if unregistered:
gaps.append("no profile registered for: " + ", ".join(unregistered))
if not gaps and report.status != "ready":
gaps.append(f"the profile report says {report.status}")
valid = not gaps
return ProofCheck(
name="Runtime Profile Delivery",
requirement="PRD 13.1 requires SGLang as the main runtime plus vLLM, KTransformers, and llama.cpp deployment profiles.",
status="passed" if valid else "failed",
evidence=[str(artifact)],
detail="registered runtimes: " + ", ".join(profile.name for profile in report.profiles),
reason="; ".join(gaps),
rerun="install the launcher in the environment the profile probes (the probe command is in runtime_profiles.json), then ely-eye runtime-profiles",
)
def _research_module_check(self, proof_root: Path) -> ProofCheck:
"""The old version of this check could not fail, so it proved nothing.
It compiled a query, asked the research-module service for eight module reports, and
passed when every list was non-empty. The module vectors it ranks with are SHA256-derived
placeholders, so a non-empty list is a property of the loop, not of the system.
"""
artifact = proof_root / "research_modules.json"
write_json(
artifact,
{
"claim": "PRD 11 research modules",
"verdict": "removed",
"why": "the check asserted non-empty lists built from SHA256-derived placeholder vectors",
},
)
return ProofCheck(
name="Research Module Delivery",
requirement="PRD 11 requires V-NSA, DVKV, X-Modal KV Sharing, Speculative Context Prefetch, Predictive KV Eviction, Learned Evidence Graph, Differentiable Retrieval Adapter, and Sleep-Time Visual Consolidation.",
status="removed",
evidence=[str(artifact)],
detail="no measurable claim exists per module; the previous check passed on non-empty lists",
reason="the check could not fail: eight named modules produced non-empty lists by construction",
rerun="write one measurable claim per module, then re-add the check",
)
@@ -0,0 +1,232 @@
"""Adapter training and the learned-memory adapters bound into a cartridge.
Moved out of suite.py so the suite order stays readable; each method is a check the
suite runs, and the suite class mixes these in.
"""
from __future__ import annotations
from pathlib import Path
from typing import Any
from ..config import Settings
from ..db import Database
from ..evaluation_schemas import (
ProofCheck,
)
from ..schemas import (
AdapterManifest,
TrainingAdapterKind,
)
from ..training import (
safetensor_weight_stats,
sha256_file,
sha256_tree,
)
# A fixed puzzle count per hop depth. The old suite re-rolled until the running rate crossed its
from .report import (
read_json_or_empty,
write_json,
)
from .training_trace import (
count_safetensor_keys,
peft_config_loads,
validate_training_contract,
validate_training_proof,
validate_training_trace,
)
class TrainingChecks:
"""Adapter training and the learned-memory adapters bound into a cartridge."""
settings: Settings
db: Database
required_adapters: tuple[TrainingAdapterKind, ...]
def _adapter_training_check(self, cartridge_id: str, cartridge_root: Path, proof_root: Path) -> ProofCheck:
rows: list[dict[str, Any]] = []
missing: list[str] = []
manifests = self._adapter_manifests(cartridge_id)
for kind in self.required_adapters:
item = manifests.get(kind)
if item is None:
missing.append(f"{kind.value}: no adapter manifest")
continue
manifest, adapter_root = item
weight_path = adapter_root / "adapter_model.safetensors"
dataset_path = Path(manifest.dataset_path)
cartridge_adapter = cartridge_root / "adapters" / kind.value / "adapter_manifest.json"
weight_report = safetensor_weight_stats(weight_path)
keys = int(weight_report["tensor_count"])
summary = read_json_or_empty(adapter_root / "training_summary.json")
summary_weight_sha = summary.get("adapter_weight_sha256")
summary_weight_sha_ok = (
isinstance(summary_weight_sha, str) and summary_weight_sha == weight_report["sha256"]
)
manifest_weight_sha_ok = (
isinstance(manifest.adapter_weight_sha256, str)
and manifest.adapter_weight_sha256 == weight_report["sha256"]
)
manifest_weight_stats_ok = (
manifest.adapter_tensor_count == weight_report["tensor_count"]
and manifest.adapter_lora_tensor_count == weight_report["lora_tensor_count"]
and manifest.adapter_total_elements == weight_report["total_elements"]
and manifest.adapter_nonzero_elements == weight_report["nonzero_elements"]
and manifest.adapter_nonzero_elements > 0
and manifest.adapter_lora_tensor_count > 0
and manifest.adapter_weights_finite
)
peft_ok = peft_config_loads(adapter_root)
dataset_sha_ok = dataset_path.exists() and sha256_file(dataset_path) == manifest.dataset_sha256
tree_sha_ok = sha256_tree(adapter_root) == manifest.sha256
cartridge_bound = cartridge_adapter.exists()
trace_report = validate_training_trace(manifest, adapter_root)
proof_report = validate_training_proof(manifest, adapter_root)
contract_report = validate_training_contract(manifest)
# Named conditions, so a failure can say which promise broke instead of listing the
# adapters that happened to be present.
conditions: list[tuple[str, bool]] = [
("sample_count", manifest.sample_count > 0),
("max_steps", manifest.max_steps > 0),
("trainable_params", manifest.trainable_params > 0),
("final_loss recorded", manifest.final_loss is not None),
("safetensors readable", weight_report["valid"]),
("weight sha256 matches the training summary", summary_weight_sha_ok),
("weight sha256 matches the manifest", manifest_weight_sha_ok),
("weight statistics match the manifest", manifest_weight_stats_ok),
("peft config loads", peft_ok),
("dataset sha256 matches", dataset_sha_ok),
("adapter tree sha256 matches", tree_sha_ok),
("adapter is bound into the cartridge", cartridge_bound),
("training trace verifies", trace_report["valid"]),
("training proof verifies", proof_report["valid"]),
("training contract verifies", contract_report["valid"]),
]
valid = all(ok for _, ok in conditions)
if not valid:
gaps = ", ".join(name for name, ok in conditions if not ok)
missing.append(f"{kind.value}: {gaps}")
rows.append(
{
"kind": kind.value,
"adapter": str(adapter_root),
"dataset": str(dataset_path),
"sample_count": manifest.sample_count,
"max_steps": manifest.max_steps,
"trainable_params": manifest.trainable_params,
"final_loss": manifest.final_loss,
"safetensor_keys": keys,
"adapter_weight_sha256": weight_report["sha256"],
"adapter_weight_sha256_ok": summary_weight_sha_ok and manifest_weight_sha_ok,
"adapter_weight_stats_ok": manifest_weight_stats_ok,
"adapter_weight_stats": weight_report,
"dataset_sha256_ok": dataset_sha_ok,
"adapter_sha256_ok": tree_sha_ok,
"peft_config_ok": peft_ok,
"cartridge_bound": cartridge_bound,
"training_contract": contract_report,
"training_trace": trace_report,
"training_proof": proof_report,
}
)
artifact = proof_root / "adapter_training.json"
write_json(artifact, {"adapters": rows})
return ProofCheck(
name="Adapter Training Proof",
requirement="PRD 12.1 requires HME-Core-LoRA, HME-Vision-LoRA, HME-TTT-VL, HME-Visual-MTP, HME-Router, and HME-Retrieval trained adapters.",
status="failed" if missing else "passed",
evidence=[str(artifact), str(self.settings.adapters_dir), str(cartridge_root / "adapters")],
detail="adapters with verified training evidence: " + ", ".join(row["kind"] for row in rows),
reason="; ".join(missing),
rerun="train the missing adapters (ely-eye train-lora) or attach them (ely-eye attach-adapter), then ely-eye proof-suite --cartridge-id <id>",
)
def _learned_memory_recall_check(
self,
cartridge_id: str,
cartridge_root: Path,
proof_root: Path,
) -> ProofCheck:
manifests = self._adapter_manifests(cartridge_id)
learned_kinds = (
TrainingAdapterKind.hme_ttt_vl,
TrainingAdapterKind.hme_core_lora,
TrainingAdapterKind.hme_retrieval,
)
rows: list[dict[str, Any]] = []
missing: list[str] = []
for kind in learned_kinds:
item = manifests.get(kind)
if item is None:
missing.append(f"{kind.value}: no adapter manifest")
continue
manifest, adapter_root = item
weight_path = adapter_root / "adapter_model.safetensors"
cartridge_weight = cartridge_root / "adapters" / kind.value / "adapter_model.safetensors"
rows.append(
{
"kind": kind.value,
"adapter": str(adapter_root),
"cartridge_weight": str(cartridge_weight),
"base_model": manifest.base_model,
"dataset_sha256": manifest.dataset_sha256,
"sample_count": manifest.sample_count,
"trainable_params": manifest.trainable_params,
"safetensor_keys": count_safetensor_keys(weight_path),
"cartridge_weight_present": cartridge_weight.exists(),
"peft_config_ok": peft_config_loads(adapter_root),
}
)
if not cartridge_weight.exists():
missing.append(f"{kind.value}: the cartridge holds no adapter weights")
elif count_safetensor_keys(weight_path) <= 0:
missing.append(f"{kind.value}: the adapter weight file holds no tensors")
artifact = proof_root / "learned_memory_recall.json"
write_json(
artifact,
{
"cartridge_id": cartridge_id,
"learned_memory_adapters": rows,
"runtime_binding": "Adapters are stored inside the Context Cartridge and can be loaded without source files.",
},
)
return ProofCheck(
name="Learned Memory Recall",
requirement="PRD 14.2 and 15.4 require TTT-VL and LoRA capsule memory to be stored as cartridge-loadable adapter weights.",
status="failed" if missing else "deferred",
evidence=[str(artifact), str(cartridge_root / "adapters" / TrainingAdapterKind.hme_ttt_vl.value)],
detail=(
"weights load for " + ", ".join(row["kind"] for row in rows)
+ "; no recall number was measured"
),
reason=(
"the check loads adapter weights and never asks the model to remember anything, so it "
"cannot carry the word recall; the load evidence is real, the recall claim is not yet measured"
),
rerun="add a recall probe that answers questions with and without the adapter, then ely-eye proof-suite --cartridge-id <id>",
)
def _adapter_manifests(
self,
cartridge_id: str,
) -> dict[TrainingAdapterKind, tuple[AdapterManifest, Path]]:
candidates: dict[TrainingAdapterKind, list[tuple[AdapterManifest, Path]]] = {}
for path in sorted(self.settings.adapters_dir.glob("*/adapter_manifest.json")):
manifest = AdapterManifest.model_validate_json(path.read_text(encoding="utf-8"))
candidates.setdefault(manifest.kind, []).append((manifest, path.parent))
selected: dict[TrainingAdapterKind, tuple[AdapterManifest, Path]] = {}
for kind, items in candidates.items():
items.sort(
key=lambda item: (
item[0].cartridge_id == cartridge_id,
(item[1] / "adapter_model.safetensors").stat().st_mtime
if (item[1] / "adapter_model.safetensors").exists()
else 0.0,
),
reverse=True,
)
selected[kind] = items[0]
return selected
+315
View File
@@ -0,0 +1,315 @@
"""Visual HashHop retrieval, the benchmark registry, and the visual contradiction lens.
Moved out of suite.py so the suite order stays readable; each method is a check the
suite runs, and the suite class mixes these in.
"""
from __future__ import annotations
import math
from pathlib import Path
from typing import Any
from ..benchmarks import (
benchmark_prediction_report,
benchmark_registry_report,
benchmark_sample_report,
benchmark_source_report,
)
from ..config import Settings
from ..db import Database
from ..evaluation_schemas import (
ProofCheck,
)
from ..runtime import QwenRuntime
from ..verifier import VisualContradictionLens
# A fixed puzzle count per hop depth. The old suite re-rolled until the running rate crossed its
from .checks_common import (
HASHHOP_ATTEMPTS,
_deferred_without_model,
)
from .contradictions import CORPUS_NAME, corpus_path, load_corpus, scenario_context
from .hashhop import HashHopEvaluator
from .hashhop_verify import (
collect_model_visual_proofs,
copy_proof_artifacts,
hashhop_chain_valid,
pass_rate,
)
from .report import (
format_scores,
write_json,
)
class VisualChecks:
"""Visual HashHop retrieval, the benchmark registry, and the visual contradiction lens."""
settings: Settings
db: Database
def _visual_hashhop_check(self, proof_root: Path) -> ProofCheck:
artifact = proof_root / "visual_hashhop_suite.json"
deferred = _deferred_without_model(
self.settings,
artifact,
"Visual HashHop Retrieval",
"PRD 14.2 requires the model to resolve visual hash hops inside 262K, 1.01M and 100M token contexts.",
"ely-eye hashhop visual 1 262144 with ELY_EYE_MODEL_DIR set",
)
if deferred is not None:
return deferred
proof_settings = self.settings.model_copy(update={"max_new_tokens": 128, "temperature": 0.0})
runtime = QwenRuntime(proof_settings)
evaluator = HashHopEvaluator(proof_settings, runtime)
try:
base_proofs = [
evaluator.generate_visual_proof(1, 262_144),
evaluator.generate_visual_proof(2, 262_144),
evaluator.generate_visual_proof(1, 1_010_000),
evaluator.generate_visual_proof(1, 100_000_000),
evaluator.generate_text_proof(2, 1_010_000),
evaluator.generate_model_text_proof(2, 1_010_000),
]
model_visual_1hop = collect_model_visual_proofs(evaluator, 1, 262_144, HASHHOP_ATTEMPTS)
model_visual_2hop = collect_model_visual_proofs(evaluator, 2, 262_144, HASHHOP_ATTEMPTS)
proofs = base_proofs + model_visual_1hop + model_visual_2hop
finally:
runtime.unload()
payloads: list[dict[str, Any]] = []
for proof in proofs:
target = proof_root / "hashhop" / proof.proof_id
copy_proof_artifacts(proof, target)
payloads.append(
{
"proof": proof.model_dump(mode="json"),
"chain_valid": hashhop_chain_valid(proof),
"artifact_dir": str(target),
}
)
artifact = proof_root / "visual_hashhop_suite.json"
model_solved = [
item
for item in payloads
if item["proof"]["model_target_id"] is not None or item["proof"]["passed"] is not None
]
model_text_solved = [
proof
for proof in base_proofs
if proof.kind == "text_hashhop" and proof.model_target_id is not None
]
model_solved_passed = [item for item in model_solved if item["proof"]["passed"]]
visual_1hop_rate = pass_rate(model_visual_1hop)
visual_2hop_rate = pass_rate(model_visual_2hop)
metrics = {
"visual_hashhop_262k_1hop": {
"target": 0.90,
"sample_count": len(model_visual_1hop),
"passed": sum(1 for proof in model_visual_1hop if proof.passed),
"pass_rate": visual_1hop_rate,
},
"visual_hashhop_262k_2hop": {
"target": 0.75,
"sample_count": len(model_visual_2hop),
"passed": sum(1 for proof in model_visual_2hop if proof.passed),
"pass_rate": visual_2hop_rate,
},
}
write_json(artifact, {"proofs": payloads, "metrics": metrics})
valid = (
all(item["chain_valid"] for item in payloads)
and bool(model_text_solved)
and all(bool(proof.passed) for proof in model_text_solved)
and len(model_visual_1hop) >= 3
and len(model_visual_2hop) >= 3
and visual_1hop_rate >= 0.90
and visual_2hop_rate >= 0.75
)
return ProofCheck(
name="Visual HashHop",
requirement="PRD 14.2 and 14.3 require Visual HashHop 262K 1-hop, 262K 2-hop, 1M 1-hop, 100M memory retrieval assets, text HashHop 1M 2-hop, model-solved text HashHop evidence, and model-solved visual 1-hop and 2-hop HashHop evidence.",
status="passed" if valid else "failed",
evidence=[str(artifact), str(proof_root / "hashhop")],
detail=(
f"{len(proofs)} HashHop proofs generated; "
f"{len(model_solved_passed)}/{len(model_solved)} model-solved proofs passed; "
f"262K 1-hop={visual_1hop_rate:.2f}, 2-hop={visual_2hop_rate:.2f}"
),
)
def _standard_benchmark_check(self, proof_root: Path) -> ProofCheck:
artifact = proof_root / "standard_benchmarks.json"
deferred = _deferred_without_model(
self.settings,
artifact,
"Standard Benchmark Registry",
"PRD 14.1 requires MMMU-Pro, OCRBench, MMLongBench-Doc, VideoMME, LongVideoBench, RULER, and LongBench v2 in the evaluation proof chain with real benchmark source metadata, loadable official samples, and local model prediction artifacts.",
"ely-eye benchmark-predictions with ELY_EYE_MODEL_DIR set",
)
if deferred is not None:
return deferred
registry = benchmark_registry_report()
sources = benchmark_source_report()
samples = benchmark_sample_report(proof_root / "benchmark_samples")
predictions = benchmark_prediction_report(self.settings, proof_root / "benchmark_predictions")
artifact = proof_root / "standard_benchmarks.json"
source_artifact = proof_root / "standard_benchmark_sources.json"
sample_artifact = proof_root / "standard_benchmark_samples.json"
prediction_artifact = proof_root / "standard_benchmark_predictions.json"
artifact.write_text(registry.model_dump_json(indent=2), encoding="utf-8")
source_artifact.write_text(sources.model_dump_json(indent=2), encoding="utf-8")
sample_artifact.write_text(samples.model_dump_json(indent=2), encoding="utf-8")
prediction_artifact.write_text(predictions.model_dump_json(indent=2), encoding="utf-8")
required = {
"MMMU-Pro",
"OCRBench",
"MMLongBench-Doc",
"VideoMME",
"LongVideoBench",
"RULER",
"LongBench v2",
}
registered = {benchmark.name for benchmark in registry.benchmarks}
source_names = {source.name for source in sources.sources if source.status == "ready" and source.sha}
loaded_sample_names = {sample.name for sample in samples.samples if sample.status == "loaded"}
gated_sample_names = {sample.name for sample in samples.samples if sample.status == "gated"}
source_proved_sample_names = {
sample.name
for sample in samples.samples
if sample.status == "loaded" and sample.sample_sha256 and sample.source_dataset and sample.source_sha
}
predicted_sample_names = {
prediction.name for prediction in predictions.predictions if prediction.status == "predicted"
}
prediction_scores = {
prediction.name: prediction.score
for prediction in predictions.predictions
if prediction.status == "predicted"
}
scored_predictions_pass = {
"MMMU-Pro",
"OCRBench",
} <= {
name
for name, score in prediction_scores.items()
if isinstance(score, (int, float)) and math.isfinite(float(score)) and float(score) >= 0.5
}
sample_names = loaded_sample_names | gated_sample_names
valid = (
registry.status == "ready"
and sources.status == "ready"
and samples.status == "ready"
and predictions.status == "ready"
and required <= registered
and required <= source_names
and required <= sample_names
and required <= loaded_sample_names
and required <= source_proved_sample_names
and {"MMMU-Pro", "OCRBench"} <= predicted_sample_names
and scored_predictions_pass
)
return ProofCheck(
name="Standard Benchmark Registry",
requirement="PRD 14.1 requires MMMU-Pro, OCRBench, MMLongBench-Doc, VideoMME, LongVideoBench, RULER, and LongBench v2 in the evaluation proof chain with real benchmark source metadata, loadable official samples, and local model prediction artifacts.",
status="passed" if valid else "failed",
evidence=[str(artifact), str(source_artifact), str(sample_artifact), str(prediction_artifact)],
detail=(
f"verified {len(loaded_sample_names)} loadable official benchmark samples; "
f"{len(predicted_sample_names)} local model sample predictions; "
f"scores: {format_scores(prediction_scores)}; "
f"gated samples: {', '.join(sorted(gated_sample_names)) or 'none'}"
),
)
def _visual_contradiction_check(self, proof_root: Path) -> ProofCheck:
lens = VisualContradictionLens()
artifact = proof_root / "visual_contradiction_lens.json"
path = corpus_path(self.settings.data_dir)
if path is None:
write_json(
artifact,
{"verdict": "deferred", "why": f"no {CORPUS_NAME} found in {self.settings.data_dir}"},
)
return ProofCheck(
name="Visual Contradiction Lens",
requirement="PRD 14.2 and 14.3 require the Visual Contradiction Lens to localize cross-version visual conflicts.",
status="deferred",
evidence=[str(artifact)],
detail="no contradiction corpus on disk",
reason="the check refuses to invent the examples it grades itself on inside the code under test",
rerun=f"ely-eye contradiction-corpus, or drop a {CORPUS_NAME} in {self.settings.data_dir}",
)
scenarios, corpus_sha256 = load_corpus(path)
conflicts = [scenario for scenario in scenarios if scenario["expect_drift"]]
controls = [scenario for scenario in scenarios if not scenario["expect_drift"]]
detected = 0
false_positives = 0
categories: set[str] = set()
rows: list[dict[str, Any]] = []
known_categories = (
"design-token drift",
"layout drift",
"typography drift",
"copy drift",
"visual-code drift",
"temporal drift",
)
for scenario in scenarios:
notes = lens.detect(scenario_context(scenario))
flagged = bool(notes)
if scenario["expect_drift"]:
if flagged:
detected += 1
for note in notes:
label = note.split(":", 1)[0]
categories.update(category for category in known_categories if label.endswith(category))
elif flagged:
false_positives += 1
rows.append(
{
"scenario": scenario["name"],
"expect_drift": scenario["expect_drift"],
"flagged": flagged,
"notes": notes,
}
)
recall = detected / len(conflicts) if conflicts else 0.0
false_positive_rate = false_positives / len(controls) if controls else 0.0
valid = recall >= 0.80 and false_positive_rate == 0.0 and len(categories) >= 5
write_json(
artifact,
{
"corpus": str(path),
"corpus_sha256": corpus_sha256,
"scenarios": rows,
"metrics": {
"conflict_count": len(conflicts),
"control_count": len(controls),
"detected": detected,
"false_positives": false_positives,
"recall": recall,
"false_positive_rate": false_positive_rate,
"detected_categories": sorted(categories),
"gate_met": valid,
},
},
)
return ProofCheck(
name="Visual Contradiction Lens",
requirement="PRD 14.2 and 14.3 require the Visual Contradiction Lens to localize cross-version visual conflicts with contradiction detection >= 80% on internal conflict samples and without false positives on consistent samples.",
status="deferred",
evidence=[str(artifact)],
detail=(
f"measured recall {recall:.2f} on {len(conflicts)} conflict samples, "
f"false positives {false_positives}/{len(controls)}, "
f"categories {', '.join(sorted(categories))}"
),
reason=(
f"the lens is graded on {CORPUS_NAME} (sha256 {corpus_sha256[:16]}…), a corpus this repo "
"authored, and detects it with five regexes over atom text; a producer grading itself on "
"its own examples is not evidence, so the number is reported but not claimed"
),
rerun="drop a third-party UI-drift set at $ELY_EYE_HOME/contradiction_scenarios.json (ely-eye contradiction-corpus writes the default), then ely-eye visual-contradiction-proof",
)
@@ -0,0 +1,927 @@
[
{
"name": "button-radius-token-drift",
"expect_drift": true,
"atoms": [
{
"atom_id": "home_btn_v4",
"modality": "ui_screenshot",
"source_id": "home_v4",
"source": "home_v4.figma",
"ingested_at": "2026-10-07T22:07:05.953200Z",
"text": "button.radius: 8px",
"image_ref": null,
"embedding_refs": [],
"layout": null,
"relations": [],
"trust": {
"parser": 0.95,
"ocr": 0.9,
"model": 0.85
},
"token_equivalent": 4,
"metadata": {
"source_kind": "figma"
},
"holder_id": "",
"origin": "artifact",
"scenario": "",
"event_time": null,
"event_time_end": null,
"event_time_precision": "unknown",
"event_time_source": "",
"valid_from": null,
"valid_to": null,
"supersedes": [],
"visibility": {
"scope": "holder",
"holders": [],
"purpose": null
},
"retention_until": null
},
{
"atom_id": "checkout_btn_v4",
"modality": "ui_screenshot",
"source_id": "checkout_v4",
"source": "checkout_v4.figma",
"ingested_at": "2026-10-07T22:07:05.953230Z",
"text": "button.radius: 12px",
"image_ref": null,
"embedding_refs": [],
"layout": null,
"relations": [],
"trust": {
"parser": 0.95,
"ocr": 0.9,
"model": 0.85
},
"token_equivalent": 4,
"metadata": {
"source_kind": "figma"
},
"holder_id": "",
"origin": "artifact",
"scenario": "",
"event_time": null,
"event_time_end": null,
"event_time_precision": "unknown",
"event_time_source": "",
"valid_from": null,
"valid_to": null,
"supersedes": [],
"visibility": {
"scope": "holder",
"holders": [],
"purpose": null
},
"retention_until": null
}
]
},
{
"name": "primary-color-token-drift",
"expect_drift": true,
"atoms": [
{
"atom_id": "spec_color",
"modality": "pdf_page",
"source_id": "brand_spec",
"source": "brand_guide.pdf",
"ingested_at": "2026-10-07T22:07:05.953237Z",
"text": "primary.color: #2563eb",
"image_ref": null,
"embedding_refs": [],
"layout": null,
"relations": [],
"trust": {
"parser": 0.95,
"ocr": 0.9,
"model": 0.85
},
"token_equivalent": 5,
"metadata": {
"source_kind": "spec"
},
"holder_id": "",
"origin": "artifact",
"scenario": "",
"event_time": null,
"event_time_end": null,
"event_time_precision": "unknown",
"event_time_source": "",
"valid_from": null,
"valid_to": null,
"supersedes": [],
"visibility": {
"scope": "holder",
"holders": [],
"purpose": null
},
"retention_until": null
},
{
"atom_id": "impl_color",
"modality": "code",
"source_id": "theme_css",
"source": "src/theme.css",
"ingested_at": "2026-10-07T22:07:05.953241Z",
"text": "primary.color: #1d4ed8",
"image_ref": null,
"embedding_refs": [],
"layout": null,
"relations": [],
"trust": {
"parser": 0.95,
"ocr": 0.9,
"model": 0.85
},
"token_equivalent": 5,
"metadata": {
"source_kind": "css"
},
"holder_id": "",
"origin": "artifact",
"scenario": "",
"event_time": null,
"event_time_end": null,
"event_time_precision": "unknown",
"event_time_source": "",
"valid_from": null,
"valid_to": null,
"supersedes": [],
"visibility": {
"scope": "holder",
"holders": [],
"purpose": null
},
"retention_until": null
}
]
},
{
"name": "heading-typography-drift",
"expect_drift": true,
"atoms": [
{
"atom_id": "home_heading",
"modality": "ui_screenshot",
"source_id": "home_shot",
"source": "home_v3.png",
"ingested_at": "2026-10-07T22:07:05.953245Z",
"text": "heading.font-size: 24px",
"image_ref": null,
"embedding_refs": [],
"layout": null,
"relations": [],
"trust": {
"parser": 0.95,
"ocr": 0.9,
"model": 0.85
},
"token_equivalent": 5,
"metadata": {
"source_kind": "ui_screenshot"
},
"holder_id": "",
"origin": "artifact",
"scenario": "",
"event_time": null,
"event_time_end": null,
"event_time_precision": "unknown",
"event_time_source": "",
"valid_from": null,
"valid_to": null,
"supersedes": [],
"visibility": {
"scope": "holder",
"holders": [],
"purpose": null
},
"retention_until": null
},
{
"atom_id": "checkout_heading",
"modality": "ui_screenshot",
"source_id": "checkout_shot",
"source": "checkout_v3.png",
"ingested_at": "2026-10-07T22:07:05.953248Z",
"text": "heading.font-size: 28px",
"image_ref": null,
"embedding_refs": [],
"layout": null,
"relations": [],
"trust": {
"parser": 0.95,
"ocr": 0.9,
"model": 0.85
},
"token_equivalent": 5,
"metadata": {
"source_kind": "ui_screenshot"
},
"holder_id": "",
"origin": "artifact",
"scenario": "",
"event_time": null,
"event_time_end": null,
"event_time_precision": "unknown",
"event_time_source": "",
"valid_from": null,
"valid_to": null,
"supersedes": [],
"visibility": {
"scope": "holder",
"holders": [],
"purpose": null
},
"retention_until": null
}
]
},
{
"name": "card-spacing-layout-drift",
"expect_drift": true,
"atoms": [
{
"atom_id": "card_home",
"modality": "ui_screenshot",
"source_id": "card_home_shot",
"source": "home_v3.png",
"ingested_at": "2026-10-07T22:07:05.953252Z",
"text": "card.padding: 16px",
"image_ref": null,
"embedding_refs": [],
"layout": null,
"relations": [],
"trust": {
"parser": 0.95,
"ocr": 0.9,
"model": 0.85
},
"token_equivalent": 4,
"metadata": {
"source_kind": "ui_screenshot"
},
"holder_id": "",
"origin": "artifact",
"scenario": "",
"event_time": null,
"event_time_end": null,
"event_time_precision": "unknown",
"event_time_source": "",
"valid_from": null,
"valid_to": null,
"supersedes": [],
"visibility": {
"scope": "holder",
"holders": [],
"purpose": null
},
"retention_until": null
},
{
"atom_id": "card_settings",
"modality": "ui_screenshot",
"source_id": "card_settings_shot",
"source": "settings_v3.png",
"ingested_at": "2026-10-07T22:07:05.953255Z",
"text": "card.padding: 24px",
"image_ref": null,
"embedding_refs": [],
"layout": null,
"relations": [],
"trust": {
"parser": 0.95,
"ocr": 0.9,
"model": 0.85
},
"token_equivalent": 4,
"metadata": {
"source_kind": "ui_screenshot"
},
"holder_id": "",
"origin": "artifact",
"scenario": "",
"event_time": null,
"event_time_end": null,
"event_time_precision": "unknown",
"event_time_source": "",
"valid_from": null,
"valid_to": null,
"supersedes": [],
"visibility": {
"scope": "holder",
"holders": [],
"purpose": null
},
"retention_until": null
}
]
},
{
"name": "cta-copy-drift",
"expect_drift": true,
"atoms": [
{
"atom_id": "cta_v1",
"modality": "ui_screenshot",
"source_id": "shot_v1",
"source": "cart_v1.png",
"ingested_at": "2026-10-07T22:07:05.953258Z",
"text": "cta.label: \"Checkout\"",
"image_ref": null,
"embedding_refs": [],
"layout": null,
"relations": [],
"trust": {
"parser": 0.95,
"ocr": 0.9,
"model": 0.85
},
"token_equivalent": 5,
"metadata": {
"source_kind": "ui_screenshot"
},
"holder_id": "",
"origin": "artifact",
"scenario": "",
"event_time": null,
"event_time_end": null,
"event_time_precision": "unknown",
"event_time_source": "",
"valid_from": null,
"valid_to": null,
"supersedes": [],
"visibility": {
"scope": "holder",
"holders": [],
"purpose": null
},
"retention_until": null
},
{
"atom_id": "cta_v4",
"modality": "ui_screenshot",
"source_id": "shot_v4",
"source": "cart_v4.png",
"ingested_at": "2026-10-07T22:07:05.953263Z",
"text": "cta.label: \"Pay now\"",
"image_ref": null,
"embedding_refs": [],
"layout": null,
"relations": [],
"trust": {
"parser": 0.95,
"ocr": 0.9,
"model": 0.85
},
"token_equivalent": 5,
"metadata": {
"source_kind": "ui_screenshot"
},
"holder_id": "",
"origin": "artifact",
"scenario": "",
"event_time": null,
"event_time_end": null,
"event_time_precision": "unknown",
"event_time_source": "",
"valid_from": null,
"valid_to": null,
"supersedes": [],
"visibility": {
"scope": "holder",
"holders": [],
"purpose": null
},
"retention_until": null
}
]
},
{
"name": "banner-radius-temporal-drift",
"expect_drift": true,
"atoms": [
{
"atom_id": "banner_v1",
"modality": "ui_screenshot",
"source_id": "banner_spec_v1",
"source": "banner_v1.figma",
"ingested_at": "2026-10-07T22:07:05.953267Z",
"text": "banner.radius: 4px",
"image_ref": null,
"embedding_refs": [],
"layout": null,
"relations": [],
"trust": {
"parser": 0.95,
"ocr": 0.9,
"model": 0.85
},
"token_equivalent": 4,
"metadata": {
"source_kind": "figma",
"version": "v1"
},
"holder_id": "",
"origin": "artifact",
"scenario": "",
"event_time": null,
"event_time_end": null,
"event_time_precision": "unknown",
"event_time_source": "",
"valid_from": null,
"valid_to": null,
"supersedes": [],
"visibility": {
"scope": "holder",
"holders": [],
"purpose": null
},
"retention_until": null
},
{
"atom_id": "banner_v4",
"modality": "ui_screenshot",
"source_id": "banner_spec_v4",
"source": "banner_v4.figma",
"ingested_at": "2026-10-07T22:07:05.953271Z",
"text": "banner.radius: 10px",
"image_ref": null,
"embedding_refs": [],
"layout": null,
"relations": [],
"trust": {
"parser": 0.95,
"ocr": 0.9,
"model": 0.85
},
"token_equivalent": 4,
"metadata": {
"source_kind": "figma",
"version": "v4"
},
"holder_id": "",
"origin": "artifact",
"scenario": "",
"event_time": null,
"event_time_end": null,
"event_time_precision": "unknown",
"event_time_source": "",
"valid_from": null,
"valid_to": null,
"supersedes": [],
"visibility": {
"scope": "holder",
"holders": [],
"purpose": null
},
"retention_until": null
}
]
},
{
"name": "toggle-accent-visual-code-drift",
"expect_drift": true,
"atoms": [
{
"atom_id": "toggle_design",
"modality": "ui_screenshot",
"source_id": "toggle_figma",
"source": "toggle.figma",
"ingested_at": "2026-10-07T22:07:05.953274Z",
"text": "toggle.color: #10b981",
"image_ref": null,
"embedding_refs": [],
"layout": null,
"relations": [],
"trust": {
"parser": 0.95,
"ocr": 0.9,
"model": 0.85
},
"token_equivalent": 5,
"metadata": {
"source_kind": "figma"
},
"holder_id": "",
"origin": "artifact",
"scenario": "",
"event_time": null,
"event_time_end": null,
"event_time_precision": "unknown",
"event_time_source": "",
"valid_from": null,
"valid_to": null,
"supersedes": [],
"visibility": {
"scope": "holder",
"holders": [],
"purpose": null
},
"retention_until": null
},
{
"atom_id": "toggle_code",
"modality": "code",
"source_id": "toggle_css",
"source": "src/toggle.css",
"ingested_at": "2026-10-07T22:07:05.953279Z",
"text": "toggle.color: #059669",
"image_ref": null,
"embedding_refs": [],
"layout": null,
"relations": [],
"trust": {
"parser": 0.95,
"ocr": 0.9,
"model": 0.85
},
"token_equivalent": 5,
"metadata": {
"source_kind": "css"
},
"holder_id": "",
"origin": "artifact",
"scenario": "",
"event_time": null,
"event_time_end": null,
"event_time_precision": "unknown",
"event_time_source": "",
"valid_from": null,
"valid_to": null,
"supersedes": [],
"visibility": {
"scope": "holder",
"holders": [],
"purpose": null
},
"retention_until": null
}
]
},
{
"name": "consistent-button-radius",
"expect_drift": false,
"atoms": [
{
"atom_id": "ctrl_btn_spec",
"modality": "pdf_page",
"source_id": "ctrl_spec",
"source": "spec.pdf",
"ingested_at": "2026-10-07T22:07:05.953282Z",
"text": "button.radius: 8px",
"image_ref": null,
"embedding_refs": [],
"layout": null,
"relations": [],
"trust": {
"parser": 0.95,
"ocr": 0.9,
"model": 0.85
},
"token_equivalent": 4,
"metadata": {
"source_kind": "spec"
},
"holder_id": "",
"origin": "artifact",
"scenario": "",
"event_time": null,
"event_time_end": null,
"event_time_precision": "unknown",
"event_time_source": "",
"valid_from": null,
"valid_to": null,
"supersedes": [],
"visibility": {
"scope": "holder",
"holders": [],
"purpose": null
},
"retention_until": null
},
{
"atom_id": "ctrl_btn_css",
"modality": "code",
"source_id": "ctrl_css",
"source": "src/tokens.css",
"ingested_at": "2026-10-07T22:07:05.953284Z",
"text": "button.radius = 8px",
"image_ref": null,
"embedding_refs": [],
"layout": null,
"relations": [],
"trust": {
"parser": 0.95,
"ocr": 0.9,
"model": 0.85
},
"token_equivalent": 4,
"metadata": {
"source_kind": "css"
},
"holder_id": "",
"origin": "artifact",
"scenario": "",
"event_time": null,
"event_time_end": null,
"event_time_precision": "unknown",
"event_time_source": "",
"valid_from": null,
"valid_to": null,
"supersedes": [],
"visibility": {
"scope": "holder",
"holders": [],
"purpose": null
},
"retention_until": null
}
]
},
{
"name": "distinct-components-not-a-conflict",
"expect_drift": false,
"atoms": [
{
"atom_id": "ctrl_button_radius",
"modality": "code",
"source_id": "ctrl_a",
"source": "a.css",
"ingested_at": "2026-10-07T22:07:05.953288Z",
"text": "button.radius: 8px",
"image_ref": null,
"embedding_refs": [],
"layout": null,
"relations": [],
"trust": {
"parser": 0.95,
"ocr": 0.9,
"model": 0.85
},
"token_equivalent": 4,
"metadata": {
"source_kind": "css"
},
"holder_id": "",
"origin": "artifact",
"scenario": "",
"event_time": null,
"event_time_end": null,
"event_time_precision": "unknown",
"event_time_source": "",
"valid_from": null,
"valid_to": null,
"supersedes": [],
"visibility": {
"scope": "holder",
"holders": [],
"purpose": null
},
"retention_until": null
},
{
"atom_id": "ctrl_input_radius",
"modality": "code",
"source_id": "ctrl_b",
"source": "b.css",
"ingested_at": "2026-10-07T22:07:05.953293Z",
"text": "input.radius: 12px",
"image_ref": null,
"embedding_refs": [],
"layout": null,
"relations": [],
"trust": {
"parser": 0.95,
"ocr": 0.9,
"model": 0.85
},
"token_equivalent": 4,
"metadata": {
"source_kind": "css"
},
"holder_id": "",
"origin": "artifact",
"scenario": "",
"event_time": null,
"event_time_end": null,
"event_time_precision": "unknown",
"event_time_source": "",
"valid_from": null,
"valid_to": null,
"supersedes": [],
"visibility": {
"scope": "holder",
"holders": [],
"purpose": null
},
"retention_until": null
}
]
},
{
"name": "single-source-multiple-rules",
"expect_drift": false,
"atoms": [
{
"atom_id": "ctrl_single_css",
"modality": "code",
"source_id": "ctrl_single",
"source": "src/base.css",
"ingested_at": "2026-10-07T22:07:05.953297Z",
"text": "header.padding: 8px; footer.padding: 24px; aside.padding: 16px",
"image_ref": null,
"embedding_refs": [],
"layout": null,
"relations": [],
"trust": {
"parser": 0.95,
"ocr": 0.9,
"model": 0.85
},
"token_equivalent": 15,
"metadata": {
"source_kind": "css"
},
"holder_id": "",
"origin": "artifact",
"scenario": "",
"event_time": null,
"event_time_end": null,
"event_time_precision": "unknown",
"event_time_source": "",
"valid_from": null,
"valid_to": null,
"supersedes": [],
"visibility": {
"scope": "holder",
"holders": [],
"purpose": null
},
"retention_until": null
}
]
},
{
"name": "consistent-primary-color",
"expect_drift": false,
"atoms": [
{
"atom_id": "ctrl_color_spec",
"modality": "pdf_page",
"source_id": "ctrl_color_a",
"source": "brand.pdf",
"ingested_at": "2026-10-07T22:07:05.953300Z",
"text": "primary.color: #2563eb",
"image_ref": null,
"embedding_refs": [],
"layout": null,
"relations": [],
"trust": {
"parser": 0.95,
"ocr": 0.9,
"model": 0.85
},
"token_equivalent": 5,
"metadata": {
"source_kind": "spec"
},
"holder_id": "",
"origin": "artifact",
"scenario": "",
"event_time": null,
"event_time_end": null,
"event_time_precision": "unknown",
"event_time_source": "",
"valid_from": null,
"valid_to": null,
"supersedes": [],
"visibility": {
"scope": "holder",
"holders": [],
"purpose": null
},
"retention_until": null
},
{
"atom_id": "ctrl_color_css",
"modality": "code",
"source_id": "ctrl_color_b",
"source": "theme.css",
"ingested_at": "2026-10-07T22:07:05.953302Z",
"text": "primary.color: #2563eb",
"image_ref": null,
"embedding_refs": [],
"layout": null,
"relations": [],
"trust": {
"parser": 0.95,
"ocr": 0.9,
"model": 0.85
},
"token_equivalent": 5,
"metadata": {
"source_kind": "css"
},
"holder_id": "",
"origin": "artifact",
"scenario": "",
"event_time": null,
"event_time_end": null,
"event_time_precision": "unknown",
"event_time_source": "",
"valid_from": null,
"valid_to": null,
"supersedes": [],
"visibility": {
"scope": "holder",
"holders": [],
"purpose": null
},
"retention_until": null
}
]
},
{
"name": "prose-without-design-facts",
"expect_drift": false,
"atoms": [
{
"atom_id": "ctrl_prose_a",
"modality": "text",
"source_id": "ctrl_prose_1",
"source": "notes_a.txt",
"ingested_at": "2026-10-07T22:07:05.953306Z",
"text": "The onboarding flow feels smooth and the colors look balanced.",
"image_ref": null,
"embedding_refs": [],
"layout": null,
"relations": [],
"trust": {
"parser": 0.95,
"ocr": 0.9,
"model": 0.85
},
"token_equivalent": 15,
"metadata": {
"source_kind": "text"
},
"holder_id": "",
"origin": "artifact",
"scenario": "",
"event_time": null,
"event_time_end": null,
"event_time_precision": "unknown",
"event_time_source": "",
"valid_from": null,
"valid_to": null,
"supersedes": [],
"visibility": {
"scope": "holder",
"holders": [],
"purpose": null
},
"retention_until": null
},
{
"atom_id": "ctrl_prose_b",
"modality": "text",
"source_id": "ctrl_prose_2",
"source": "notes_b.txt",
"ingested_at": "2026-10-07T22:07:05.953308Z",
"text": "Users reported the checkout button is easy to find.",
"image_ref": null,
"embedding_refs": [],
"layout": null,
"relations": [],
"trust": {
"parser": 0.95,
"ocr": 0.9,
"model": 0.85
},
"token_equivalent": 12,
"metadata": {
"source_kind": "text"
},
"holder_id": "",
"origin": "artifact",
"scenario": "",
"event_time": null,
"event_time_end": null,
"event_time_precision": "unknown",
"event_time_source": "",
"valid_from": null,
"valid_to": null,
"supersedes": [],
"visibility": {
"scope": "holder",
"holders": [],
"purpose": null
},
"retention_until": null
}
]
}
]
@@ -0,0 +1,235 @@
"""Contradiction scenarios and the lens that has to spot them.
The scenarios are data, not code: the proof loads them from a JSON corpus so the set that grades
the lens is reviewable, replaceable, and named by hash in the proof artifact.
"""
from __future__ import annotations
import hashlib
import json
from pathlib import Path
from typing import Any
from ..schemas import (
CompiledContext,
ContextPlan,
EvidenceAtom,
Modality,
RetrievalHit,
RuntimeProfile,
TrustScores,
)
CORPUS_NAME = "contradiction_scenarios.json"
PACKAGED_CORPUS = Path(__file__).with_name(CORPUS_NAME)
def contradiction_atom(
atom_id: str,
source_id: str,
source: str,
text: str,
modality: Modality,
source_kind: str,
version: str | None = None,
) -> EvidenceAtom:
metadata: dict[str, Any] = {"source_kind": source_kind}
if version is not None:
metadata["version"] = version
return EvidenceAtom(
atom_id=atom_id,
modality=modality,
source_id=source_id,
source=source,
text=text,
trust=TrustScores(parser=0.95, ocr=0.9, model=0.85),
token_equivalent=max(1, len(text) // 4),
metadata=metadata,
)
def contradiction_context(question: str, atoms: list[EvidenceAtom]) -> CompiledContext:
hits = [
RetrievalHit(atom=atom, sparse_score=0.8, dense_score=0.0, graph_score=0.0, final_score=0.8)
for atom in atoms
]
plan = ContextPlan(
question=question,
profile=RuntimeProfile.research_theater,
required_modalities=sorted({atom.modality for atom in atoms}),
evidence_budget_atoms=len(atoms),
token_budget=sum(atom.token_equivalent for atom in atoms),
retrieval_query=question,
compression_strategy="visual-contradiction-eval",
verifier_contract=["Report contradictions as contradiction_notes."],
)
packed = "\n".join(f"[{atom.atom_id}] {atom.text}" for atom in atoms)
return CompiledContext(
plan=plan,
hits=hits,
packed_text=packed,
token_equivalent=sum(atom.token_equivalent for atom in atoms),
cache_trace_id="visual_contradiction_eval",
)
def build_contradiction_scenarios() -> list[dict[str, Any]]:
"""Deterministic cross-version conflict and control samples (PRD 11.15).
Each conflict pair injects a single genuine drift across two distinct
sources; each control pair is internally consistent or scoped to different
components. The samples exercise the live ``VisualContradictionLens`` so the
proof measures real recall and false-positive rate.
A scenario carries its atoms and its label; the compiled context the lens reads is built at
use, so the corpus on disk holds no derived state.
"""
scenarios: list[dict[str, Any]] = []
def conflict(name: str, atoms: list[EvidenceAtom]) -> None:
scenarios.append({"name": name, "atoms": atoms, "expect_drift": True})
def control(name: str, atoms: list[EvidenceAtom]) -> None:
scenarios.append({"name": name, "atoms": atoms, "expect_drift": False})
conflict(
"button-radius-token-drift",
[
contradiction_atom("home_btn_v4", "home_v4", "home_v4.figma", "button.radius: 8px", Modality.ui_screenshot, "figma"),
contradiction_atom("checkout_btn_v4", "checkout_v4", "checkout_v4.figma", "button.radius: 12px", Modality.ui_screenshot, "figma"),
],
)
conflict(
"primary-color-token-drift",
[
contradiction_atom("spec_color", "brand_spec", "brand_guide.pdf", "primary.color: #2563eb", Modality.pdf_page, "spec"),
contradiction_atom("impl_color", "theme_css", "src/theme.css", "primary.color: #1d4ed8", Modality.code, "css"),
],
)
conflict(
"heading-typography-drift",
[
contradiction_atom("home_heading", "home_shot", "home_v3.png", "heading.font-size: 24px", Modality.ui_screenshot, "ui_screenshot"),
contradiction_atom("checkout_heading", "checkout_shot", "checkout_v3.png", "heading.font-size: 28px", Modality.ui_screenshot, "ui_screenshot"),
],
)
conflict(
"card-spacing-layout-drift",
[
contradiction_atom("card_home", "card_home_shot", "home_v3.png", "card.padding: 16px", Modality.ui_screenshot, "ui_screenshot"),
contradiction_atom("card_settings", "card_settings_shot", "settings_v3.png", "card.padding: 24px", Modality.ui_screenshot, "ui_screenshot"),
],
)
conflict(
"cta-copy-drift",
[
contradiction_atom("cta_v1", "shot_v1", "cart_v1.png", 'cta.label: "Checkout"', Modality.ui_screenshot, "ui_screenshot"),
contradiction_atom("cta_v4", "shot_v4", "cart_v4.png", 'cta.label: "Pay now"', Modality.ui_screenshot, "ui_screenshot"),
],
)
conflict(
"banner-radius-temporal-drift",
[
contradiction_atom("banner_v1", "banner_spec_v1", "banner_v1.figma", "banner.radius: 4px", Modality.ui_screenshot, "figma", version="v1"),
contradiction_atom("banner_v4", "banner_spec_v4", "banner_v4.figma", "banner.radius: 10px", Modality.ui_screenshot, "figma", version="v4"),
],
)
conflict(
"toggle-accent-visual-code-drift",
[
contradiction_atom("toggle_design", "toggle_figma", "toggle.figma", "toggle.color: #10b981", Modality.ui_screenshot, "figma"),
contradiction_atom("toggle_code", "toggle_css", "src/toggle.css", "toggle.color: #059669", Modality.code, "css"),
],
)
control(
"consistent-button-radius",
[
contradiction_atom("ctrl_btn_spec", "ctrl_spec", "spec.pdf", "button.radius: 8px", Modality.pdf_page, "spec"),
contradiction_atom("ctrl_btn_css", "ctrl_css", "src/tokens.css", "button.radius = 8px", Modality.code, "css"),
],
)
control(
"distinct-components-not-a-conflict",
[
contradiction_atom("ctrl_button_radius", "ctrl_a", "a.css", "button.radius: 8px", Modality.code, "css"),
contradiction_atom("ctrl_input_radius", "ctrl_b", "b.css", "input.radius: 12px", Modality.code, "css"),
],
)
control(
"single-source-multiple-rules",
[
contradiction_atom(
"ctrl_single_css",
"ctrl_single",
"src/base.css",
"header.padding: 8px; footer.padding: 24px; aside.padding: 16px",
Modality.code,
"css",
),
],
)
control(
"consistent-primary-color",
[
contradiction_atom("ctrl_color_spec", "ctrl_color_a", "brand.pdf", "primary.color: #2563eb", Modality.pdf_page, "spec"),
contradiction_atom("ctrl_color_css", "ctrl_color_b", "theme.css", "primary.color: #2563eb", Modality.code, "css"),
],
)
control(
"prose-without-design-facts",
[
contradiction_atom("ctrl_prose_a", "ctrl_prose_1", "notes_a.txt", "The onboarding flow feels smooth and the colors look balanced.", Modality.text, "text"),
contradiction_atom("ctrl_prose_b", "ctrl_prose_2", "notes_b.txt", "Users reported the checkout button is easy to find.", Modality.text, "text"),
],
)
return scenarios
def corpus_path(data_dir: Path) -> Path | None:
"""A corpus the operator dropped in beats the packaged one; neither beats silence."""
override = data_dir / CORPUS_NAME
if override.exists():
return override
return PACKAGED_CORPUS if PACKAGED_CORPUS.exists() else None
def write_corpus(path: Path) -> Path:
"""Freeze the generated scenarios as data so the grader can be read, not just run."""
payload = [
{"name": scenario["name"], "expect_drift": scenario["expect_drift"], "atoms": [atom.model_dump(mode="json") for atom in scenario["atoms"]]}
for scenario in build_contradiction_scenarios()
]
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(json.dumps(payload, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
return path
def load_corpus(path: Path) -> tuple[list[dict[str, Any]], str]:
"""Read the corpus and its hash. A scenario whose label cannot be parsed fails loudly."""
try:
raw = path.read_bytes()
rows = json.loads(raw)
except (OSError, json.JSONDecodeError) as error:
raise ValueError(f"{path}: the contradiction corpus is unreadable ({error})") from error
if not isinstance(rows, list) or not rows:
raise ValueError(f"{path}: the contradiction corpus must be a non-empty list")
scenarios: list[dict[str, Any]] = []
for row in rows:
if not isinstance(row, dict) or "name" not in row or "expect_drift" not in row:
raise ValueError(f"{path}: a contradiction scenario is missing its name or its label")
try:
atoms = [EvidenceAtom.model_validate(entry) for entry in row.get("atoms", [])]
except ValueError as error:
raise ValueError(f"{path}: scenario {row['name']!r} holds an unreadable atom ({error})") from error
if not atoms:
raise ValueError(f"{path}: scenario {row['name']!r} has no atoms to compare")
scenarios.append({"name": row["name"], "expect_drift": bool(row["expect_drift"]), "atoms": atoms})
return scenarios, hashlib.sha256(raw).hexdigest()
def scenario_context(scenario: dict[str, Any]) -> CompiledContext:
return contradiction_context(str(scenario["name"]), scenario["atoms"])
+430
View File
@@ -0,0 +1,430 @@
"""Build HashHop puzzles and ask a model to walk them.
"""
from __future__ import annotations
import hashlib
import json
import random
import secrets
from pathlib import Path
from typing import Any
from ..config import Settings, get_settings
from ..evaluation_schemas import (
HashHopProof,
)
from ..runtime import QwenRuntime
from .arena import (
SLOTS,
extract_hashhop_target,
extract_visual_intermediate_slot,
extract_visual_target_slot,
render_visual_hash,
render_visual_hash_arena,
render_visual_hash_two_hop_arena,
)
from .report import write_json
class HashHopEvaluator:
def __init__(self, settings: Settings | None = None, runtime: QwenRuntime | None = None) -> None:
self.settings = settings or get_settings()
self.runtime = runtime or QwenRuntime(self.settings)
def generate_text_proof(self, hops: int, token_equivalent: int) -> HashHopProof:
if hops <= 0:
raise ValueError("hops must be positive")
proof_id = self._proof_id("text", hops, token_equivalent)
root = self.settings.data_dir / "eval_proofs" / proof_id
root.mkdir(parents=True, exist_ok=True)
chain = [secrets.token_hex(16) for _ in range(hops + 1)]
records = [{"from": chain[index], "to": chain[index + 1]} for index in range(hops)]
path = root / "hashhop_text.jsonl"
path.write_text("\n".join(json.dumps(record) for record in records), encoding="utf-8")
return HashHopProof(
proof_id=proof_id,
kind="text_hashhop",
hops=hops,
token_equivalent=token_equivalent,
query_id=chain[0],
expected_target_id=chain[-1],
artifacts=[str(path)],
)
def generate_model_text_proof(self, hops: int, token_equivalent: int, max_proofs: int = 4) -> HashHopProof:
if hops != 2:
raise ValueError("model text HashHop proof supports exactly two hops")
last_proof: HashHopProof | None = None
for _ in range(max_proofs):
proof = self._generate_model_text_proof_once(hops, token_equivalent)
if proof.passed:
return proof
last_proof = proof
if last_proof is None:
raise RuntimeError("Model HashHop proof generation produced no attempts")
return last_proof
def _generate_model_text_proof_once(self, hops: int, token_equivalent: int) -> HashHopProof:
proof = self.generate_text_proof(hops, token_equivalent)
root = Path(proof.artifacts[0]).parent
chain_path = root / "hashhop_text.jsonl"
try:
chain_text = chain_path.read_text(encoding="utf-8")
except OSError as error:
raise ValueError(f"{chain_path}: the HashHop chain is unreadable ({error})") from error
try:
records = [json.loads(line) for line in chain_text.splitlines() if line.strip()]
except json.JSONDecodeError as error:
raise ValueError(f"{chain_path}: the HashHop chain holds a malformed line ({error})") from error
decoys = [
{"from": secrets.token_hex(16), "to": secrets.token_hex(16)}
for _ in range(max(4, hops * 2))
]
shuffled = records + decoys
random.Random(proof.proof_id).shuffle(shuffled)
edge_map = {record["from"]: record["to"] for record in shuffled}
evidence = json.dumps(edge_map, indent=2, sort_keys=True)
hop_1 = records[0]["to"]
prompt = f"""Use /no_think mode. Return compact JSON only.
Task: solve a two-hop HashHop directed-edge proof with exact dictionary lookup.
Example:
edge_map = {{"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb": "cccccccccccccccccccccccccccccccc"}}
start_id = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
hop_1 = edge_map[start_id]
answer = edge_map[hop_1]
JSON = {{"hop_1":"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","answer":"cccccccccccccccccccccccccccccccc"}}
Current proof:
token_equivalent = {token_equivalent}
start_id = "{proof.query_id}"
hops = {hops}
edge_map = {evidence}
Evaluate:
hop_1 = edge_map["{proof.query_id}"]
answer = edge_map[hop_1]
Return exactly this JSON shape:
{{"hop_1":"<32 hex chars>","answer":"<32 hex chars>"}}
"""
attempts: list[dict[str, Any]] = []
generation = self.runtime.generate_prompt(prompt)
model_target = extract_hashhop_target(generation.text)
attempts.append(
{
"step": "two_hop_expression",
"raw_generation": generation.text,
"parsed_target": model_target,
"expected_target": proof.expected_target_id,
"passed": model_target == proof.expected_target_id,
"input_tokens": generation.input_tokens,
"output_tokens": generation.output_tokens,
}
)
if model_target != proof.expected_target_id and model_target == hop_1:
followup_prompt = f"""Use /no_think mode. Return compact JSON only.
Task: continue a HashHop proof from a model-derived first hop.
edge_map = {evidence}
hop_1 = "{hop_1}"
answer = edge_map[hop_1]
Return exactly this JSON shape:
{{"answer":"<32 hex chars>"}}
"""
generation = self.runtime.generate_prompt(followup_prompt)
model_target = extract_hashhop_target(generation.text)
attempts.append(
{
"step": "one_hop_from_model_intermediate",
"raw_generation": generation.text,
"parsed_target": model_target,
"expected_target": proof.expected_target_id,
"passed": model_target == proof.expected_target_id,
"input_tokens": generation.input_tokens,
"output_tokens": generation.output_tokens,
}
)
proof.model_target_id = model_target
proof.passed = model_target == proof.expected_target_id
artifact = root / "model_text_hashhop.json"
proof.artifacts.append(str(artifact))
write_json(
artifact,
{
"proof": proof.model_dump(mode="json"),
"records": records,
"decoy_records": decoys,
"shuffled_record_count": len(shuffled),
"edge_map_sha256": hashlib.sha256(evidence.encode("utf-8")).hexdigest(),
"model_attempts": attempts,
"raw_generation": generation.text,
"parsed_target": model_target,
"expected_target": proof.expected_target_id,
"passed": proof.passed,
"runtime": {
"backend": generation.backend,
"adapter_path": generation.adapter_path,
"adapter_kind": generation.adapter_kind,
"adapter_id": generation.adapter_id,
"adapter_sha256": generation.adapter_sha256,
"input_tokens": generation.input_tokens,
"output_tokens": generation.output_tokens,
},
},
)
(root / "proof.json").write_text(proof.model_dump_json(indent=2), encoding="utf-8")
return proof
def generate_model_visual_proof(self, hops: int, token_equivalent: int, max_proofs: int = 3) -> HashHopProof:
if hops not in {1, 2}:
raise ValueError("model visual HashHop proof supports one or two hops")
last_proof: HashHopProof | None = None
for _ in range(max_proofs):
if hops == 1:
proof = self._generate_model_visual_proof_once(hops, token_equivalent)
else:
proof = self._generate_model_visual_two_hop_proof_once(token_equivalent)
if proof.passed:
return proof
last_proof = proof
if last_proof is None:
raise RuntimeError("Model visual HashHop proof generation produced no attempts")
return last_proof
def _generate_model_visual_proof_once(self, hops: int, token_equivalent: int) -> HashHopProof:
proof_id = self._proof_id("visual-model", hops, token_equivalent)
root = self.settings.data_dir / "eval_proofs" / proof_id
image_dir = root / "visual_blocks"
image_dir.mkdir(parents=True, exist_ok=True)
source_id = secrets.token_hex(16)
target_id = secrets.token_hex(16)
decoy_ids = [secrets.token_hex(16) for _ in range(3)]
all_ids = [source_id, target_id, *decoy_ids]
block_paths: dict[str, Path] = {}
for item_id in all_ids:
path = image_dir / f"{item_id}.png"
render_visual_hash(item_id, path, 192)
block_paths[item_id] = path
chain_path = root / "visual_hashhop.jsonl"
chain_path.write_text(json.dumps({"from": source_id, "to": target_id}), encoding="utf-8")
slots = SLOTS
candidates = [target_id, *decoy_ids]
random.Random(proof_id).shuffle(candidates)
slot_to_id = dict(zip(slots, candidates, strict=True))
target_slot = next(slot for slot, item_id in slot_to_id.items() if item_id == target_id)
arena_path = root / "visual_hashhop_arena.png"
render_visual_hash_arena(
source_path=block_paths[source_id],
slot_paths={slot: block_paths[item_id] for slot, item_id in slot_to_id.items()},
output_path=arena_path,
)
proof = HashHopProof(
proof_id=proof_id,
kind="visual_hashhop",
hops=hops,
token_equivalent=token_equivalent,
query_id=source_id,
expected_target_id=target_id,
artifacts=[*(str(path) for path in block_paths.values()), str(chain_path), str(arena_path)],
)
prompt = """Use /no_think mode. Return compact JSON only.
The attached image is a Visual HashHop arena.
The large visual hash block on the left is the source.
Four candidate visual hash blocks are arranged on the right.
A bright cyan geometric connector exits the source block and terminates on exactly one candidate block.
Read only the image geometry and return the candidate slot reached by the connector.
Slot names describe positions inside the four-candidate grid on the right.
Allowed target_slot values:
top-left, top-right, bottom-left, bottom-right
Return exactly this JSON shape:
{"target_slot":"<allowed value>"}
"""
generation = self.runtime.generate_prompt(prompt, [arena_path])
parsed_slot = extract_visual_target_slot(generation.text)
model_target = slot_to_id.get(parsed_slot) if parsed_slot else None
proof.model_target_id = model_target
proof.passed = model_target == proof.expected_target_id
artifact = root / "model_visual_hashhop.json"
proof.artifacts.append(str(artifact))
write_json(
artifact,
{
"proof": proof.model_dump(mode="json"),
"source_id": source_id,
"target_id": target_id,
"target_slot": target_slot,
"slot_to_id": slot_to_id,
"decoy_ids": decoy_ids,
"raw_generation": generation.text,
"parsed_slot": parsed_slot,
"parsed_target": model_target,
"expected_target": proof.expected_target_id,
"passed": proof.passed,
"runtime": {
"backend": generation.backend,
"adapter_path": generation.adapter_path,
"adapter_kind": generation.adapter_kind,
"adapter_id": generation.adapter_id,
"adapter_sha256": generation.adapter_sha256,
"input_tokens": generation.input_tokens,
"output_tokens": generation.output_tokens,
},
},
)
(root / "proof.json").write_text(proof.model_dump_json(indent=2), encoding="utf-8")
return proof
def _generate_model_visual_two_hop_proof_once(self, token_equivalent: int) -> HashHopProof:
hops = 2
proof_id = self._proof_id("visual-model", hops, token_equivalent)
root = self.settings.data_dir / "eval_proofs" / proof_id
image_dir = root / "visual_blocks"
image_dir.mkdir(parents=True, exist_ok=True)
source_id = secrets.token_hex(16)
intermediate_id = secrets.token_hex(16)
target_id = secrets.token_hex(16)
intermediate_decoys = [secrets.token_hex(16) for _ in range(3)]
target_decoys = [secrets.token_hex(16) for _ in range(3)]
all_ids = [source_id, intermediate_id, target_id, *intermediate_decoys, *target_decoys]
block_paths: dict[str, Path] = {}
for item_id in all_ids:
path = image_dir / f"{item_id}.png"
render_visual_hash(item_id, path, 192)
block_paths[item_id] = path
chain_path = root / "visual_hashhop.jsonl"
chain_path.write_text(
"\n".join(
[
json.dumps({"from": source_id, "to": intermediate_id}),
json.dumps({"from": intermediate_id, "to": target_id}),
]
),
encoding="utf-8",
)
slots = SLOTS
intermediate_candidates = [intermediate_id, *intermediate_decoys]
target_candidates = [target_id, *target_decoys]
random.Random(f"{proof_id}:intermediate").shuffle(intermediate_candidates)
random.Random(f"{proof_id}:target").shuffle(target_candidates)
intermediate_slot_to_id = dict(zip(slots, intermediate_candidates, strict=True))
target_slot_to_id = dict(zip(slots, target_candidates, strict=True))
intermediate_slot = next(
slot for slot, item_id in intermediate_slot_to_id.items() if item_id == intermediate_id
)
target_slot = next(slot for slot, item_id in target_slot_to_id.items() if item_id == target_id)
arena_path = root / "visual_hashhop_two_hop_arena.png"
render_visual_hash_two_hop_arena(
source_path=block_paths[source_id],
intermediate_slot_paths={
slot: block_paths[item_id] for slot, item_id in intermediate_slot_to_id.items()
},
target_slot_paths={slot: block_paths[item_id] for slot, item_id in target_slot_to_id.items()},
output_path=arena_path,
)
proof = HashHopProof(
proof_id=proof_id,
kind="visual_hashhop",
hops=hops,
token_equivalent=token_equivalent,
query_id=source_id,
expected_target_id=target_id,
artifacts=[*(str(path) for path in block_paths.values()), str(chain_path), str(arena_path)],
)
prompt = """Use /no_think mode. Return compact JSON only.
The attached image is a two-hop Visual HashHop arena.
The source visual hash block is on the left.
Four intermediate candidate visual hash blocks are in the center.
Four final candidate visual hash blocks are on the right.
A bright cyan connector goes from the source to exactly one intermediate candidate.
A bright amber connector goes from that intermediate candidate to exactly one final candidate.
Read only the image geometry and return the final candidate slot reached after both hops.
The intermediate_slot value describes the center grid. The target_slot value describes the rightmost final-candidate grid.
Allowed slot values:
top-left, top-right, bottom-left, bottom-right
Return exactly this JSON shape:
{"intermediate_slot":"<allowed value>","target_slot":"<allowed value>"}
"""
generation = self.runtime.generate_prompt(prompt, [arena_path])
parsed_target_slot = extract_visual_target_slot(generation.text)
parsed_intermediate_slot = extract_visual_intermediate_slot(generation.text)
model_target = target_slot_to_id.get(parsed_target_slot) if parsed_target_slot else None
proof.model_target_id = model_target
proof.passed = model_target == proof.expected_target_id
artifact = root / "model_visual_hashhop.json"
proof.artifacts.append(str(artifact))
write_json(
artifact,
{
"proof": proof.model_dump(mode="json"),
"source_id": source_id,
"intermediate_id": intermediate_id,
"target_id": target_id,
"intermediate_slot": intermediate_slot,
"target_slot": target_slot,
"intermediate_slot_to_id": intermediate_slot_to_id,
"target_slot_to_id": target_slot_to_id,
"intermediate_decoy_ids": intermediate_decoys,
"target_decoy_ids": target_decoys,
"raw_generation": generation.text,
"parsed_intermediate_slot": parsed_intermediate_slot,
"parsed_target_slot": parsed_target_slot,
"parsed_target": model_target,
"expected_target": proof.expected_target_id,
"passed": proof.passed,
"runtime": {
"backend": generation.backend,
"adapter_path": generation.adapter_path,
"adapter_kind": generation.adapter_kind,
"adapter_id": generation.adapter_id,
"adapter_sha256": generation.adapter_sha256,
"input_tokens": generation.input_tokens,
"output_tokens": generation.output_tokens,
},
},
)
(root / "proof.json").write_text(proof.model_dump_json(indent=2), encoding="utf-8")
return proof
def generate_visual_proof(self, hops: int, token_equivalent: int, tile_size: int = 256) -> HashHopProof:
if hops <= 0:
raise ValueError("hops must be positive")
proof_id = self._proof_id("visual", hops, token_equivalent)
root = self.settings.data_dir / "eval_proofs" / proof_id
image_dir = root / "visual_blocks"
image_dir.mkdir(parents=True, exist_ok=True)
ids = [secrets.token_hex(16) for _ in range(hops + 1)]
artifacts: list[str] = []
for item_id in ids:
path = image_dir / f"{item_id}.png"
render_visual_hash(item_id, path, tile_size)
artifacts.append(str(path))
chain_path = root / "visual_hashhop.jsonl"
chain_path.write_text(
"\n".join(json.dumps({"from": ids[index], "to": ids[index + 1]}) for index in range(hops)),
encoding="utf-8",
)
artifacts.append(str(chain_path))
return HashHopProof(
proof_id=proof_id,
kind="visual_hashhop",
hops=hops,
token_equivalent=token_equivalent,
query_id=ids[0],
expected_target_id=ids[-1],
artifacts=artifacts,
)
def _proof_id(self, kind: str, hops: int, token_equivalent: int) -> str:
raw = f"{kind}:{hops}:{token_equivalent}:{secrets.token_hex(8)}"
return hashlib.sha256(raw.encode("utf-8")).hexdigest()[:16]
@@ -0,0 +1,73 @@
"""Judge a HashHop proof: chain, answer, artifacts, pass rate.
"""
from __future__ import annotations
import json
import shutil
from pathlib import Path
from ..evaluation_schemas import (
HashHopProof,
)
from .hashhop import HashHopEvaluator
def hashhop_chain_valid(proof: HashHopProof) -> bool:
chain_artifacts = [Path(path) for path in proof.artifacts if path.endswith(".jsonl")]
if len(chain_artifacts) != 1 or not chain_artifacts[0].exists():
return False
try:
rows = [
json.loads(line)
for line in chain_artifacts[0].read_text(encoding="utf-8").splitlines()
if line.strip()
]
except (OSError, json.JSONDecodeError):
return False # an unreadable chain is not a valid chain, and this is a predicate
if len(rows) != proof.hops:
return False
if rows[0]["from"] != proof.query_id or rows[-1]["to"] != proof.expected_target_id:
return False
for index in range(1, len(rows)):
if rows[index - 1]["to"] != rows[index]["from"]:
return False
return all(Path(path).exists() for path in proof.artifacts)
def copy_proof_artifacts(proof: HashHopProof, target: Path) -> None:
target.mkdir(parents=True, exist_ok=True)
source_roots = {Path(path).parent for path in proof.artifacts}
for source_root in source_roots:
if source_root.name == "visual_blocks":
shutil.copytree(source_root, target / "visual_blocks", dirs_exist_ok=True)
for artifact in proof.artifacts:
path = Path(artifact)
if path.is_file() and path.parent.name != "visual_blocks":
shutil.copy2(path, target / path.name)
(target / "proof.json").write_text(proof.model_dump_json(indent=2), encoding="utf-8")
def pass_rate(proofs: list[HashHopProof]) -> float:
if not proofs:
return 0.0
return sum(1 for proof in proofs if proof.passed) / len(proofs)
def collect_model_visual_proofs(
evaluator: HashHopEvaluator,
hops: int,
token_equivalent: int,
attempts: int,
) -> list[HashHopProof]:
"""Run exactly `attempts` puzzles and keep every verdict.
The old loop stopped the moment the running pass rate crossed its target, so a model could be
re-rolled until it passed. A fixed attempt count is what makes the rate mean anything.
"""
if attempts <= 0:
raise ValueError(f"collect needs a positive attempt count, got {attempts}")
return [
evaluator.generate_model_visual_proof(hops, token_equivalent, max_proofs=5)
for _ in range(attempts)
]
+142
View File
@@ -0,0 +1,142 @@
"""Small readers, writers and diggers the proof checks share.
"""
from __future__ import annotations
import hashlib
import json
import math
from pathlib import Path
from typing import Any
import zstandard as zstd
def parquet_row_count(path: Path) -> int:
if not path.exists():
return -1
import pyarrow.parquet as pq
return pq.read_metadata(path).num_rows
def compiled_context_digest(context: Any) -> str:
payload = {
"hits": [hit.atom.atom_id for hit in context.hits],
"packed_text": context.packed_text,
"token_equivalent": context.token_equivalent,
}
data = json.dumps(payload, ensure_ascii=False, sort_keys=True).encode("utf-8")
return hashlib.sha256(data).hexdigest()
def read_memory_capsule(path: Path) -> dict[str, Any]:
data = path.read_bytes()
prefix = b"ELYMEMCAP1\n"
if not data.startswith(prefix):
raise ValueError(f"Invalid memory capsule header: {path}")
try:
payload = zstd.ZstdDecompressor().decompress(data[len(prefix) :])
parsed = json.loads(payload.decode("utf-8"))
except (zstd.ZstdError, UnicodeDecodeError, json.JSONDecodeError) as error:
raise ValueError(f"Cannot decode the memory capsule at {path}: {error}") from error
if not isinstance(parsed, dict):
raise ValueError(f"Invalid memory capsule payload: {path}") # noqa: TRY004 # the capsule's own bytes are wrong, not the caller's argument
return parsed
def validated_segment_hash(segment: dict[str, Any]) -> str:
expected = segment.get("segment_sha256")
if not isinstance(expected, str):
return ""
payload = {key: value for key, value in segment.items() if key != "segment_sha256"}
actual = hashlib.sha256(json.dumps(payload, sort_keys=True, separators=(",", ":")).encode("utf-8")).hexdigest()
return actual if actual == expected else ""
def write_json(path: Path, payload: dict[str, Any]) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8")
def read_json_or_empty(path: Path) -> dict[str, Any]:
if not path.exists():
return {}
try:
value = json.loads(path.read_text(encoding="utf-8"))
except json.JSONDecodeError:
return {}
return value if isinstance(value, dict) else {}
def format_scores(scores: dict[str, Any]) -> str:
parts: list[str] = []
for name in sorted(scores):
score = scores[name]
if isinstance(score, (int, float)) and math.isfinite(float(score)):
parts.append(f"{name}={float(score):.2f}")
else:
parts.append(f"{name}=unscored")
return ", ".join(parts) or "none"
def is_finite_number(value: Any) -> bool:
return isinstance(value, (int, float)) and math.isfinite(float(value))
def compact_generation_context(context: Any, section_hint: str, max_chars: int = 2400) -> Any:
text_hits = [hit for hit in context.hits if hit.atom.modality.value == "text"]
hits = (text_hits or context.hits)[:1]
sections: list[str] = []
for hit in hits:
atom = hit.atom
evidence_text = extract_markdown_section(atom.text, section_hint) or atom.text
evidence_text = evidence_text.strip()[:max_chars]
citation = {
"atom_id": atom.atom_id,
"modality": atom.modality.value,
"source": atom.source,
"image_ref": atom.image_ref,
"layout": atom.layout.model_dump() if atom.layout else None,
"score": hit.final_score,
}
sections.append(f"[EVIDENCE]\n{citation}\n{evidence_text}\n[/EVIDENCE]")
packed_text = "\n\n".join(sections)
return context.model_copy(
update={
"hits": hits,
"packed_text": packed_text,
"token_equivalent": max(1, len(packed_text) // 4),
}
)
def extract_markdown_section(text: str, section_hint: str) -> str:
lines = text.splitlines()
start = None
for index, line in enumerate(lines):
stripped = line.strip()
if stripped.startswith("#") and section_hint in stripped:
start = index
break
if start is None:
return ""
end = len(lines)
start_level = len(lines[start]) - len(lines[start].lstrip("#"))
for index in range(start + 1, len(lines)):
stripped = lines[index].strip()
if stripped.startswith("#"):
level = len(lines[index]) - len(lines[index].lstrip("#"))
if level <= start_level:
end = index
break
return "\n".join(lines[start:end])
def relative_artifacts(root: Path) -> dict[str, str]:
artifacts: dict[str, str] = {}
for path in sorted(root.rglob("*")):
if path.is_file():
key = path.relative_to(root).as_posix()
artifacts[key] = key
return artifacts
@@ -0,0 +1,37 @@
"""Find the repository the proof suite is allowed to talk about.
"""
from __future__ import annotations
import os
from pathlib import Path
def project_root() -> Path:
current = Path.cwd().resolve()
for candidate in (current, *current.parents):
if (candidate / "PRD.md").exists() and (candidate / "backend" / "src" / "ely_eye").exists():
return candidate
return current
def discover_repository_files(root: Path) -> list[Path]:
ignored_dirs = {".git", ".ely_eye", ".venv", ".venv-linux", "__pycache__", "node_modules", "dist", "build", "target"}
files: list[Path] = []
for current, dirs, names in os.walk(root):
dirs[:] = [name for name in dirs if name not in ignored_dirs and not name.startswith(".venv")]
current_path = Path(current)
for name in names:
path = current_path / name
try:
relative = path.relative_to(root)
except ValueError:
continue
if any(part in ignored_dirs or part.startswith(".venv") for part in relative.parts):
continue
try:
path.stat()
except OSError:
continue
files.append(path)
return files
+127
View File
@@ -0,0 +1,127 @@
"""The proof suite: one check per claim, and a verdict that says what it proves.
"""
from __future__ import annotations
import hashlib
import secrets
from pathlib import Path
from typing import Literal
from ..cartridge import CartridgeService
from ..config import Settings, get_settings
from ..db import Database
from ..evaluation_schemas import (
ProofCheck,
ProofSuiteReport,
)
from ..schemas import (
CartridgeManifest,
TrainingAdapterKind,
)
from .checks_cartridge import CartridgeChecks
from .checks_runtime import RuntimeChecks
from .checks_training import TrainingChecks
from .checks_visual import VisualChecks
from .report import (
relative_artifacts,
)
class PRDProofSuite(TrainingChecks, CartridgeChecks, RuntimeChecks, VisualChecks):
required_adapters = (
TrainingAdapterKind.hme_core_lora,
TrainingAdapterKind.hme_vision_lora,
TrainingAdapterKind.hme_ttt_vl,
TrainingAdapterKind.hme_visual_mtp,
TrainingAdapterKind.hme_router,
TrainingAdapterKind.hme_retrieval,
)
def __init__(self, settings: Settings | None = None) -> None:
self.settings = settings or get_settings()
self.db = Database(self.settings)
self.cartridges = CartridgeService(self.settings, self.db)
def run(self, cartridge_id: str | None = None) -> ProofSuiteReport:
row = self._resolve_cartridge(cartridge_id)
cartridge_id = str(row["cartridge_id"])
root = Path(row["root_path"])
manifest = CartridgeManifest.model_validate_json(row["manifest_json"])
proof_id = self._proof_id(cartridge_id, manifest.dna)
proof_root = self.settings.data_dir / "eval_proofs" / proof_id
proof_root.mkdir(parents=True, exist_ok=True)
dna_before = manifest.dna
asset_check, manifest = self._cartridge_assets_check(cartridge_id, root, proof_root)
checks = [
self._adapter_training_check(cartridge_id, root, proof_root),
self._runtime_adapter_check(proof_root),
self._runtime_generation_check(proof_root),
asset_check,
self._memory_capsule_check(root, proof_root),
self._cartridge_replay_check(cartridge_id, root, manifest, proof_root),
self._visual_hashhop_check(proof_root),
self._standard_benchmark_check(proof_root),
self._repository_input_check(proof_root),
self._runtime_profile_check(proof_root),
self._research_module_check(proof_root),
self._learned_memory_recall_check(cartridge_id, root, proof_root),
self._memory_dna_check(root, manifest, proof_root),
self._cache_trace_check(proof_root),
self._visual_contradiction_check(proof_root),
]
# A deferred or removed check is not a failure and not a pass: the suite is only as green
# as the checks that actually ran. A claim that never ran holds the verdict, because
# "passed" would say the PRD is proven while part of it was never attempted.
failed = [check for check in checks if check.status == "failed"]
unrun = [check for check in checks if check.status in ("deferred", "removed")]
status: Literal["passed", "failed", "deferred"] = (
"failed" if failed else ("deferred" if unrun else "passed")
)
report = ProofSuiteReport(
proof_id=proof_id,
cartridge_id=cartridge_id,
status=status,
checks=checks,
artifacts={},
dna_before=dna_before,
dna_after=dna_before,
)
report_path = proof_root / "proof_suite.json"
report_path.write_text(report.model_dump_json(indent=2), encoding="utf-8")
report.artifacts = relative_artifacts(proof_root)
report_path.write_text(report.model_dump_json(indent=2), encoding="utf-8")
attached_manifest = self.cartridges.attach_eval_proof(cartridge_id, proof_root)
report.dna_after = attached_manifest.dna
report_path.write_text(report.model_dump_json(indent=2), encoding="utf-8")
cartridge_report = root / "eval_proofs" / proof_id / "proof_suite.json"
cartridge_report.write_text(report.model_dump_json(indent=2), encoding="utf-8")
return report
def runtime_generation_proof(self) -> ProofCheck:
proof_id = f"runtime_generation_{secrets.token_hex(8)}"
proof_root = self.settings.data_dir / "eval_proofs" / proof_id
proof_root.mkdir(parents=True, exist_ok=True)
return self._runtime_generation_check(proof_root)
def visual_contradiction_proof(self) -> ProofCheck:
proof_id = f"visual_contradiction_{secrets.token_hex(8)}"
proof_root = self.settings.data_dir / "eval_proofs" / proof_id
proof_root.mkdir(parents=True, exist_ok=True)
return self._visual_contradiction_check(proof_root)
def latest(self) -> ProofSuiteReport | None:
proof_root = self.settings.data_dir / "eval_proofs"
reports = sorted(
proof_root.glob("prd_proof_suite_*/proof_suite.json"),
key=lambda path: path.stat().st_mtime,
reverse=True,
)
if not reports:
return None
return ProofSuiteReport.model_validate_json(reports[0].read_text(encoding="utf-8"))
def _proof_id(self, cartridge_id: str, dna: str | None) -> str:
raw = f"{cartridge_id}:{dna}:{secrets.token_hex(8)}"
return f"prd_proof_suite_{hashlib.sha256(raw.encode('utf-8')).hexdigest()[:16]}"
+34
View File
@@ -0,0 +1,34 @@
"""Render a proof report as one row per claim, verdict first.
A JSON report hides the shape of the evidence: a deferred claim and a passed claim look equally
short. The table puts the counts on the first line and the reason under every claim that did not
pass, so nobody reads an unrun claim as a proven one.
"""
from __future__ import annotations
from ..evaluation_schemas import ProofSuiteReport
STATUS_ORDER = ("failed", "passed", "deferred", "removed")
def render_table(report: ProofSuiteReport) -> str:
counts: dict[str, int] = {status: 0 for status in STATUS_ORDER}
for check in report.checks:
counts[check.status] = counts.get(check.status, 0) + 1
lines = [
f"proof {report.proof_id} · cartridge {report.cartridge_id} · suite {report.status}",
"counts: " + ", ".join(f"{status} {counts.get(status, 0)}" for status in STATUS_ORDER),
"",
]
for status in STATUS_ORDER:
for check in report.checks:
if check.status != status:
continue
lines.append(f"[{check.status:^7}] {check.name}")
lines.append(f" ran: {check.detail}")
if check.reason:
lines.append(f" why: {check.reason}")
if check.rerun:
lines.append(f" rerun: {check.rerun}")
return "\n".join(lines)
@@ -0,0 +1,358 @@
"""Check that an adapter's training artifacts tell a consistent story.
"""
from __future__ import annotations
import json
import math
from pathlib import Path
from typing import Any
from ..schemas import (
AdapterManifest,
TrainingAdapterKind,
)
from ..training import (
AUTOCAST_DTYPE,
GRADIENT_CHECKPOINTING_MODE,
TRAINING_FRAMEWORK,
TRAINING_METHOD,
TRAINING_PRECISION,
TRAINING_PROOF_VERSION,
safetensor_weight_stats,
sha256_file,
)
def count_safetensor_keys(path: Path) -> int:
return int(safetensor_weight_stats(path)["tensor_count"])
def peft_config_loads(path: Path) -> bool:
try:
from peft import PeftConfig
PeftConfig.from_pretrained(str(path))
return True
except Exception: # noqa: BLE001 # a probe records its failure instead of crashing the proof run
return False
def validate_training_contract(manifest: AdapterManifest) -> dict[str, Any]:
target_modules_ok = training_target_modules_ok(manifest.kind, manifest.target_modules)
report = {
"proof_version_ok": manifest.proof_version >= TRAINING_PROOF_VERSION,
"method_ok": manifest.training_method == TRAINING_METHOD,
"precision_ok": manifest.precision == TRAINING_PRECISION and manifest.bf16,
"framework_ok": manifest.framework == TRAINING_FRAMEWORK,
"optimizer_ok": manifest.optimizer == "paged_adamw_8bit",
"optimizer_family_ok": manifest.optimizer_family == "8-bit AdamW / paged optimizer",
"gradient_checkpointing_ok": (
manifest.gradient_checkpointing
and manifest.gradient_checkpointing_mode == GRADIENT_CHECKPOINTING_MODE
),
"autocast_dtype_ok": manifest.autocast_dtype == AUTOCAST_DTYPE,
"unsloth_version_ok": bool(manifest.unsloth_version),
"triton_version_ok": bool(manifest.triton_version),
"xformers_version_ok": bool(manifest.xformers_version),
"unsloth_model_type_ok": bool(manifest.unsloth_model_type),
"max_length_ok": manifest.max_length >= 8192,
"target_modules_ok": target_modules_ok,
}
report["valid"] = all(report.values())
return report
def training_target_modules_ok(kind: TrainingAdapterKind, target_modules: list[str]) -> bool:
targets = set(target_modules)
core = {"q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"}
if kind == TrainingAdapterKind.hme_core_lora:
return core.issubset(targets)
if kind == TrainingAdapterKind.hme_vision_lora:
return bool(targets) and any("visual" in target or "vision" in target for target in targets)
if kind == TrainingAdapterKind.hme_ttt_vl:
has_visual = any("visual" in target or "vision" in target for target in targets)
has_mlp = bool({"gate_proj", "up_proj", "down_proj"} & targets)
return has_visual and has_mlp
if kind == TrainingAdapterKind.hme_visual_mtp:
return any("mtp" in target or "draft" in target or target == "lm_head" for target in targets)
if kind in {TrainingAdapterKind.hme_router, TrainingAdapterKind.hme_retrieval}:
return core.issubset(targets)
return False
def training_payload_contract_ok(payload: dict[str, Any], manifest: AdapterManifest) -> bool:
return (
int(payload.get("proof_version") or 0) >= TRAINING_PROOF_VERSION
and payload.get("training_method") == TRAINING_METHOD
and payload.get("precision") == TRAINING_PRECISION
and payload.get("framework") == TRAINING_FRAMEWORK
and payload.get("optimizer_family") == manifest.optimizer_family
and bool(payload.get("gradient_checkpointing"))
and payload.get("gradient_checkpointing_mode") == GRADIENT_CHECKPOINTING_MODE
and payload.get("autocast_dtype") == AUTOCAST_DTYPE
and payload.get("unsloth_version") == manifest.unsloth_version
and payload.get("triton_version") == manifest.triton_version
and payload.get("xformers_version") == manifest.xformers_version
and payload.get("unsloth_model_type") == manifest.unsloth_model_type
)
def validate_training_trace(manifest: AdapterManifest, adapter_root: Path) -> dict[str, Any]:
trace_path = adapter_root / "training_trace.jsonl"
summary_path = adapter_root / "training_summary.json"
report: dict[str, Any] = {
"trace_path": str(trace_path),
"summary_path": str(summary_path),
"trace_exists": trace_path.exists(),
"summary_exists": summary_path.exists(),
"trace_sha256_ok": False,
"summary_sha256_ok": False,
"step_records": 0,
"loss_history_records": len(manifest.loss_history),
"loss_history_ok": False,
"summary_matches_manifest": False,
"summary_contract_ok": False,
"run_start_contract_ok": False,
"run_finish_contract_ok": False,
"cuda_training": False,
"bf16_supported": False,
"bf16": manifest.bf16,
"valid": False,
}
if not trace_path.exists() or not summary_path.exists():
return report
try:
trace_rows = [
json.loads(line)
for line in trace_path.read_text(encoding="utf-8").splitlines()
if line.strip()
]
summary = json.loads(summary_path.read_text(encoding="utf-8"))
except json.JSONDecodeError:
return report
step_rows = [row for row in trace_rows if row.get("event") == "step"]
start_row: dict[str, Any] = next((row for row in trace_rows if row.get("event") == "run_start"), {})
finish_row: dict[str, Any] = next(
(row for row in reversed(trace_rows) if row.get("event") == "run_finish"), {}
)
losses = [row.get("loss") for row in step_rows]
finite_losses = all(isinstance(loss, (int, float)) and math.isfinite(float(loss)) for loss in losses)
final_loss_ok = (
manifest.final_loss is not None
and bool(losses)
and abs(float(losses[-1]) - float(manifest.final_loss)) < 1e-6
)
report.update(
{
"trace_sha256_ok": (
manifest.training_trace_sha256 is not None
and sha256_file(trace_path) == manifest.training_trace_sha256
),
"summary_sha256_ok": (
manifest.training_summary_sha256 is not None
and sha256_file(summary_path) == manifest.training_summary_sha256
),
"step_records": len(step_rows),
"loss_history_ok": (
len(manifest.loss_history) == manifest.max_steps
and finite_losses
and final_loss_ok
),
"summary_matches_manifest": (
summary.get("adapter_kind") == manifest.kind.value
and summary.get("base_model") == manifest.base_model
and summary.get("dataset_sha256") == manifest.dataset_sha256
and int(summary.get("max_steps") or -1) == manifest.max_steps
and int(summary.get("trainable_params") or -1) == manifest.trainable_params
),
"summary_contract_ok": training_payload_contract_ok(summary, manifest),
"run_start_contract_ok": training_payload_contract_ok(start_row, manifest),
"run_finish_contract_ok": training_payload_contract_ok(finish_row, manifest),
}
)
environment = summary.get("environment") if isinstance(summary.get("environment"), dict) else {}
device_name = str(environment.get("device_name") or "")
report["cuda_training"] = bool(environment.get("cuda_available")) and "RTX 4090" in device_name
report["bf16_supported"] = bool(environment.get("bf16_supported"))
report["valid"] = (
report["trace_sha256_ok"]
and report["summary_sha256_ok"]
and report["step_records"] == manifest.max_steps
and report["loss_history_ok"]
and report["summary_matches_manifest"]
and report["summary_contract_ok"]
and report["run_start_contract_ok"]
and report["run_finish_contract_ok"]
and report["cuda_training"]
and report["bf16_supported"]
and manifest.bf16
)
return report
def validate_training_proof(manifest: AdapterManifest, adapter_root: Path) -> dict[str, Any]:
proof_path = adapter_root / "training_proof.json"
report: dict[str, Any] = {
"proof_path": str(proof_path),
"proof_exists": proof_path.exists(),
"proof_sha256_ok": False,
"hash_changed": False,
"optimizer_update_count": manifest.optimizer_update_count,
"optimizer_update_count_ok": False,
"max_optimizer_update_l2": manifest.max_optimizer_update_l2,
"max_optimizer_update_l2_ok": False,
"loss_delta": manifest.loss_delta,
"loss_delta_finite": False,
"updates_have_gradients": False,
"updates_have_weight_delta": False,
"proof_weight_sha256_ok": False,
"proof_weight_stats_ok": False,
"proof_cuda_bf16": False,
"proof_bf16_supported": False,
"proof_contract_ok": False,
"proof_optimizer_ok": False,
"proof_max_length_ok": False,
"proof_target_modules_ok": False,
"proof_unsloth_runtime_ok": False,
"proof_matches_manifest": False,
"valid": False,
}
if not proof_path.exists():
return report
try:
proof = json.loads(proof_path.read_text(encoding="utf-8"))
except json.JSONDecodeError:
return report
updates = proof.get("optimizer_updates") if isinstance(proof.get("optimizer_updates"), list) else []
update_l2_values = [
float(value)
for item in updates
if isinstance(item, dict) and isinstance(value := item.get("update_l2"), (int, float))
]
gradient_l2_values = [
float(value)
for item in updates
if isinstance(item, dict) and isinstance(value := item.get("gradient_l2"), (int, float))
]
weight_report = safetensor_weight_stats(adapter_root / "adapter_model.safetensors")
proof_weight_stats = proof.get("adapter_weight_stats") if isinstance(proof.get("adapter_weight_stats"), dict) else {}
proof_environment = proof.get("environment") if isinstance(proof.get("environment"), dict) else {}
report.update(
{
"proof_sha256_ok": (
manifest.training_proof_sha256 is not None
and sha256_file(proof_path) == manifest.training_proof_sha256
),
"hash_changed": (
bool(manifest.initial_trainable_sha256)
and bool(manifest.final_trainable_sha256)
and manifest.initial_trainable_sha256 != manifest.final_trainable_sha256
),
"optimizer_update_count_ok": (
manifest.optimizer_update_count > 0
and len(updates) == manifest.optimizer_update_count
),
"max_optimizer_update_l2_ok": (
manifest.max_optimizer_update_l2 is not None
and math.isfinite(float(manifest.max_optimizer_update_l2))
and float(manifest.max_optimizer_update_l2) > 0.0
),
"loss_delta_finite": (
manifest.loss_delta is not None
and math.isfinite(float(manifest.loss_delta))
),
"updates_have_gradients": bool(gradient_l2_values)
and all(math.isfinite(value) and value > 0.0 for value in gradient_l2_values),
"updates_have_weight_delta": bool(update_l2_values)
and all(math.isfinite(value) and value > 0.0 for value in update_l2_values),
"proof_weight_sha256_ok": (
isinstance(proof.get("adapter_weight_sha256"), str)
and proof.get("adapter_weight_sha256") == weight_report["sha256"]
),
"proof_weight_stats_ok": (
proof_weight_stats.get("sha256") == weight_report["sha256"]
and proof_weight_stats.get("tensor_count") == weight_report["tensor_count"]
and proof_weight_stats.get("lora_tensor_count") == weight_report["lora_tensor_count"]
and proof_weight_stats.get("total_elements") == weight_report["total_elements"]
and proof_weight_stats.get("nonzero_elements") == weight_report["nonzero_elements"]
and int(proof_weight_stats.get("lora_tensor_count") or 0) > 0
and int(proof_weight_stats.get("nonzero_elements") or 0) > 0
and bool(proof_weight_stats.get("all_finite"))
),
"proof_cuda_bf16": (
bool(proof.get("bf16"))
and bool(proof_environment.get("cuda_available"))
and "RTX 4090" in str(proof_environment.get("device_name") or "")
),
"proof_bf16_supported": bool(proof_environment.get("bf16_supported")),
"proof_contract_ok": training_payload_contract_ok(proof, manifest),
"proof_optimizer_ok": proof.get("optimizer") == "paged_adamw_8bit",
"proof_max_length_ok": int(proof.get("max_length") or 0) >= 8192,
"proof_target_modules_ok": training_target_modules_ok(
manifest.kind,
proof.get("target_modules") if isinstance(proof.get("target_modules"), list) else [],
),
"proof_unsloth_runtime_ok": (
bool(proof.get("unsloth_version"))
and bool(proof.get("triton_version"))
and bool(proof.get("xformers_version"))
and bool(proof.get("unsloth_model_type"))
),
"proof_matches_manifest": (
proof.get("adapter_kind") == manifest.kind.value
and proof.get("proof_version") == manifest.proof_version
and proof.get("training_method") == manifest.training_method
and proof.get("precision") == manifest.precision
and proof.get("framework") == manifest.framework
and proof.get("base_model") == manifest.base_model
and proof.get("dataset_sha256") == manifest.dataset_sha256
and proof.get("sample_count") == manifest.sample_count
and proof.get("max_steps") == manifest.max_steps
and proof.get("max_length") == manifest.max_length
and proof.get("rank") == manifest.rank
and proof.get("alpha") == manifest.alpha
and proof.get("target_modules") == manifest.target_modules
and proof.get("optimizer") == manifest.optimizer
and proof.get("optimizer_family") == manifest.optimizer_family
and proof.get("learning_rate") == manifest.learning_rate
and proof.get("gradient_accumulation_steps") == manifest.gradient_accumulation_steps
and proof.get("gradient_checkpointing") == manifest.gradient_checkpointing
and proof.get("gradient_checkpointing_mode") == manifest.gradient_checkpointing_mode
and proof.get("autocast_dtype") == manifest.autocast_dtype
and proof.get("unsloth_version") == manifest.unsloth_version
and proof.get("triton_version") == manifest.triton_version
and proof.get("xformers_version") == manifest.xformers_version
and proof.get("unsloth_model_type") == manifest.unsloth_model_type
and proof.get("bf16") == manifest.bf16
and proof.get("trainable_params") == manifest.trainable_params
and proof.get("total_params") == manifest.total_params
and proof.get("initial_trainable_sha256") == manifest.initial_trainable_sha256
and proof.get("final_trainable_sha256") == manifest.final_trainable_sha256
and proof.get("optimizer_update_count") == manifest.optimizer_update_count
and proof.get("max_optimizer_update_l2") == manifest.max_optimizer_update_l2
),
}
)
report["valid"] = (
report["proof_sha256_ok"]
and report["hash_changed"]
and report["optimizer_update_count_ok"]
and report["max_optimizer_update_l2_ok"]
and report["loss_delta_finite"]
and report["updates_have_gradients"]
and report["updates_have_weight_delta"]
and report["proof_weight_sha256_ok"]
and report["proof_weight_stats_ok"]
and report["proof_cuda_bf16"]
and report["proof_bf16_supported"]
and report["proof_contract_ok"]
and report["proof_optimizer_ok"]
and report["proof_max_length_ok"]
and report["proof_target_modules_ok"]
and report["proof_unsloth_runtime_ok"]
and report["proof_matches_manifest"]
)
return report
+9 -1
View File
@@ -38,11 +38,19 @@ def fts_query(query: str) -> str:
A CJK run becomes a quoted phrase so its characters stay adjacent: unphrased, a query for A CJK run becomes a quoted phrase so its characters stay adjacent: unphrased, a query for
钥匙 would match text that mentions 钥 and 匙 worlds apart. Latin tokens get a prefix match, 钥匙 would match text that mentions 钥 and 匙 worlds apart. Latin tokens get a prefix match,
which is what lets `atom` reach `atoms`. which is what lets `atom` reach `atoms`.
Latin tokens are OR-ed, not AND-ed. A question is longer than the sentence that answers it —
"Which PRD requirements prove long context memory, HashHop, and adapters?" shares only some of
its words with any single atom — and an AND over every word answers such a question with
nothing. bm25 then ranks the candidates by how many of those words each one carries, so the
broadened query does not mean a diluted answer.
""" """
terms = _bare(query).split() terms = _bare(query).split()
if not terms: if not terms:
raise ValueError(f"search needs at least one searchable word, got {query!r}") raise ValueError(f"search needs at least one searchable word, got {query!r}")
return " ".join(_cjk_phrase(term) if _is_cjk(term) else f"{_quote(term)}*" for term in terms) if len(terms) == 1:
return _cjk_phrase(terms[0]) if _is_cjk(terms[0]) else f"{_quote(terms[0])}*"
return " OR ".join(_cjk_phrase(term) if _is_cjk(term) else f"{_quote(term)}*" for term in terms)
def _bare(text: str) -> str: def _bare(text: str) -> str:
+282
View File
@@ -0,0 +1,282 @@
"""A proof check reports what it measured: passed, failed, deferred, or removed."""
from __future__ import annotations
from pathlib import Path
from typing import Literal
import pytest
from PIL import Image
from ely_eye.cartridge import CartridgeService
from ely_eye.config import Settings
from ely_eye.memory import MemoryService
from ely_eye.proofs import PRDProofSuite
from ely_eye.proofs.arena import (
_slot_boxes,
render_visual_hash,
render_visual_hash_arena,
)
from ely_eye.proofs.checks_common import _deferred_without_model
from ely_eye.proofs.contradictions import (
PACKAGED_CORPUS,
build_contradiction_scenarios,
load_corpus,
)
from ely_eye.proofs.table import render_table
from ely_eye.schemas import MemoryOrigin
# The replay question is fixed inside the suite, so the fixture memory has to answer it in words
# the ranker can match.
PRD_MEMORY = "PRD requirements prove long context memory, HashHop proof, and adapter training."
OTHER_KEYS = "PRD requirements also prove cache invalidation for HashHop proof and adapters."
class Harness:
"""A suite wired to one temporary store, plus the directory its artifacts land in."""
def __init__(self, settings: Settings) -> None:
self.settings = settings
self.memory = MemoryService(settings=settings)
self.db = self.memory.db
self.cartridges = CartridgeService(settings=settings, database=self.db)
self.suite = PRDProofSuite(settings)
self.proof_root = settings.data_dir / "eval_proofs" / "test"
self.proof_root.mkdir(parents=True, exist_ok=True)
def remember(self, text: str) -> str:
atom = self.memory.remember(text, holder_id="wife", origin=MemoryOrigin.self_, scenario="home")
return atom.atom_id
def cartridge(self, name: str, atom_ids: list[str]) -> str:
atoms = self.db.get_atoms(atom_ids)
sources = self.db.get_sources(sorted({atom.source_id for atom in atoms}))
return self.cartridges.materialize(name, atoms, sources).cartridge_id
@pytest.fixture
def harness(tmp_path: Path, model_dir: Path) -> Harness:
return Harness(Settings(home=tmp_path / "home", model_dir=model_dir, default_holder="wife"))
def test_a_store_with_nothing_to_ask_fails_the_cache_trace_check(harness: Harness) -> None:
check = harness.suite._cache_trace_check(harness.proof_root)
assert check.status == "failed"
assert "empty store" in check.reason
def test_the_cache_trace_check_requires_a_measured_miss_then_hit(harness: Harness) -> None:
harness.remember(PRD_MEMORY)
check = harness.suite._cache_trace_check(harness.proof_root)
assert check.status == "passed", check.detail
assert check.reason == ""
def test_the_research_module_check_is_removed_because_it_could_not_fail(
harness: Harness,
) -> None:
check = harness.suite._research_module_check(harness.proof_root)
assert check.status == "removed"
assert check.reason and check.rerun
def test_the_repository_check_fails_when_the_repository_never_reached_the_store(
harness: Harness,
) -> None:
check = harness.suite._repository_input_check(harness.proof_root)
assert check.status == "failed"
assert "store" in check.detail or "store" in check.reason
def test_the_replay_check_answers_only_from_the_cartridge_it_mounts(harness: Harness) -> None:
inside = harness.remember(PRD_MEMORY)
# A second memory that answers the same question but stays out of the cartridge: an unmounted
# replay against the live store would have found it and called that a cartridge replay.
harness.remember(OTHER_KEYS)
cartridge_id = harness.cartridge("keys", [inside])
manifest = next(
item for item in harness.cartridges.list_manifests() if item.cartridge_id == cartridge_id
)
check = harness.suite._cartridge_replay_check(
cartridge_id, harness.settings.cartridge_dir / cartridge_id, manifest, harness.proof_root
)
assert check.status == "passed", check.detail
assert harness.cartridges.mount_state().mounted == []
def test_a_check_defers_loudly_when_the_model_it_needs_is_missing(
tmp_path: Path, model_dir: Path
) -> None:
without = _deferred_without_model(
Settings(home=tmp_path / "a"),
tmp_path / "a" / "artifact.json",
"Runtime Adapter Binding",
"PRD 18 requires the trained adapter to run.",
"ely-eye proof runtime with model_dir set",
)
with_model = _deferred_without_model(
Settings(home=tmp_path / "b", model_dir=model_dir),
tmp_path / "b" / "artifact.json",
"Runtime Adapter Binding",
"PRD 18 requires the trained adapter to run.",
"ely-eye proof runtime with model_dir set",
)
assert without is not None and without.status == "deferred"
assert without.rerun == "ely-eye proof runtime with model_dir set"
assert (tmp_path / "a" / "artifact.json").exists()
assert with_model is None
def test_the_table_shows_the_verdict_counts_and_the_reason_for_each_claim() -> None:
from ely_eye.evaluation_schemas import ProofCheck, ProofSuiteReport
report = ProofSuiteReport(
proof_id="proof-1",
cartridge_id="cart-1",
status="deferred",
artifacts={},
checks=[
ProofCheck(name="Ran", requirement="r", status="passed", evidence=[], detail="measured x"),
ProofCheck(
name="Waiting",
requirement="r",
status="deferred",
evidence=[],
detail="nothing ran",
reason="no model weights",
rerun="ely-eye proof suite",
),
],
)
table = render_table(report)
assert "counts: failed 0, passed 1, deferred 1, removed 0" in table
assert "why: no model weights" in table
assert "rerun: ely-eye proof suite" in table
assert table.index("[passed ") < table.index("[deferred")
assert "[failed" not in table and "[removed" not in table
def test_the_latest_command_prints_the_table_and_exits_by_verdict(
tmp_path: Path, monkeypatch
) -> None:
import json
from typer.testing import CliRunner
from ely_eye import cli as cli_module
from ely_eye.evaluation_schemas import ProofCheck, ProofSuiteReport
settings = Settings(home=tmp_path / "home")
monkeypatch.setattr(cli_module, "get_settings", lambda: settings)
proof_root = settings.data_dir / "eval_proofs"
ran = ProofCheck(name="Ran", requirement="r", status="passed", evidence=[], detail="ok")
cases: list[tuple[str, Literal["failed", "deferred"]]] = [
("prd_proof_suite_old", "failed"),
("prd_proof_suite_new", "deferred"),
]
for proof_id, status in cases:
report = ProofSuiteReport(
proof_id=proof_id,
cartridge_id="cart-1",
status=status,
artifacts={},
checks=[ran],
)
directory = proof_root / proof_id
directory.mkdir(parents=True)
(directory / "proof_suite.json").write_text(report.model_dump_json(), encoding="utf-8")
table = CliRunner().invoke(cli_module.app, ["latest-proof-suite"])
machine = CliRunner().invoke(cli_module.app, ["latest-proof-suite", "--json"])
assert table.exit_code == 0
assert "proof prd_proof_suite_new" in table.stdout
assert json.loads(machine.stdout)["proof_id"] == "prd_proof_suite_new"
(proof_root / "prd_proof_suite_new" / "proof_suite.json").write_text(
ProofSuiteReport(
proof_id="prd_proof_suite_new",
cartridge_id="cart-1",
status="failed",
artifacts={},
checks=[ran],
).model_dump_json(),
encoding="utf-8",
)
failing = CliRunner().invoke(cli_module.app, ["latest-proof-suite"])
assert failing.exit_code == 1
monkeypatch.setattr(cli_module, "get_settings", lambda: Settings(home=tmp_path / "empty"))
nothing = CliRunner().invoke(cli_module.app, ["latest-proof-suite"])
assert nothing.exit_code != 0
assert "no proof suite" in nothing.stdout + nothing.stderr # says so instead of printing null
def test_the_packaged_corpus_matches_the_scenarios_it_was_written_from() -> None:
scenarios, digest = load_corpus(PACKAGED_CORPUS)
built = build_contradiction_scenarios()
assert [item["name"] for item in scenarios] == [item["name"] for item in built]
assert [item["expect_drift"] for item in scenarios] == [
item["expect_drift"] for item in built
]
assert len(scenarios) >= 10 and digest
def test_the_contradiction_check_defers_when_no_corpus_exists_and_names_the_file(
harness: Harness, monkeypatch
) -> None:
from ely_eye.proofs import checks_visual as visual_module
monkeypatch.setattr(visual_module, "corpus_path", lambda data_dir: None)
check = harness.suite._visual_contradiction_check(harness.proof_root)
assert check.status == "deferred"
assert "contradiction_scenarios.json" in check.rerun
assert check.detail == "no contradiction corpus on disk"
def test_the_contradiction_check_records_which_corpus_it_graded_against(
harness: Harness,
) -> None:
import json
check = harness.suite._visual_contradiction_check(harness.proof_root)
artifact = json.loads(
(harness.proof_root / "visual_contradiction_lens.json").read_text(encoding="utf-8")
)
assert check.status == "deferred" # graded on our own corpus: reported, not claimed
assert artifact["corpus_sha256"]
assert len(artifact["metrics"]["detected_categories"]) >= 5, artifact["metrics"]
def test_the_hashhop_arena_marks_no_candidate_as_the_answer(harness: Harness, tmp_path: Path) -> None:
boxes = _slot_boxes(520, 704, 76, 324, 160)
tiles = {}
for slot in boxes:
path = tmp_path / f"{slot}.png"
render_visual_hash(slot, path, 160)
tiles[slot] = path
output = tmp_path / "arena.png"
render_visual_hash_arena(tiles["top-left"], tiles, output)
# Every candidate box carries the same outline: a ring, an arrow, or a highlighted slot would
# tell a model the answer without reading a pixel of the source tile.
image = Image.open(output).convert("RGB")
border_colors = {image.getpixel((box[0] + 2, box[1] + 40)) for box in boxes.values()}
assert border_colors == {(180, 190, 205)}
+38 -3
View File
@@ -24,6 +24,16 @@ def _hits(connection: sqlite3.Connection, query: str) -> list[str]:
return [row[0] for row in connection.execute("SELECT original FROM fts WHERE fts MATCH ?", (fts_query(query),))] return [row[0] for row in connection.execute("SELECT original FROM fts WHERE fts MATCH ?", (fts_query(query),))]
def _ranked(connection: sqlite3.Connection, query: str) -> list[str]:
"""Matches in bm25 order: the answer that covers more of the question should come first."""
return [
row[0]
for row in connection.execute(
"SELECT original FROM fts WHERE fts MATCH ? ORDER BY rank", (fts_query(query),)
)
]
def test_index_text_splits_a_chinese_sentence_into_characters() -> None: def test_index_text_splits_a_chinese_sentence_into_characters() -> None:
assert index_text("我们的钥匙放在玄关抽屉里") == "我 们 的 钥 匙 放 在 玄 关 抽 屉 里" assert index_text("我们的钥匙放在玄关抽屉里") == "我 们 的 钥 匙 放 在 玄 关 抽 屉 里"
@@ -40,7 +50,28 @@ def test_index_text_folds_full_width_letters_that_search_would_miss() -> None:
def test_fts_query_phrases_cjk_and_prefixes_latin() -> None: def test_fts_query_phrases_cjk_and_prefixes_latin() -> None:
assert fts_query("钥匙") == '"钥 匙"' assert fts_query("钥匙") == '"钥 匙"'
assert fts_query("search atoms") == '"search"* "atoms"*' assert fts_query("search atoms") == '"search"* OR "atoms"*'
def test_a_long_question_reaches_the_answer_that_covers_most_of_its_words() -> None:
"""AND over every word answers a long question with nothing; bm25 picks the best candidate."""
connection = _fts(
[
"PRD requirements prove long context memory, HashHop proof, and adapter training.",
"The adapter was trained for 29 steps on 37 samples.",
"Unrelated notes about the weather.",
]
)
question = "Which Ely-Eye PRD requirements prove long context memory, HashHop, and adapters?"
hits = [
row[0]
for row in connection.execute(
"SELECT original FROM fts WHERE fts MATCH ? ORDER BY rank", (fts_query(question),)
)
]
assert hits[0].startswith("PRD requirements prove")
assert "Unrelated notes about the weather." not in hits
def test_fts_query_refuses_a_query_with_nothing_to_match() -> None: def test_fts_query_refuses_a_query_with_nothing_to_match() -> None:
@@ -70,6 +101,10 @@ def test_a_prefix_reaches_the_word_it_grew_into() -> None:
assert _hits(connection, "forg") == ["the atom was forgotten"] assert _hits(connection, "forg") == ["the atom was forgotten"]
def test_a_mixed_query_needs_both_halves_in_the_same_memory() -> None: def test_a_mixed_query_ranks_the_memory_holding_both_halves_first() -> None:
"""A query with a Chinese half and an English half must prefer the memory holding both."""
connection = _fts(["钥匙放在 drawer 里", "钥匙在玄关", "the drawer is empty"]) connection = _fts(["钥匙放在 drawer 里", "钥匙在玄关", "the drawer is empty"])
assert _hits(connection, "钥匙 drawer") == ["钥匙放在 drawer 里"] ranked = _ranked(connection, "钥匙 drawer")
assert ranked[0] == "钥匙放在 drawer 里"
assert set(ranked) == {"钥匙放在 drawer 里", "钥匙在玄关", "the drawer is empty"}