Files
brain-of-reese/tests/unit/test_source_chip_quality.py
ducoterra a5b63f83ad
Build and Push Containers / build-and-push-app (push) Successful in 2m1s
Build and Push Containers / build-and-push-db (push) Successful in 18s
phase: 119_name_signal_read_chips
All verification complete. Final report:

**Phase 119 final verification pass — all criteria verified, one stale pin fixed.**
- Verified implementation of all 6 tasks: D1 component name-hit rule (`name_hit` flag, titles never matched, retired length tie-break), D2 `BOR_NAME_HIT_BONUS` (0.005 default, 0 = byte-identical kill switch, negative fails startup, selection-layer only, `eval_retrieval` `suggested:` line), D3 suggested-folder lines (after `SUGGEST_INTRO`, before first block), D4 cite-discipline `SUGGEST_INTRO` sentence (PERSONA/LOW/`TOOLS_SECTION` byte-pins intact), D5 `done.sources` = read docs only (frontend no-op on empty confirmed), D6 mock `repeat your folder map` echo + new suite + telemetry.
- Battery (replica restored per skill, fingerprint docs=1000/chunks=8866 verified, `eval_retrieval --from-file tests/fixtures/retrieval_battery.txt` re-run): **GATE PASS** — gitea README #4 in suggested top-5, forgejo 5/5 (README #1), gateway README in top-5 (#4), qwen3.8-27b quadlets top-5, Mongolia HIGH/fts=5 unchanged.
- New E2E in isolation: `4 passed` ×2 (deterministic). All 27 modified E2E suites in isolation: 26 green; **1 stale pin fixed** — `test_source_chip_quality.py` durable-record order pin pre-dated the D1 re-rank (`aliases` stem sub-component name-hits `ssh_aliases.txt`, deterministically lifting `backups.md` over `kubernetes.md`; probe-verified 0.016277 vs 0.016036, 4/4 stable) — re-pinned with the phase-119 rationale; suite green ×2.
- Gates: `uv run pytest --cov=app --cov-report=term-missing` → **2547 passed, app coverage 99%** (>90%); `uv run ruff check .` → All checks passed; `uv run pyright` → 0 errors.
- Completion criteria: 1 ✅ (battery, recorded), 2 ✅ (folder lines; block/LOW byte-identical pins green), 3 ✅ (read-only chips, zero-read chips nothing, related row + durable record untouched — unit+E2E agree), 4 ✅ (all green), 5 → commit/phase-move left to the harness per pass rules (nothing committed).
- Deviations: battery output + real-model telemetry recorded in `.agents/reports/119_name_signal_read_chips/task06_battery_and_e2e.md` and `TOOL_CALLING_TESTING.md` §11 (task files in `complete/` are immutable to this pass); gateway canonical doc at #4 vs overview's #3 was already documented at task 06 (containment gate met).
- Next pending phase: **none** — `todo/` holds only phase 119.
2026-09-16 15:50:48 -04:00

