Expose --kind on ai_query so definitional questions can reach the prose

The index already stored chunk origin and search.js already filtered on it;
only the wrapper refused the flag. Intent routing boosts PURPOSE for "what
is X", which buried README.md and made the system answer that it had no
definition of itself.
This commit is contained in:
Gmer4Lfe
2026-08-02 13:09:17 -04:00
parent 885cceccae
commit eb36641523
2 changed files with 38 additions and 2 deletions
+15
View File
@@ -59,6 +59,20 @@ Applied as a **score boost, not a filter**. Intent detection is a heuristic, and
must never be able to exclude the one chunk that holds the answer. `--section=NAME` forces a must never be able to exclude the one chunk that holds the answer. `--section=NAME` forces a
hard filter when you actually want one. hard filter when you actually want one.
The boost still has a blind spot worth knowing about: **definitional questions.** "What is
Varaverk?" matches the `PURPOSE` intent, so every script's one-line PURPOSE gets boosted above
the top-level prose that actually answers it — and the model correctly replies that the context
does not define the system. The corpus is fine; `README.md` is indexed. The routing simply
buries it. `--kind=readme` is the hard filter for that case:
```bash
bash AI/ai_query.sh --kind=readme "what is Varaverk"
```
`--kind` filters on where a chunk came from — `header`, `readme`, `manual`, `template`, `doc`
and composes with `--section`. Prefer it over `--section` for "what is" and "why does this
exist" questions, where the answer is narrative rather than a header field.
--- ---
## ━━━ NAMED-PARAGRAPH SUB-CHUNKING ━━━ ## ━━━ NAMED-PARAGRAPH SUB-CHUNKING ━━━
@@ -154,6 +168,7 @@ bash AI/ai_index.sh --status # size, counts, last build
bash AI/ai_query.sh "what stops rsync and the mover running at once" bash AI/ai_query.sh "what stops rsync and the mover running at once"
bash AI/ai_query.sh --search "why are the cache writers lockless" bash AI/ai_query.sh --search "why are the cache writers lockless"
bash AI/ai_query.sh --section=CONFIGURATION "which variable sets the mover grace period" bash AI/ai_query.sh --section=CONFIGURATION "which variable sets the mover grace period"
bash AI/ai_query.sh --kind=readme "what is Varaverk" # definitional / narrative
bash AI/ai_query.sh --json "..." # for other scripts bash AI/ai_query.sh --json "..." # for other scripts
``` ```
+23 -2
View File
@@ -104,6 +104,12 @@
# ai_query.sh --section=CONFIGURATION "your question" # ai_query.sh --section=CONFIGURATION "your question"
# Restrict retrieval to one header section. # Restrict retrieval to one header section.
# #
# ai_query.sh --kind=readme "what is Varaverk"
# Restrict retrieval to one chunk origin: header, readme, manual, template, doc.
# Use this for definitional and narrative questions. Intent routing boosts header
# sections such as PURPOSE, which answers "what does this script do" well but buries
# the top-level prose that explains what the system *is*. --kind=readme reaches it.
#
# ai_query.sh --json "your question" # ai_query.sh --json "your question"
# Machine-readable output for other scripts. # Machine-readable output for other scripts.
# #
@@ -119,18 +125,32 @@ source "${SCRIPT_DIR}/../load_config.sh"
detect_hosts detect_hosts
SEARCH_ONLY=false; JSON=false; STATUS=false; SECTION=""; QUERY="" SEARCH_ONLY=false; JSON=false; STATUS=false; SECTION=""; KIND=""; QUERY=""
for arg in "$@"; do for arg in "$@"; do
case "$arg" in case "$arg" in
--search) SEARCH_ONLY=true ;; --search) SEARCH_ONLY=true ;;
--json) JSON=true ;; --json) JSON=true ;;
--status) STATUS=true ;; --status) STATUS=true ;;
--section=*) SECTION="${arg#*=}" ;; --section=*) SECTION="${arg#*=}" ;;
--kind=*) KIND="${arg#*=}" ;;
--*) echo "Unknown option: $arg" >&2; exit 1 ;; --*) echo "Unknown option: $arg" >&2; exit 1 ;;
*) QUERY="$arg" ;; *) QUERY="$arg" ;;
esac esac
done done
# --kind is a hard filter on chunk origin; --section filters the header section within a
# chunk. They answer different questions and compose: --kind=readme --section=PURPOSE is
# meaningful. Validated here rather than in the CLI so a typo costs nothing — an unknown kind
# silently matches no rows, which reads as "the index has no answer" and is the most
# misleading failure this tool can produce.
if [[ -n "$KIND" ]]; then
case "$KIND" in
header|readme|manual|template|doc) ;;
*) echo "Unknown --kind=$KIND (expected: header, readme, manual, template, doc)" >&2
exit 1 ;;
esac
fi
CLI="${SCRIPT_DIR}/lib/cli.js" CLI="${SCRIPT_DIR}/lib/cli.js"
DB="${AI_INDEX_DB:-${DATA_DIR}/ai_index.db}" DB="${AI_INDEX_DB:-${DATA_DIR}/ai_index.db}"
@@ -156,7 +176,7 @@ if [[ "${AI_ENABLED:-false}" != "true" ]]; then
exit 0 exit 0
fi fi
[[ -z "$QUERY" ]] && { echo "usage: ai_query.sh [--search] [--section=NAME] \"your question\"" >&2; exit 1; } [[ -z "$QUERY" ]] && { echo "usage: ai_query.sh [--search] [--section=NAME] [--kind=KIND] \"your question\"" >&2; exit 1; }
[[ -f "$DB" ]] || { error "No index at $DB — run AI/ai_index.sh first"; exit 1; } [[ -f "$DB" ]] || { error "No index at $DB — run AI/ai_index.sh first"; exit 1; }
[[ -f "$CLI" ]] || { error "missing $CLI"; exit 1; } [[ -f "$CLI" ]] || { error "missing $CLI"; exit 1; }
command -v node >/dev/null 2>&1 || { error "node not found"; exit 1; } command -v node >/dev/null 2>&1 || { error "node not found"; exit 1; }
@@ -169,6 +189,7 @@ fi
_args=("--db=${DB}" "--url=${OLLAMA_URL}" "--query=${QUERY}") _args=("--db=${DB}" "--url=${OLLAMA_URL}" "--query=${QUERY}")
[[ -n "$SECTION" ]] && _args+=("--section=${SECTION}") [[ -n "$SECTION" ]] && _args+=("--section=${SECTION}")
[[ -n "$KIND" ]] && _args+=("--kind=${KIND}")
[[ "$JSON" == true ]] && _args+=(--json) [[ "$JSON" == true ]] && _args+=(--json)
if [[ "$SEARCH_ONLY" == true ]]; then if [[ "$SEARCH_ONLY" == true ]]; then