phase: 119_name_signal_read_chips
Build and Push Containers / build-and-push-app (push) Successful in 2m1s
Build and Push Containers / build-and-push-db (push) Successful in 18s

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.
This commit is contained in:
2026-09-16 15:50:48 -04:00
parent 795fb56425
commit a5b63f83ad
89 changed files with 4377 additions and 655 deletions
+92
View File
@@ -920,6 +920,98 @@ def render_folder_listing(
return "\n".join([header, *body])
def suggested_folder_lines(
db: Session,
suggested: Sequence[Document],
max_lines: int = 5,
max_entries: int = 8,
) -> list[str]:
"""The HIGH prompt's suggested-folder context lines (phase 119, D3,
LOCKED A4) — pure composition over the existing ``ls`` machinery.
One line per DISTINCT parent folder of the *suggested* documents —
in suggested-doc order, deduped by ``(source, parent prefix)`` (the
first suggested doc wins the slot), at most *max_lines* lines:
* the parent prefix is the path up to (excluding) the last ``/``
(``""`` = the source root);
* the line is ``<source>/<prefix>/: e1, e2, …`` (the source root
renders as ``<source>/: …`` — the filesystem-style folder path,
trailing slash included, + the colon) with the folder's direct
children in the
EXISTING ``ls`` folder-level rendering order — the direct
subfolders first (``name/ (N docs)``, the recursive doc count,
singular ``(1 doc)``), then the files by relative filename — so
the line reads the same as the model's own ``ls`` output of that
folder (the :func:`group_folder_listing` grouping, over
:func:`_source_document_rows` + :func:`_source_folder_summaries`);
* the suggested document that OWNS the line is excluded from the
entries (its identity is already in its ``<document>`` block — the
line is the folder's OTHER contents, the pre-seed that makes the
model ``read`` the right file in round 1 instead of walking the
``ls`` drill-downs);
* at most *max_entries* entries, then `` +N more`` (N = the
remaining count, the true pre-cap folder total — the suggested
doc leaves the total even when its row sat past
:data:`LS_MAX_FILE_LINES`); a folder whose only entry was the
suggested doc renders its header alone (the ``… — 0 documents, 0
folders:`` empty-level precedent).
Empty *suggested* → ``[]`` (the caller then builds the
byte-identical phase-118 prompt). Module-level so unit tests can
monkeypatch the fetchers without a database (the house style:
:func:`ls_top` / :func:`ls_folder` compose the same fetchers).
"""
lines: list[str] = []
seen: set[tuple[str, str]] = set()
rows_cache: dict[str, tuple[list[tuple[str, str, str]], dict[str, str]]] = {}
for doc in suggested:
if len(lines) >= max_lines:
break
prefix = folder_of(doc.path)
key = (doc.source, prefix)
if key in seen:
continue
seen.add(key)
if doc.source not in rows_cache:
rows_cache[doc.source] = (
_source_document_rows(db, doc.source),
_source_folder_summaries(db, doc.source),
)
rows, summaries = rows_cache[doc.source]
subfolders, files, total_files = group_folder_listing(
doc.source, prefix, rows, summaries
)
entries = [
f"{sub}/ ({count} {'doc' if count == 1 else 'docs'})"
for sub, count, _summary in subfolders
]
# The owning suggested doc is a direct file of this folder —
# drop it from the entries (its identity is already in its
# <document> block); its count leaves the total either way
# (even when its row sat past the LS_MAX_FILE_LINES file cap).
files = [entry for entry in files if entry[1] != doc.path]
# The file entries come AFTER the subfolders (the ls folder-level
# order) and ride by RELATIVE filename — the basename within the
# folder (the line's ``<source>/<prefix>/:`` header supplies the
# folder; combined ``source/prefix/name`` is the read identity).
entries.extend(path.rsplit("/", 1)[-1] for _src, path, _title, _date in files)
total = len(subfolders) + total_files - 1
shown = entries[:max_entries]
# The pinned identity shape: ``<source>/<prefix>/:`` (the source
# root: ``<source>/:``) — the filesystem-style folder path
# (trailing slash included) + the colon.
identity = f"{doc.source}/{prefix}/" if prefix else f"{doc.source}/"
line = f"{identity}:"
if shown:
suffix = ", ".join(shown)
if total > len(shown):
suffix += f" +{total - len(shown)} more"
line += f" {suffix}"
lines.append(line)
return lines
def find_document(db: Session, source: str, path: str) -> Document | None:
"""The indexed document at ``(source, path)``, or ``None``.