860 lines
37 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Unit: the phase-113 source-chip-quality contract (TODO L5 + L2c —
"the 2nd chip is often noise the answer never used").
Phase 118 re-tiers the same frame (LOCKED A3/A4): ``sources`` carries
the suggested tier (top-5, NO floor) + the agent-read docs (deduped)
— rendered by ``appendSources`` as ``.source-chip`` pills, UNCHANGED —
and ``related`` carries rank 6+ after the suggested set (rendered by
``appendRelated`` as the de-emphasized labeled row — ``.related-doc``
links, never ``.source-chip``). A deflected turn carries
``sources: []`` → zero chips; its weak hits are the suggested tier
(the durable record), and with ≤5 retrieved docs the related row is
empty.
This module pins the STATIC SOURCES the UI contract stands on, in the
house source-pin pattern (the test_chip_sizing_question_cap.py
``_rule`` style):
* task 02 — the frontend: ``appendRelated`` exists and never builds a
``source-chip``; the row renders only when ``related`` is non-empty;
the label copy is present; the done-frame handler and the restore path
both call it (the related tier persists with the turn, so a reload
re-renders the row exactly as it looked live); the CSS row is clearly
secondary (dashed border, muted ink, flat hover);
* task 03 — the acceptance pin (TODO L5): the FOUR OBSERVED LIVE SHAPES
(L110–123), each modeled as a ``plan_turn`` fixture with controlled
cosine/``fts_hit``/fused ``score`` under the production calibration
(the code defaults — the shapes were observed live):
1. **both docs weak** ("What is the capital of Mongolia?" →
``Trooper_Nagraz.pl`` + ``Trooper_Begzei.pl``, both unrelated) —
the weak hits are SUGGESTED (no floor, A3; the durable record),
nothing left for the related tier; the FTS hit without vector
corroboration stays LOW (the A8-revised "Mongolia" case);
2. **one strong + one weak** (the phase-gate question answered from
``brain-of-reese/.agents/validate.sh``; ``ServMon/README.md``
alongside) — BOTH suggested (no floor) ⇒ both cited refs (A4),
no related tier;
3. **the Nagraz case** (``Trooper_Nagraz.pl`` strong,
``Trooper_Byzin.pl`` weak — same shape, different fixtures);
4. **the meta/history question** (the agent reads nothing —
``app/api/suggestions.py`` + ``108_history_wire_check/00_phase.md``
alongside) — pinned on the DONE FRAME (endpoint-level, fake
retriever/LLM/session): ``sources: []`` (zero chips) and an EMPTY
related row (both weak docs are suggested, ≤5 docs retrieved);
5. **the agent-read exemption** (LOCKED A4): a rank-6+ (related-
tier) doc the agent ``read`` via the tool joins ``sources``
(cited, last) and is excluded from ``related``.
The browser behavior (chip counts on a single-source question, zero
chips on a deflected turn) is E2E-gated by
tests/e2e/test_source_chip_quality.py (task 03).
"""
from __future__ import annotations
import json
import re
import uuid
from collections.abc import Iterator
from datetime import UTC, datetime
from pathlib import Path
from typing import TYPE_CHECKING, Any
import pytest
from fastapi.testclient import TestClient
from app.api import chat as chat_api
from app.config import Settings
from app.main import app as fastapi_app
from app.models import Document, QueryLog
from app.rag import agent
from app.rag.llm import StreamPiece, ToolCallPiece
from app.rag.retriever import RetrievedChunk
from tests.conftest import ADMIN_PASSWORD
if TYPE_CHECKING:
from app.rag.scaffolding import ScaffoldingFilter
FRONTEND = Path(__file__).resolve().parents[2] / "frontend"
STYLES_CSS = FRONTEND / "assets" / "styles.css"
APP_JS = FRONTEND / "assets" / "app.js"
def _css() -> str:
assert STYLES_CSS.is_file(), f"missing {STYLES_CSS}"
return STYLES_CSS.read_text(encoding="utf-8")
def _app_js() -> str:
assert APP_JS.is_file(), f"missing {APP_JS}"
return APP_JS.read_text(encoding="utf-8")
def _function_body(js: str, header: str) -> str:
"""The full text of the function whose header is ``header`` — from
the header to its brace-matched closing ``}``. The naive brace
count is safe for the pinned functions: their template literals
carry balanced ``${…}`` pairs and no string literal holds a stray
brace."""
start = js.index(header)
body_open = js.index("{", start)
depth = 0
for j in range(body_open, len(js)):
if js[j] == "{":
depth += 1
elif js[j] == "}":
depth -= 1
if depth == 0:
return js[start : j + 1]
raise AssertionError(f"unbalanced braces in {header!r}")
def _rule(css: str, selector: str) -> str:
"""The body of the rule whose selector line is exactly ``selector``
(multi-line block)."""
block = re.search(rf"^{re.escape(selector)} \{{\n([\s\S]*?)\n\}}", css, re.MULTILINE)
assert block, f"styles.css must carry a `{selector} {{ … }}` rule"
return block.group(1)
def _done_branch(js: str) -> str:
"""The SSE ``done`` branch of the stream handler — from the
``ev.type === "done"`` test to the next ``else if`` (the
``tool_result`` branch). The branch is a flat block (no nested
else-if chain), so a slice between the two branch markers is
exact."""
start = js.index('ev.type === "done"')
end = js.index('ev.type === "tool_result"', start)
branch = js[start:end]
assert "appendSources(wrap, ev.sources);" in branch, (
"the done branch must keep appending the cited tier (phase 113 "
"demotes to a row — it never removed the citation surface)"
)
return branch
# ---------- task 02: appendRelated — the secondary row, never a chip ----------
def test_append_related_exists_and_never_uses_source_chip() -> None:
"""``appendRelated`` exists and builds ONLY ``.related-doc`` links —
the string ``source-chip`` must NOT appear anywhere in its body
(the acceptance criterion: a weak doc renders only as
``.related-doc``, never as ``.source-chip``). It reuses the chip
behavior for navigation: the same ``documentUrl(s.source, s.path,
"/")`` href (the /document.html no-JS escape hatch) and the same
left-click → ``openDocumentModal`` (phase 26, the same-page modal).
Each link carries the full path in ``title`` AND ``aria-label``
(the accessible name never depends on the visible text fitting)."""
body = _function_body(_app_js(), "function appendRelated(wrap, related) {")
assert "link.className = \"related-doc\";" in body, (
"the related links must carry the .related-doc class"
)
assert "source-chip" not in body, (
"appendRelated must NEVER build a citation chip — the related "
"row is not a citation surface (phase 113 LOCKED A1/A2)"
)
assert "link.href = documentUrl(s.source, s.path, \"/\");" in body, (
"each related link keeps the chip's /document.html href — the "
"no-JS / context-menu escape hatch (back → the chat page)"
)
assert "openDocumentModal(s.source, s.path, link);" in body, (
"left-click opens the same-page document modal exactly like the "
"chips (phase 26 contract)"
)
assert "e.preventDefault();" in body, (
"the click must prevent default navigation — the modal takes "
"over, no new tab (the chip pattern)"
)
assert "link.title = docLabel;" in body, (
"the native tooltip carries the FULL path (the chip pattern)"
)
assert 'link.setAttribute("aria-label", docLabel);' in body, (
"the accessible name is the full path, always"
)
def test_append_related_renders_only_when_related_is_non_empty() -> None:
"""The row renders ONLY when ``related`` is non-empty: an
``undefined``/``null``/``[]`` input (every pre-phase turn, every
turn with nothing under the bar) early-returns with NO DOM — the
bubble reads exactly as it did before phase 113. The pin is the
house guard, verbatim, as the FIRST statement of the body."""
body = _function_body(_app_js(), "function appendRelated(wrap, related) {")
first_stmt = body.split("{", 1)[1].lstrip()
assert first_stmt.startswith("if (!related || !related.length) return;"), (
"appendRelated must early-return on !related || !related.length — "
"an empty related tier adds zero DOM (the pre-phase look stays "
"byte-identical for those turns)"
)
def test_append_related_row_contract() -> None:
"""The row itself: a ``.msg-meta.related-docs`` div (it joins the
bubble's meta family — the .msg-body flex gap stacks it below the
citation row with the existing gap) that is an accessible list
(``role="list"`` + ``aria-label="Nearby docs, in case"``) headed
by the visible small-caps label ``Nearby docs, in case:`` (the
TODO's suggested wording, trimmed) with the
``.related-docs-label`` class, and one ``role="listitem"`` link
per doc."""
body = _function_body(_app_js(), "function appendRelated(wrap, related) {")
assert "row.className = \"msg-meta related-docs\";" in body, (
"the row is a .msg-meta row (the family the bubble's meta rows "
"already form) with the .related-docs marker"
)
assert 'row.setAttribute("role", "list");' in body
assert 'row.setAttribute("aria-label", "Nearby docs, in case");' in body, (
"the row is an accessible list named 'Nearby docs, in case'"
)
assert "label.className = \"related-docs-label\";" in body
assert "label.textContent = \"Nearby docs, in case:\";" in body, (
"the visible label carries the TODO's suggested wording (trimmed)"
)
assert 'link.setAttribute("role", "listitem");' in body, (
"each link is a listitem of the row's list (ARIA stays valid)"
)
assert "for (const s of related) {" in body, (
"one link per related doc"
)
# ---------- task 02: wiring — the done frame and the restore path ----------
def test_done_handler_calls_append_related_last() -> None:
"""The done-frame handler calls ``appendRelated(wrap, ev.related)``
— and appends the row LAST among the bubble's meta rows: AFTER
``markLastRetryable()`` (the appendTuneButton / appendSaveAsDoc /
appendRetryButton claimers all take the FIRST ``.msg-meta`` row,
so a deflected turn with related docs — no citation row — gets its
OWN meta row for the buttons instead of actions joining the
related row). The call sits after the Retry claim in the branch."""
branch = _done_branch(_app_js())
assert "appendRelated(wrap, ev.related);" in branch, (
"the done handler must render the related tier (it arrives in "
"ev.related — on a deflected turn ev.sources is empty and the "
"weak hits live here, row only, zero chips)"
)
assert branch.index("appendRelated(wrap, ev.related);") > branch.index(
"markLastRetryable();"
), (
"appendRelated must run AFTER the meta-action claimers (last "
"meta row) — a deflected turn's tune/retry buttons must land in "
"their own row, never in the related row"
)
def test_done_handler_persists_related_with_the_turn() -> None:
"""The related tier PERSISTS with the turn (the done handler's
``rememberBrainTurn`` meta), using the house optional-meta pattern
(``undefined`` drops the key from the JSON — no ``related: []``
noise on turns with nothing related). Without this the restore
path could never re-render the row after a reload."""
branch = _done_branch(_app_js())
pattern = (
r"rememberBrainTurn\(finalText \|\| acc, \{([\s\S]*?)\}"
r"\s*,\s*leavePartialIndex\);"
)
persist = re.search(pattern, branch)
assert persist, "the done handler must persist the turn through rememberBrainTurn"
meta = persist.group(1)
assert "related: ev.related?.length ? ev.related : undefined," in meta, (
"the done frame's related tier must persist (undefined drops "
"the key — the house optional-meta pattern, cf. `tools`)"
)
def test_restore_path_calls_append_related() -> None:
"""The phase-14 restore path (``renderStoredMessage`` — used by
BOTH the localStorage restore and the /?chat=<id> saved-chat boot
load) re-renders the related row from the stored payload when it
carries ``related``; a pre-phase record without the field
restores exactly as today (appendRelated no-ops — no row). The
call sits after the meta-row claimers, exactly like the live
done path, so restored buttons never join the related row."""
body = _function_body(_app_js(), "function renderStoredMessage(m) {")
assert "appendRelated(wrap, m.related);" in body, (
"the restore path must render the related tier from the stored "
"payload (pre-phase records carry no `related` → no row, "
"graceful)"
)
assert body.index("appendRelated(wrap, m.related);") > body.index(
"appendStoppedNote(wrap);"
), (
"the related row appends LAST (after the claimers) on the "
"restore path too — identical order to the live done path"
)
def test_citation_surface_untouched() -> None:
"""The citation chip component is NOT touched (phase 113 "NOT
touched" list): ``appendSources`` still builds ``.source-chip``
pills and still early-returns on an empty list — which is exactly
what a deflected turn (``ev.sources === []``) hits: zero
``.source-chip`` elements under the bubble. The suggestion chips
(``appendMaybeTry`` / ``.suggestion-chip``) are a different
surface and stay as they were."""
js = _app_js()
body = _function_body(js, "function appendSources(wrap, sources) {")
assert "chip.className = \"source-chip\";" in body
assert body.lstrip().startswith("function appendSources"), "sanity"
assert "if (!sources || !sources.length) return;" in body, (
"appendSources still no-ops on an empty list — a deflected "
"turn's empty ev.sources renders ZERO citation chips (the "
"weak hits arrive in ev.related → the row only)"
)
assert js.count("function appendRelated(wrap, related) {") == 1, (
"exactly ONE appendRelated — no second related renderer"
)
# ---------- task 02: the CSS — clearly secondary, AA, theme-neutral ----------
def test_related_doc_rule_is_the_secondary_look() -> None:
"""The ``.related-doc`` link: dashed border (the citation chip's
solid 1px ``--line`` pill is the citation look — the dash is the
visual split), transparent fill (no ``--brand-soft``), muted
``--ink-soft`` text (8.6:1 on ``--bg`` — verified ≥4.5:1, WCAG
2.1 AA; the ratio is recorded in the rule's provenance comment),
smaller mono than the chip (0.7rem < 0.72rem), and the
single-line ellipsis set (same overflow contract as the chip).
Palette variables only — zero new literals (phase-92 invariant),
so the monochrome theme grays the row automatically."""
body = _rule(_css(), ".related-doc")
assert "border: 1px dashed var(--line);" in body, (
"the related link is DASHED — the chip's solid border is the "
"citation look, the dash is the 'not a citation' signal"
)
assert "background: transparent;" in body, (
"no brand-soft fill — that surface is the citation pill's"
)
assert "color: var(--ink-soft);" in body, (
"the link text is the muted ink — AA on the page bg (8.6:1)"
)
assert "font-family: var(--mono);" in body, (
"source/path reads mono like the chips (same data, secondary "
"weight)"
)
assert "font-size: 0.7rem;" in body, (
"smaller than the chip's 0.72rem — visually secondary"
)
for prop in (
"white-space: nowrap;",
"overflow: hidden;",
"text-overflow: ellipsis;",
"max-width: 100%;",
"min-width: 0;",
):
assert prop in body, f"the related link keeps the chip's single-line ellipsis set ({prop})"
comment = re.search(r"(/\*[^*]*?\*/)\s*\.related-docs-label \{", _css())
assert comment, "the related-docs rules must carry their provenance comment"
note = comment.group(1)
assert "8.6:1" in note and "4.5:1" in note, (
"the --ink-soft on --bg ratio must be recorded (verified "
"8.6:1 ≥ 4.5:1, WCAG AA — house style)"
)
assert "#" not in note.replace("--", ""), (
"the comment is theme-variable language — no literal colors "
"(phase-92 zero-literal invariant)"
)
def test_related_doc_hover_is_flat() -> None:
"""The ``.related-doc:hover`` rule is deliberately FLAT: no
background swap (the chip's ``background: var(--brand-soft)``
hover is the citation affordance — 'no hover elevation of the
citation chips'), only the ink-soft → ink step-up (16.7:1 on
``--bg``) plus the underline. The global 3px ``:focus-visible``
outline rule covers the focus ring (no per-rule ring needed, the
chip precedent)."""
body = _rule(_css(), ".related-doc:hover")
assert "background" not in body, (
"the hover must NOT change the background — that surface swap "
"is the citation chip's affordance"
)
assert "box-shadow" not in body, "no hover elevation (no shadow gain)"
assert "color: var(--ink);" in body, (
"the hover is the flat ink step-up (16.7:1 on --bg, AA)"
)
assert "text-decoration: underline;" in body
def test_related_docs_label_is_small_caps_muted() -> None:
"""The ``.related-docs-label``: small muted uppercase text (the
'small caps or muted small text' from the task) — smaller than the
row's 0.75rem ``.msg-meta`` base, the same AA-safe ``--ink-soft``
(8.6:1 on ``--bg``) as the links, letterspaced like every other
overline in the app."""
body = _rule(_css(), ".related-docs-label")
assert "text-transform: uppercase;" in body
assert "color: var(--ink-soft);" in body, (
"the label uses the AA-safe muted ink (8.6:1 on --bg)"
)
size = re.search(r"font-size: ([0-9.]+)rem;", body)
assert size, "the label must set its own (smaller) font size"
assert float(size.group(1)) < 0.75, (
"the label is smaller than the row's 0.75rem base — it is a "
"whisper, not a heading"
)
# ---------- task 03: the four observed shapes (TODO L110–123) ----------
#: The canned answer the endpoint-level fakes stream (the gate-suite
#: convention — byte-stable, assertable against the wire).
ANSWER = "I haven't done anything like that — try one of these instead!"
def _shape_settings() -> Settings:
"""The PRODUCTION calibration (the code defaults, explicit) — the
four shapes were observed LIVE under this threshold/floor pair.
``_env_file=None`` keeps the mock-calibrated values from
``tests/conftest.py`` (and any local ``.env``) out of the pin.
``source_usefulness_floor`` / ``top_n_docs`` are legacy phase-113
settings — phase 118 retired their seeding role (A6; ``plan_turn``
never consults them), they are carried here for completeness."""
return Settings(
_env_file=None, # pyright: ignore[reportCallIssue]
relevance_threshold=0.62,
lexical_support_floor=0.35,
source_usefulness_floor=0.35, # retired by phase 118 (A6) — not consulted
related_max_docs=2, # the rank-6+ row cap (LOCKED A4)
top_n_docs=2, # retired by phase 118 (A6) — not consulted
suggested_docs=5, # the "start here" cap (LOCKED A3)
)
def _doc(source: str, path: str, title: str, content: str) -> Document:
return Document(
id=uuid.uuid4(),
source=source,
path=path,
full_path=f"/{source}/{path}",
title=title,
content=content,
content_hash="0" * 64,
# Phase 106, D5: the HIGH block / the ``read`` result's date
# line format the row's created_at — a fixed value keeps the
# fixtures deterministic.
created_at=datetime(2024, 6, 15, 12, 0, 0, tzinfo=UTC),
)
def _chunk(
doc: Document,
score: float,
cosine: float,
fts_hit: bool = False,
) -> RetrievedChunk:
"""One fake retrieval candidate: *score* is the RRF fused rank key,
*cosine* the vector similarity (the bar's input — independent of
*score* on purpose: the bar is on the cosine, LOCKED A2)."""
return RetrievedChunk(
chunk_id=uuid.uuid4(),
position=0,
content=doc.content[:32],
score=score,
document=doc,
cosine=cosine,
fts_hit=fts_hit,
)
def test_shape_1_mongolia_both_docs_weak_cite_nothing() -> None:
"""Observed shape 1 (TODO L110–113): "What is the capital of
Mongolia?" → chips ``Trooper_Nagraz.pl`` + ``Trooper_Begzei.pl``,
BOTH unrelated. Phase 118 (A3): the floor never filters — the weak
hits are the SUGGESTED tier (the durable record's input), and with
three retrieved docs nothing is left for the related tier (rank
6+). The FTS hit without vector corroboration (0.20 < the 0.35
lexical floor) stays LOW — the A8-revised "Mongolia" case; the weak
content never reaches the LLM (titles only)."""
nagraz = _doc("scripts", "scripts/Trooper_Nagraz.pl", "Trooper_Nagraz.pl",
"NAGRAZ_PL_CONTENT")
begzei = _doc("scripts", "scripts/Trooper_Begzei.pl", "Trooper_Begzei.pl",
"BEGZEI_PL_CONTENT")
third = _doc("scripts", "scripts/Trooper_Third.pl", "Trooper_Third.pl",
"THIRD_PL_CONTENT")
chunks = [
_chunk(nagraz, 0.033, cosine=0.20, fts_hit=True), # rank 1, lexical hit
_chunk(begzei, 0.031, cosine=0.12),
_chunk(third, 0.030, cosine=0.10),
]
plan = chat_api.plan_turn(chunks, _shape_settings())
assert plan.deflected is True # 0.20 < 0.62 AND 0.20 < the 0.35 lex floor
# No floor (A3): the weak hits are suggested, in rank order (≤5).
assert [d.title for d in plan.suggested_docs] == [
"Trooper_Nagraz.pl",
"Trooper_Begzei.pl",
"Trooper_Third.pl",
]
assert plan.related_docs == [] # no rank-6+ doc among 3 retrieved
# The LOW prompt is titles only — none of the weak content is sent.
assert "NAGRAZ_PL_CONTENT" not in plan.system_prompt
assert "Trooper_Nagraz.pl" in plan.system_prompt # weak-hit titles carried
assert plan.suggestions # the "Maybe try" chips are unchanged
def test_shape_2_validate_sh_strong_plus_weak_second_suggested() -> None:
"""Observed shape 2 (TODO L114–116): the phase-gate question is
answered from ``brain-of-reese/.agents/validate.sh`` with
``ServMon/README.md`` retrieved alongside (weak cosine). Phase 118
(A3): the floor never filters — the weak 2nd doc is SUGGESTED too
(both docs seed the HIGH prompt as summaries; the A5 fallback
carries the short fixture content whole), and A4 makes both
citation refs on the done frame — the "unused 2nd chip" is the
phase-113 shape, retired by the owner directive."""
validate = _doc("brain-of-reese", ".agents/validate.sh", "validate.sh",
"VALIDATE_SH_CONTENT")
servmon = _doc("ServMon", "README.md", "ServMon README",
"SERVMON_README_CONTENT")
chunks = [
_chunk(validate, 0.90, cosine=0.70), # clears the threshold
_chunk(servmon, 0.80, cosine=0.20), # high fused rank, weak cosine
]
plan = chat_api.plan_turn(chunks, _shape_settings())
assert plan.deflected is False # 0.70 >= 0.62
assert [d.title for d in plan.suggested_docs] == [
"validate.sh",
"ServMon README",
] # both suggested (no floor), rank order
assert plan.related_docs == [] # nothing beyond rank 2 for 2 docs
assert "VALIDATE_SH_CONTENT" in plan.system_prompt # A5 preview fallback
assert "SERVMON_README_CONTENT" in plan.system_prompt # ditto
def test_shape_3_nagraz_answered_by_own_doc_byzin_suggested() -> None:
"""Observed shape 3 (TODO L117–119): the Trooper_Nagraz question is
answered from ``Trooper_Nagraz.pl`` with ``Trooper_Byzin.pl``
retrieved alongside (weak cosine). The SAME shape as shape 2 with
different fixtures — phase 118's no-floor tiering suggests BOTH
(the phase-113 "bar filters the 2nd chip" story is retired); the
HIGH prompt seeds both summaries (A5 fallback for the short
fixture content)."""
nagraz = _doc("scripts", "scripts/Trooper_Nagraz.pl", "Trooper_Nagraz.pl",
"NAGRAZ_PL_CONTENT")
byzin = _doc("scripts", "scripts/Trooper_Byzin.pl", "Trooper_Byzin.pl",
"BYZIN_PL_CONTENT")
chunks = [
_chunk(nagraz, 0.85, cosine=0.70),
_chunk(byzin, 0.75, cosine=0.15), # weak cosine — still suggested (A3)
]
plan = chat_api.plan_turn(chunks, _shape_settings())
assert plan.deflected is False
assert [d.title for d in plan.suggested_docs] == [
"Trooper_Nagraz.pl",
"Trooper_Byzin.pl",
] # both suggested (no floor), rank order
assert plan.related_docs == []
assert "NAGRAZ_PL_CONTENT" in plan.system_prompt # A5 preview fallback
assert "BYZIN_PL_CONTENT" in plan.system_prompt # ditto
# ---------- task 03: done-frame wire (endpoint-level fakes, no stack) ----------
class _CannedLLM:
"""Records the requests; streams the canned *answer*.
Without *read_path* it never emits tool calls (the single-request
shape). With *read_path*, the first tools-offering request that
carries no tool result yet emits ONE ``read`` call on the combined
path; the follow-up request (carrying the tool result) streams the
answer — the phase-37 single-read shape, stateless (the e2e mock's
convention)."""
def __init__(self, answer: str = ANSWER, read_path: str | None = None) -> None:
self.settings = Settings(_env_file=None) # pyright: ignore[reportCallIssue]
self.answer = answer
self.read_path = read_path
self.seen: list[list[dict[str, Any]]] = []
self.seen_tools: list[list[dict[str, Any]] | None] = []
async def embed_one(self, _text: str) -> list[float]:
return [0.0] * 768
async def chat_stream(
self,
messages: list[dict[str, Any]],
tools: list[dict[str, Any]] | None = None,
scaffolding: ScaffoldingFilter | None = None,
):
self.seen.append(messages)
self.seen_tools.append(tools)
if (
self.read_path is not None
and tools is not None
and not any(m.get("role") == "tool" for m in messages)
):
yield ToolCallPiece(
id="call_1", name="read", arguments={"path": self.read_path}
)
return
for i in range(0, len(self.answer), 12):
yield StreamPiece("content", self.answer[i : i + 12])
class _FakeSteeringResult:
"""Empty steering-note result (no stored notes in these tests)."""
def all(self) -> list[Any]:
return []
class _FakeSession:
"""Stands in for the DB session (the gate-suite pattern):
records the ``QueryLog`` row, yields no steering notes, no KB
overview (``get`` → ``None``). Tool execution's ``find_document``
is monkeypatched separately (the agent module's, not the
session's)."""
def __init__(self) -> None:
self.added: list[Any] = []
self.commits = 0
def __enter__(self) -> _FakeSession:
return self
def __exit__(self, *args: Any) -> None:
pass
def add(self, obj: Any) -> None:
self.added.append(obj)
def commit(self) -> None:
self.commits += 1
def scalars(self, _stmt: Any) -> _FakeSteeringResult:
return _FakeSteeringResult()
def get(self, _model: Any, _pk: Any) -> Any:
return None
def execute(self, *args: Any, **kwargs: Any) -> list[Any]:
# Phase 119 (D3): the endpoint's suggested-folder lines run the
# ls catalog fetchers on this session — the fake catalog is
# empty (header-only lines), keeping the prompt builds
# deterministic here.
return []
@pytest.fixture(autouse=True)
def _admin_signed_in(client: TestClient) -> None:
"""Phase 79: ``POST /api/chat`` is user-gated — the endpoint-level
tests run as the signed-in ADMIN (the gate-suite pattern)."""
r = client.post("/api/login", json={"password": ADMIN_PASSWORD})
assert r.status_code == 204, f"admin login failed: {r.status_code} {r.text}"
@pytest.fixture()
def chip_env(
monkeypatch: pytest.MonkeyPatch,
) -> Iterator[tuple[_FakeSession, _CannedLLM]]:
"""``POST /api/chat`` with retriever, session, and LLM all faked —
the production calibration (``_shape_settings``) in force."""
monkeypatch.setattr(chat_api, "db_available", lambda: True)
session = _FakeSession()
llm = _CannedLLM()
monkeypatch.setattr(chat_api, "SessionLocal", lambda: session)
monkeypatch.setitem(fastapi_app.dependency_overrides, chat_api.get_llm, lambda: llm)
monkeypatch.setattr(chat_api, "get_settings", _shape_settings)
yield session, llm
fastapi_app.dependency_overrides.clear()
def _ask(client: TestClient, message: str) -> list[dict[str, Any]]:
with client.stream("POST", "/api/chat", json={"message": message}) as r:
assert r.status_code == 200
frames: list[dict[str, Any]] = []
buf = ""
for part in r.iter_text():
buf += part
while "\n\n" in buf:
frame, buf = buf.split("\n\n", 1)
frame = frame.strip()
if frame.startswith("data:"):
frames.append(json.loads(frame.removeprefix("data:").strip()))
assert buf.strip() == ""
return frames
def _fake_retriever(chunks: list[RetrievedChunk]) -> Any:
def retrieve(_db: Any, _question: str, _vec: list[float]) -> list[RetrievedChunk]:
return chunks
return retrieve
def test_shape_4_meta_question_deflected_frame_has_no_chips_or_row(
client: TestClient,
chip_env: tuple[_FakeSession, _CannedLLM],
monkeypatch: pytest.MonkeyPatch,
) -> None:
"""Observed shape 4 (TODO L120–123), pinned on the DONE FRAME: a
meta question about the conversation's own history → weak hits
``app/api/suggestions.py`` + ``108_history_wire_check/00_phase.md``,
neither used. Phase 118: the agent reads nothing, the weak hits
are the SUGGESTED tier (no floor, A3 — the durable record's input)
and, with only two retrieved docs, nothing reaches rank 6+ — the
frame carries ``sources: []`` (zero chips — a deflected answer
cites nothing) AND an empty ``related`` row (the row's rendering
itself is pinned by task 02's source tests + the E2E). The weak
retrieval stays durably recorded (LOCKED A3); the weak content
never reaches the LLM (LOW prompt, titles only)."""
session, llm = chip_env
suggestions = _doc("brain-of-reese", "app/api/suggestions.py",
"suggestions.py", "SUGGESTIONS_PY_CONTENT")
phase_md = _doc("brain-of-reese",
".agents/108_history_wire_check/00_phase.md", "00_phase.md",
"PHASE_MD_CONTENT")
monkeypatch.setattr(
chat_api,
"retrieve",
_fake_retriever(
[
_chunk(suggestions, 0.033, cosine=0.25),
_chunk(phase_md, 0.031, cosine=0.10),
]
),
)
frames = _ask(client, "What have we covered in this conversation so far?")
done = frames[-1]
assert done["type"] == "done"
assert done["deflected"] is True
assert done["sources"] == [] # zero citation chips on the wire
# Phase 118 (A3): both weak docs are suggested (≤5, no floor) —
# nothing reaches rank 6+, so the related row is empty.
assert done["related"] == []
assert done["suggestions"] # the "Maybe try" chips are unchanged
(system, _user) = llm.seen[0][0], llm.seen[0][1]
assert "SUGGESTIONS_PY_CONTENT" not in system["content"]
assert "PHASE_MD_CONTENT" not in system["content"]
(row,) = session.added
assert isinstance(row, QueryLog)
assert row.deflected is True
# LOCKED A3: the weak retrieval stays recorded (observability).
assert "app/api/suggestions.py" in row.sources
assert "108_history_wire_check/00_phase.md" in row.sources
def test_done_frame_zero_read_grounded_turn_carries_no_chips(
client: TestClient,
chip_env: tuple[_FakeSession, _CannedLLM],
monkeypatch: pytest.MonkeyPatch,
) -> None:
"""Shape 2 on the wire under phase 119 (LOCKED A1 — the phase-118
A4 union retired): the citation surface is the agent's READ DOCS
only — with two retrieved docs and no read, ``sources`` is empty
(the zero-read grounded turn chips nothing — an accepted,
owner-directed consequence); the never-read suggested docs appear
NOWHERE in the frame (the explicit contrast against the retired
A4 union); nothing reaches rank 6+, so ``related`` is empty. The
durable record keeps the FULL retrieval (118-A3 stands)."""
session, _llm = chip_env
validate = _doc("brain-of-reese", ".agents/validate.sh", "validate.sh",
"VALIDATE_SH_CONTENT")
servmon = _doc("ServMon", "README.md", "ServMon README",
"SERVMON_README_CONTENT")
monkeypatch.setattr(
chat_api,
"retrieve",
_fake_retriever(
[
_chunk(validate, 0.90, cosine=0.70),
_chunk(servmon, 0.80, cosine=0.20),
]
),
)
frames = _ask(client, "How does the phase gate decide to validate?")
done = frames[-1]
assert done["deflected"] is False
# A1: read docs only — the agent read nothing ⇒ no chips, and the
# never-read suggested docs appear NOWHERE in the frame (the retired
# A4 union would have carried both).
assert done["sources"] == []
assert done["related"] == [] # nothing reaches rank 6+ for 2 docs
(row,) = session.added
assert isinstance(row, QueryLog)
assert row.deflected is False
# The durable record keeps BOTH docs (retrieval, not citations — A3).
assert ".agents/validate.sh" in row.sources
assert "ServMon/README.md" in row.sources
def test_agent_read_related_doc_is_cited_not_related(
client: TestClient,
chip_env: tuple[_FakeSession, _CannedLLM],
monkeypatch: pytest.MonkeyPatch,
) -> None:
"""The agent-read exemption (phase-119 A1 × phase-118 tiering):
``sources`` is the READ DOCS only — a rank-6+ doc (the related
tier, "nearby docs") that the agent ``read`` via the tool is the
frame's ONLY chip: the model read it, so it was used. It is EXCLUDED
from ``related`` (a used doc must never read as "nearby" — unchanged
intent, the dedupe now keyed on read docs); the other rank-6+ doc
stays in the tier; the never-read suggested docs appear NOWHERE in
the frame (contrast against the retired A4 union). The read content
reached the model (the tool result in the follow-up request)."""
session, _default_llm = chip_env
strong = _doc("docs", "strong.md", "Strong", "STRONG_DOC_CONTENT")
fillers = [
_doc("docs", f"filler{i}.md", f"Filler {i}", f"FILLER_{i}_CONTENT")
for i in range(1, 5) # ranks 2–5 — fill the suggested tier
]
weak_b = _doc("docs", "weak-b.md", "Weak B", "WEAK_B_READ_BY_AGENT")
weak_c = _doc("docs", "weak-c.md", "Weak C", "WEAK_C_CONTENT")
monkeypatch.setattr(
chat_api,
"retrieve",
_fake_retriever(
[
_chunk(strong, 0.90, cosine=0.70), # clears the threshold (rank 1)
_chunk(fillers[0], 0.85, cosine=0.30), # ranks 2–5: suggested
_chunk(fillers[1], 0.80, cosine=0.30),
_chunk(fillers[2], 0.75, cosine=0.30),
_chunk(fillers[3], 0.72, cosine=0.30),
_chunk(weak_b, 0.70, cosine=0.20), # rank 6 — related; read by the agent
_chunk(weak_c, 0.65, cosine=0.10), # rank 7 — related; nobody reads it
]
),
)
read_llm = _CannedLLM(read_path="docs/weak-b.md")
fastapi_app.dependency_overrides[chat_api.get_llm] = lambda: read_llm
def _find_document(_db: Any, source: str, path: str) -> Document | None:
return weak_b if (source, path) == ("docs", "weak-b.md") else None
monkeypatch.setattr(agent, "find_document", _find_document)
frames = _ask(client, "What does the weak B document say?")
done = frames[-1]
assert done["deflected"] is False
# The tool ran (one ``tool`` frame) and the read doc reached the
# model's follow-up request.
assert any(f["type"] == "tool" for f in frames)
tool_msgs = [m for m in read_llm.seen[1] if m.get("role") == "tool"]
assert len(tool_msgs) == 1
assert "WEAK_B_READ_BY_AGENT" in tool_msgs[0]["content"]
sources = [(s["source"], s["path"]) for s in done["sources"]]
# A1: read docs only — the read related doc is the ONLY chip (the
# never-read suggested docs are nowhere in the frame).
assert sources == [("docs", "weak-b.md")] # read ⇒ chip
assert ("docs", "weak-c.md") not in sources # never read
related = [(s["source"], s["path"]) for s in done["related"]]
assert related == [("docs", "weak-c.md")] # the read doc is not "nearby"
assert set(sources).isdisjoint(set(related))
(row,) = session.added
assert isinstance(row, QueryLog)
assert "weak-b.md" in row.sources # the full retrieval is recorded (A3)
assert "weak-c.md" in row.sources # … rank 6+ included (suggested + related + read)