phase: 94_ls_tree_drilldown
All green. Verification complete. **Phase 94 — `ls` drill-down tree: final verification pass (all 5 tasks were already complete; verified, nothing to fix)** - Verified `ls` 3-level tree (`app/rag/agent.py`): `ls()` sources + summaries, `ls(source)`/`ls(source/folder)` drill-down, 50-line file cap + grep-pointer note, NOT-A-FOLDER teaching refusal - Verified `folder_summaries` (migration 0017, model, `app/rag/folder_summaries.py` generator: `FOLDER_SUMMARY_MODE` marker, fail-soft per folder, ≥2-doc scope + prune) wired change-gated in both sync paths - Verified 10-turn fixture battery verdict recorded in `TOOL_CALLING_TESTING.md` §9 (2026-09-11): turbo PASS 19/19 contract, 98.7 s (−12.5…−13.2 % vs baseline); lite PASS 18/18, 43.6 s (+7.7 %) — accuracy at/above baseline, gate met - `uv run pytest --cov=app --cov-report=term-missing` → 1939 passed, 0 failed; TOTAL coverage **99 %** (folder_summaries.py 100 %) - `uv run ruff check .` → clean; `uv run pyright` → 0 errors, 0 warnings - E2E in isolation: `test_ls_tree_drilldown.py` 3 passed; `test_agent_document_tools` 4, `test_agent_unlimited_tools` 4, `test_harness_aligned_tools` 3, `test_search_tool` 3, `test_grep_regex_teaching` 2, `test_response_to_docs` 4 — all passed (read/grep contracts untouched) - Dedicated folder-summary tests (fail-soft, prune, both sync paths, migration): 46 passed - Completion criteria: all 6 met; working tree holds only phase-94 changes (commit left to harness per protocol) **Next pending phase:** `95_read_truncation_cap`
This commit is contained in:
+30
-22
@@ -11,11 +11,15 @@ And the phase-71 deflection plain-text line (owner-permitted
|
||||
line; the ``DEFLECT_MODE`` marker-keying contract is unchanged and
|
||||
the line never leaks into the HIGH prompt.
|
||||
|
||||
And the phase-72 ``<tools>`` copy: the document-identity contract is
|
||||
stated up front (the ``ls`` source-name scope, the combined
|
||||
``source/path`` identity for ``read``/``grep``) — the same contract
|
||||
the teaching refusals in :mod:`app.rag.agent` re-state; the
|
||||
``<tools>`` marker keying (HIGH only) is unchanged.
|
||||
And the ``<tools>`` copy (phase 72: the document-identity contract
|
||||
stated up front — the combined ``source/path`` identity for
|
||||
``read``/``grep``; phase 94, task 03: the ``ls`` clause rewritten to
|
||||
the drill-down tree contract — one level per call, sources at the
|
||||
top, folders + files below, ``grep`` as the without-listing locator —
|
||||
while the ``read``/``grep`` clauses and the discipline rules are
|
||||
byte-identical): the teaching refusals in :mod:`app.rag.agent`
|
||||
re-state the same contract; the ``<tools>`` marker keying (HIGH
|
||||
only) is unchanged.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -194,20 +198,22 @@ pinned byte-for-byte in
|
||||
|
||||
|
||||
def test_tools_section_phase72_contract_clauses() -> None:
|
||||
"""Phase 72: the two contract clauses the teaching refusals
|
||||
"""Phase 72 + phase 94: the contract clauses the teaching refusals
|
||||
re-state after the fact, pinned byte-for-byte in the constant —
|
||||
the ``ls`` source-name clause (its optional ``path`` is a source
|
||||
name, not a directory or file path; omit it to list every
|
||||
document) and the ``read``/``grep`` combined-identity clause
|
||||
(the combined ``source/path`` string exactly as shown in the
|
||||
``ls`` output, *including the source name*; a bare document path
|
||||
will not resolve)."""
|
||||
# The ls source-name clause.
|
||||
assert (
|
||||
"a source name (e.g. 'homelab'), not a directory or file "
|
||||
"path — omit it to list every document"
|
||||
) in TOOLS_SECTION
|
||||
# The read combined-identity clause.
|
||||
the ``ls`` clause (phase 94: the drill-down tree contract — one
|
||||
level per call, sources at the top, folders + files below, never
|
||||
the whole KB in one call, ``grep`` as the without-listing locator)
|
||||
and the ``read``/``grep`` combined-identity clause (the combined
|
||||
``source/path`` string exactly as shown in the ``ls`` output,
|
||||
*including the source name*; a bare document path will not
|
||||
resolve)."""
|
||||
# The ls drill-down clauses (phase 94, task 03).
|
||||
assert "one level at a time" in TOOLS_SECTION
|
||||
assert "lists every synced source with its document count" in TOOLS_SECTION
|
||||
assert "that source's top-level folders and files" in TOOLS_SECTION
|
||||
assert "never the whole knowledge base in one call" in TOOLS_SECTION
|
||||
assert "to find one specific document without listing, use `grep`" in TOOLS_SECTION
|
||||
# The read combined-identity clause (byte-identical across phases).
|
||||
assert (
|
||||
"combined `source/path` string, exactly as shown in the `ls` "
|
||||
"output — including the source name"
|
||||
@@ -217,23 +223,25 @@ def test_tools_section_phase72_contract_clauses() -> None:
|
||||
"a bare document path (without the source name) will not resolve"
|
||||
) == 2
|
||||
# The pre-phase-70 scope wording is gone — replaced by the
|
||||
# explicit source-name contract.
|
||||
# explicit source-name contract (and the phase-72 source-name-only
|
||||
# clause by the phase-94 drill-down contract).
|
||||
assert "pass a source name as `path`" not in TOOLS_SECTION
|
||||
assert "not a directory or file path" not in TOOLS_SECTION
|
||||
|
||||
|
||||
def test_tools_section_phase72_clauses_in_high_prompt_not_low() -> None:
|
||||
"""Phase 72: the contract clauses ride the HIGH prompt with the
|
||||
"""Phase 72/94: the contract clauses ride the HIGH prompt with the
|
||||
rest of the section and never leak into the LOW/deflection prompt
|
||||
(whose byte-identity is pinned in
|
||||
:func:`test_zero_note_prompt_is_byte_identical_to_pre_steering`)."""
|
||||
doc = _doc("kubernetes.md", "Talos Linux on three nodes.", "Kubernetes Homelab Cluster")
|
||||
high = build_high_prompt([doc])
|
||||
assert "<tools>" in high
|
||||
assert "not a directory or file path" in high
|
||||
assert "one level at a time" in high # the phase-94 ls clause
|
||||
assert "including the source name" in high
|
||||
for low in (build_deflect_prompt(["T1"]), build_deflect_prompt([])):
|
||||
assert "<tools>" not in low
|
||||
assert "not a directory or file path" not in low
|
||||
assert "one level at a time" not in low
|
||||
assert "including the source name" not in low
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user