phase: 191_source_name_labels_tags
Build and Push Containers / build-and-push-app (push) Successful in 7m24s
Build and Push Containers / build-and-push-db (push) Successful in 36s

All gates re-verified against a stable tree. Report:

**Verified (all 6 tasks in `complete/`; this was the final pass)**
- `SourceLabel`+alembic `0030` (dev DB `alembic current` = `0030 (head)`, table present, 0 rows); admin-only `GET/PUT/DELETE /api/source-labels` (`require_admin` router-wide, `resolve_source_name`, partial-update caps/404s); Sources-page "Names, labels and tags" card (read-only derived-name `<code>`, per-row `saveInFlight`, 404 note that survives the settle, chips reuse `.git-source-hidden-count`); `question_name_hits` D2 rule; ONE `all_labels` read per turn in `chat.py` feeding both the `source_name_hit` flag and the prompt surfaces; `source_name_hit_bonus=0.005` in `_selection_order`; ` name=`/` label=` in `build_high_prompt` + `build_overview_prompt(names=…)`.
- **Completion criteria:** E2E `tests/e2e/test_source_name_labels.py` ✅ 7 passed (arms a–e: editor all kinds, control/named question, rename-never-breaks-identity, 404 note, reset) · full suite ✅ · coverage ✅ · README/AGENTS ✅ · phase dir in `complete/` ✅ · commit left to the harness.
- **Gates:** `uv run pytest --cov=app --cov-report=term-missing` → **exit 0, TOTAL 7160 stmts / 16 missed = 99%** (>90%) · `uv run pytest tests/e2e/test_source_name_labels.py -v --no-cov` → **7 passed, exit 0** · regression E2E isolated, exit 0: `test_document_viewer`, `test_admin_auth`, `test_api_tokens`, `test_git_sources_admin`, `test_kb_tree`, `test_local_directory_sources` · `uv run ruff check .` → All checks passed · `uv run pyright` → 0 errors.
- **Battery (task 04 criterion):** `uv run python -m scripts.eval_retrieval --from-file tests/fixtures/retrieval_battery.txt` at default vs `BOR_SOURCE_NAME_HIT_BONUS=0` → **`diff` empty (line-for-line identical)**, matching the recorded arms (dev KB is empty, so every question deflects; the observable boost is unit/E2E-pinned).
- **Documentation:** README — fixed the `/git-sources.html` rows (nav label is **Sources**) and cross-linked the phase-191 card from that section; full audit otherwise clean: all 86 `BOR_*` settings documented with defaults matching `app/config.py`, 0 broken file/dir references and 0 broken anchors in README+AGENTS, AGENTS rule 17 re-checked line-by-line against the code.
- **Notable / deviations:** (1) a **concurrent pipeline process** (`phased-execution/progress.mjs` for `191_…_00_phase`) was mutating this same working tree mid-pass — it rewrote `tests/e2e/test_source_name_labels.py` (11→7 tests), `frontend/assets/git-sources.js`, `tests/unit/test_source_labels_editor_ui.py` and `AGENTS.md` at 05:27; every gate above was (re-)run after those edits with the tree no source file newer than the green full run. (2) The task-06 report/phase text claims regression suites `test_chat_token_gate.py`, `test_git_sources_page.py`, `test_rag_browser.py` are green — **those files have never existed in git history** (those runs exit 4); I ran the real equivalents listed above instead (phase files are not mine to edit). (3) **No live changes**: the VM DB already has `source_labels` (0 rows) but the deployed app predates this uncommitted code, so deploying `/api/source-labels` to the live service is the owner's post-commit step, not part of this phase's criteria.
- **Next pending phase:** none — `191_source_name_labels_tags` is the only entry in `.agents/phases/todo/`.
This commit is contained in:
2026-10-19 06:13:32 -04:00
parent c6ffa050a6
commit 4f20c256d7
70 changed files with 7378 additions and 50 deletions
+174 -9
View File
@@ -1260,9 +1260,12 @@ def _bonus_rc(
cosine: float,
position: int = 0,
name_hit: bool = False,
source_name_hit: bool = False,
) -> RetrievedChunk:
"""One fused-list candidate (name-hit rows follow the D1 lexical
convention: ``cosine=0.0``, ``fts_hit=True``)."""
convention: ``cosine=0.0``, ``fts_hit=True``). The
``source_name_hit`` flag (phase 191, D2) is set at the retrieval
boundary in chat.py — here directly, on the fused row."""
return RetrievedChunk(
chunk_id=uuid.uuid4(),
position=position,
@@ -1272,6 +1275,7 @@ def _bonus_rc(
cosine=cosine,
fts_hit=cosine == 0.0,
name_hit=name_hit,
source_name_hit=source_name_hit,
)
@@ -1479,24 +1483,185 @@ def test_weak_hit_titles_bonus_adjusted_order() -> None:
def test_bonus_lives_in_the_selection_layer_only() -> None:
"""LOCKED A3: the bonus never touches the chunk objects —
"""LOCKED A3 (mirrored by phase 191 for the SECOND bonus): the
bonuses never touch the chunk objects —
``score``/``cosine``/``fts_hit`` (the A8 gate's inputs —
``query_log.top_score`` is the best fused chunk score, the same
values) are unchanged after every selection walk, even with the
bonus lifting a document."""
values) and the ``name_hit``/``source_name_hit`` flags themselves
are unchanged after every selection walk, even with the bonuses
lifting a document."""
chunks = _bonus_chunks()
chunks[-1].source_name_hit = True
before = {
rc.chunk_id: (rc.score, rc.cosine, rc.fts_hit, rc.name_hit) for rc in chunks
rc.chunk_id: (
rc.score,
rc.cosine,
rc.fts_hit,
rc.name_hit,
rc.source_name_hit,
)
for rc in chunks
}
select_suggested(chunks, n=5, bonus=0.005)
select_related(chunks, set(), cap=5, bonus=0.005)
weak_hit_titles(chunks, bonus=0.005)
select_suggested(chunks, n=5, bonus=0.005, source_bonus=0.005)
select_related(chunks, set(), cap=5, bonus=0.005, source_bonus=0.005)
weak_hit_titles(chunks, bonus=0.005, source_bonus=0.005)
after = {
rc.chunk_id: (rc.score, rc.cosine, rc.fts_hit, rc.name_hit) for rc in chunks
rc.chunk_id: (
rc.score,
rc.cosine,
rc.fts_hit,
rc.name_hit,
rc.source_name_hit,
)
for rc in chunks
}
assert before == after
# ---------------------------------------------------------------------------
# Phase 191, D3 — the bounded SOURCE-name bonus (the second, independent
# knob; the phase-119 mirror: kill switch, bounded per-document apply,
# the fuse OR-merge, the settings defaults)
# ---------------------------------------------------------------------------
def test_selection_order_source_bonus_zero_is_byte_identical_to_pre_phase() -> None:
"""The kill switch (LOCKED A3, phase-119 mirror): with
*source_bonus* ``0`` the walk is byte-identical to the
pre-phase-191 walk even when EVERY chunk carries the flag — same
order, same effective scores (the phase-119 name bonus alone). With
BOTH knobs ``0`` the pre-phase golden walk returns byte-identical."""
chunks = _bonus_chunks()
for rc in chunks:
rc.source_name_hit = True
out = _selection_order(chunks, 0.005, 0.0)
assert [d.path for d, _eff, _cos, _idx in out] == [
"gitea/README.md", "a.md", "b.md", "c.md", "d.md"
]
# No +0.005 rides the effective scores — the name bonus alone.
assert out[0][1] == pytest.approx(0.016 + 0.005)
off = _selection_order(chunks, 0.0, 0.0)
assert [d.path for d, *_ in off] == GOLDEN_PRE_PHASE_ORDER
assert [eff for _d, eff, _cos, _idx in off] == [
0.0200, 0.0160, 0.0150, 0.0150, 0.0100
]
def test_selection_order_source_bonus_inert_without_source_hits() -> None:
"""No ``source_name_hit`` chunk present → the second bonus cannot
fire: with both knobs on the walk equals the phase-119 name-bonus
walk exactly (the flagged-signal presence, not just the knob, gates
the re-sort)."""
out = _selection_order(_bonus_chunks(), 0.005, 0.005)
assert [d.path for d, _eff, _cos, _idx in out] == [
"gitea/README.md", "a.md", "b.md", "c.md", "d.md"
]
assert out[0][1] == pytest.approx(0.016 + 0.005)
def test_selection_order_source_bonus_lifts_named_doc_over_equal_fused() -> None:
"""The boost (D3): a document whose source is a D2 hit
(``source_name_hit=True``) ranks ABOVE an equal-fused-score
non-hit — the fused tie normally resolves on cosine (a's 0.9 beats
the hit's 0.0), the 0.005 head start decides instead."""
gitserver = _doc("gitserver.md", "G" * 50)
a = _doc("a.md", "A" * 50)
chunks = [
_bonus_rc(a, 0.0200, 0.9),
_bonus_rc(gitserver, 0.0200, 0.0, source_name_hit=True),
]
assert [d.path for d, *_ in _selection_order(chunks, 0.0, 0.0)] == [
"a.md", "gitserver.md"
]
out = _selection_order(chunks, 0.0, 0.005)
assert [d.path for d, *_ in out] == ["gitserver.md", "a.md"]
assert out[0][1] == pytest.approx(0.0200 + 0.005)
def test_selection_order_two_bonuses_bounded_at_two_per_document() -> None:
"""A document carrying BOTH flags gets EXACTLY +0.010 (the bounded
two-bonus pin — no amplification): every one of the doc's THREE
chunks is flagged for both signals, yet each bonus applies ONCE per
document — best score + bonus + source_bonus, never more."""
gitserver = _doc("gitserver.md", "G" * 50)
a = _doc("a.md", "A" * 50)
chunks = [
_bonus_rc(a, 0.0300, 0.9),
_bonus_rc(gitserver, 0.0260, 0.0, 0, name_hit=True, source_name_hit=True),
_bonus_rc(gitserver, 0.0200, 0.0, 1, name_hit=True, source_name_hit=True),
_bonus_rc(gitserver, 0.0100, 0.0, 2, name_hit=True, source_name_hit=True),
]
out = _selection_order(chunks, 0.005, 0.005)
assert [d.path for d, *_ in out] == ["gitserver.md", "a.md"]
assert out[0][1] == pytest.approx(0.0260 + 0.010)
def test_selection_helpers_pull_the_source_bonus_from_settings(
monkeypatch: pytest.MonkeyPatch,
) -> None:
"""All three selection helpers default *source_bonus* to the LIVE
``BOR_SOURCE_NAME_HIT_BONUS`` setting (the phase-119 ``bonus``
pattern): the settings default 0.005 lifts the flagged doc, a
settings kill switch (``0``) and an explicit ``source_bonus=0``
both reproduce the pre-phase-191 walk."""
chunks = _bonus_chunks()
chunks[-1].score = 0.0199 # d.md just UNDER a.md's 0.0200
chunks[-1].source_name_hit = True
on = Settings(_env_file=None) # pyright: ignore[reportCallIssue]
assert on.source_name_hit_bonus == 0.005 # the production default
monkeypatch.setattr(retriever, "get_settings", lambda: on)
lifted = ["d.md", "gitea/README.md", "a.md", "b.md", "c.md"]
assert [d.path for d in select_suggested(chunks, n=5)] == lifted
assert [d.path for d in select_related(chunks, set(), cap=5)] == lifted
assert weak_hit_titles(chunks) == lifted
# Explicit kill switch — the pre-phase-191 (name-bonus-only) walk.
assert [d.path for d in select_suggested(chunks, n=5, source_bonus=0.0)] == [
"gitea/README.md", "a.md", "d.md", "b.md", "c.md"
]
# Settings kill switch (BOR_SOURCE_NAME_HIT_BONUS=0) — the same walk.
off = Settings(_env_file=None, source_name_hit_bonus=0.0) # pyright: ignore[reportCallIssue]
monkeypatch.setattr(retriever, "get_settings", lambda: off)
pre = ["gitea/README.md", "a.md", "d.md", "b.md", "c.md"]
assert [d.path for d in select_suggested(chunks, n=5)] == pre
assert [d.path for d in select_related(chunks, set(), cap=5)] == pre
assert weak_hit_titles(chunks) == pre
def test_fuse_or_s_source_name_hit_on_double_hit() -> None:
"""A vector row merged with a flagged source-name row keeps
``source_name_hit=True`` — the merge ORs the flag in (the
``name_hit`` mirror), so the selection tier still sees the hit on
the fused list."""
v = _rc("gitserver.md", cosine=0.9)
l1 = _rc("gitserver.md", cosine=0.1) # the lexical copy of the same chunk
l1.chunk_id = v.chunk_id
l1.source_name_hit = True
out = fuse([v], [l1], k=60)
assert len(out) == 1
assert out[0].source_name_hit is True
assert out[0].fts_hit is True
assert out[0].score == pytest.approx(2 / 61)
def test_fuse_keeps_source_name_hit_on_lexical_only_hit() -> None:
"""A source-name-hit row with no vector rank keeps
``source_name_hit=True`` through the fusion (the ``replace()``
copy carries the field — the ``name_hit`` mirror)."""
row = _rc("gitserver.md")
row.source_name_hit = True
out = fuse([], [row], k=60)
assert len(out) == 1
assert out[0].source_name_hit is True
def test_fuse_default_source_name_hit_stays_false_for_ordinary_rows() -> None:
"""Neither list flagged ⇒ fusion never invents a source-name hit —
ordinary vector and FTS rows are ``source_name_hit=False``."""
out = fuse([_rc("a.md", cosine=0.8)], [_rc("b.md", fts_hit=True)], k=60)
assert len(out) == 2
assert all(rc.source_name_hit is False for rc in out)
# ---------------------------------------------------------------------------
# Phase 162, D1 — the accent-folded name normalization (LOCKED A1): the
# 2026-10-07 live gap, the ASCII filename vs the accented content layer