Files
ZacharyZhang-NY 89c880fd36 Say what the store actually does, and put a receipt under each claim
The README described a project that no longer exists: a Windows-only Qwen
runtime with nine read-only tools, a console as the only way to operate the
store, and a 100M-token capsule as if it were measured. It is now a description
of what is here, with the report and the command that re-measures each number,
and a section that names what has not been run instead of leaving the reader to
discover it.

TRAINING_ARTIFACTS.md keeps its artifact tables and loses the scores that were
never run: MMMU-Pro and OCRBench each read one sample, and the HashHop gate
collected proofs until it hit its target. What stays is annotated with what it
actually measures — citation accuracy there means the cited id existed in the
context that was handed over, not that the passage supports the answer.

Gaps.md gains a re-audit section: ten of the twelve gaps closed, two partial,
each row naming the command or report behind it, and the remaining work stated
plainly — the 0.90 recall bar is unmet and the deficit is entirely in the
visual and audio legs.

AGENTS.md stops being ignored. It records the constraints this repository paid
for: the measurement rules, the environment traps, and the review protocol, so
the next agent does not pay them again.

The CLI could filter by holder but could not look through a holder's eyes, so
search gains --as-holder: three states of eyes on every face, not two.
2026-10-09 16:11:53 -04:00

120 lines
5.2 KiB
Python

"""Search over HTTP: the answers a caller can act on, and the reasons it gets none."""
from __future__ import annotations
from pathlib import Path
import pytest
from fastapi.testclient import TestClient
import ely_eye.api as api_module
from ely_eye.config import Settings
from ely_eye.db import Database
from ely_eye.memory import MemoryService
from ely_eye.schemas import MemoryOrigin
KEYS = "我们的钥匙放在玄关抽屉里"
PASSPORT = "护照在书房第二个抽屉里"
WALLET = "钱包在玄关的挂钩上"
@pytest.fixture
def client(tmp_path: Path, monkeypatch: pytest.MonkeyPatch, write_token: str) -> TestClient:
settings = Settings(home=tmp_path, default_holder="wife", auth_token=write_token)
monkeypatch.setattr(api_module, "get_settings", lambda: settings)
return TestClient(api_module.create_app(), headers={"Authorization": f"Bearer {write_token}"})
def search(client: TestClient, payload: dict) -> dict:
response = client.post("/api/search", json=payload)
assert response.status_code in (200, 422), response.text
return response.json()
def test_a_chinese_question_finds_the_memory_it_was_written_in(client: TestClient) -> None:
client.post("/api/memory", json={"text": KEYS, "scenario": "home"})
answer = search(client, {"query": "钥匙"})
assert answer["status"] == "hits"
assert [hit["atom"]["text"] for hit in answer["hits"]] == [KEYS]
def test_an_empty_corpus_answers_no_match_rather_than_an_empty_array(client: TestClient) -> None:
answer = search(client, {"query": "钥匙"})
assert answer["hits"] == []
assert answer["status"] == "no_match", "an empty answer must say the corpus has nothing"
def test_a_query_with_nothing_searchable_is_refused_with_the_reason(client: TestClient) -> None:
response = client.post("/api/search", json={"query": "???"})
assert response.status_code == 422
assert "needs at least one searchable word" in response.json()["detail"]
def test_the_scenario_filter_hides_memories_from_other_scenarios(client: TestClient) -> None:
client.post("/api/memory", json={"text": KEYS, "scenario": "home"})
assert search(client, {"query": "钥匙", "filters": {"scenario": "home"}})["status"] == "hits"
assert search(client, {"query": "钥匙", "filters": {"scenario": "travel"}})["status"] == "no_match"
def test_a_superseded_memory_stops_answering(client: TestClient) -> None:
old = client.post("/api/memory", json={"text": KEYS}).json()
client.post("/api/memory/supersede", json={"atom_id": old["atom_id"], "text": PASSPORT})
answer = search(client, {"query": "抽屉"})
assert [hit["atom"]["text"] for hit in answer["hits"]] == [PASSPORT]
def test_paging_walks_every_hit_without_skipping_one(client: TestClient) -> None:
for text in (KEYS, PASSPORT, WALLET, "备用钥匙在车里", "工具箱在阳台的抽屉里"):
client.post("/api/memory", json={"text": text})
seen: list[str] = []
cursor = None
for _ in range(10):
payload: dict = {"query": "钥匙", "top_k": 2}
if cursor:
payload["cursor"] = cursor
answer = search(client, payload)
seen.extend(hit["atom"]["atom_id"] for hit in answer["hits"])
cursor = answer["next_cursor"]
if not cursor:
break
assert cursor is None, "the page loop never reached the end"
assert len(seen) == len(set(seen)), "a page repeated a memory"
assert len(seen) == 2, "only two memories mention 钥匙"
def test_the_holder_filter_answers_only_that_holders_memory(
client: TestClient, tmp_path: Path
) -> None:
client.post("/api/memory", json={"text": KEYS})
husband = MemoryService(Settings(home=tmp_path, default_holder="husband"), Database(Settings(home=tmp_path)))
husband.remember("我的钥匙在办公室", holder_id="husband", origin=MemoryOrigin.self_)
answer = search(client, {"query": "钥匙", "filters": {"holder": "husband"}})
assert [hit["atom"]["text"] for hit in answer["hits"]] == ["我的钥匙在办公室"]
def test_the_cli_answers_in_json_a_machine_can_read(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
"""The three faces rank alike: the CLI reports the same hit the HTTP face returns."""
import json
from typer.testing import CliRunner
import ely_eye.cli as cli_module
from ely_eye.cli import app
settings = Settings(home=tmp_path, default_holder="wife")
monkeypatch.setattr(cli_module, "get_settings", lambda: settings)
runner = CliRunner()
MemoryService(settings, Database(settings)).remember(KEYS, holder_id="wife", origin=MemoryOrigin.self_, scenario="home")
answer = json.loads(runner.invoke(app, ["search", "钥匙", "--scenario", "home"]).stdout)
assert answer["status"] == "hits"
assert [hit["atom"]["text"] for hit in answer["hits"]] == [KEYS]
empty = json.loads(runner.invoke(app, ["search", "钥匙", "--scenario", "travel"]).stdout)
assert empty["status"] == "no_match"
stranger = json.loads(runner.invoke(app, ["search", "钥匙", "--as-holder", "stranger"]).stdout)
assert stranger["status"] == "no_match", "--as-holder must show what a stranger would see"
owner = json.loads(runner.invoke(app, ["search", "钥匙", "--as-holder", "wife"]).stdout)
assert [hit["atom"]["text"] for hit in owner["hits"]] == [KEYS]