#!/usr/bin/env bash set -eo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" TACHYON_LIB="$ROOT_DIR/tachyon/files/usr/lib" export TACHYON_LIB="$TACHYON_LIB" fail() { printf 'FAIL: %s\n' "$1" >&2 exit 1 } RAG_UC="$TACHYON_LIB/diagnostics/rag.uc" RUNTIME_UC="$TACHYON_LIB/diagnostics/runtime.uc" # 1. Regression for the inverted push(): collecting vectors from an # OpenAI-format response must append each embedding into the result array, # not append the (still empty) result array into each source embedding - # which silently made RAG return "" for every primary provider. grep -Fq 'push(embeddings, data.data[i].embedding);' "$RAG_UC" || fail "rag.uc must collect embeddings into the result array" grep -Fq 'push(data.data[i].embedding, embeddings);' "$RAG_UC" && fail "rag.uc still contains the inverted push(embedding, result) call" # 2. The cached embeddings are keyed by an index fingerprint so a rebuilt # index cannot serve stale vectors forever. grep -Fq 'cached.index_stamp == stamp' "$RAG_UC" || fail "rag.uc cache validation must compare the index fingerprint" grep -Fq 'function index_stamp()' "$RAG_UC" || fail "rag.uc must define index_stamp()" grep -Fq 'index_stamp: index_stamp(),' "$RAG_UC" || fail "rag.uc must persist the index fingerprint alongside the cache" # 3. A null/unset model override must be normalized before use; previously a # use-before-declaration produced model:null payloads rejected by APIs. grep -Fq 'model_override = trim(as_string(model_override));' "$RAG_UC" || fail "rag.uc get_embedding_model must normalize a null model override" # 4. runtime.uc must declare model_override before the RAG call consumes it. rag_line="$(grep -n 'rag_context = rag.retrieve' "$RUNTIME_UC" | cut -d: -f1)" decl_line="$(grep -n 'let model_override = trim(cfg.ai_doctor_model' "$RUNTIME_UC" | cut -d: -f1)" [ -n "$rag_line" ] && [ -n "$decl_line" ] || fail "runtime.uc must contain both the rag.retrieve call and its model_override declaration" [ "$decl_line" -lt "$rag_line" ] || fail "runtime.uc declares model_override AFTER rag.retrieve uses it (ucode does not hoist)" # 5. Pin the actual push() semantics of this ucode build so the fixed code # above stays meaningful across toolchain updates. push_check="$(ucode -e ' let source = [[1,2],[3,4]]; let out = []; for (let i = 0; i < length(source); i++) push(out, source[i]); print((length(out) == 2 && length(out[0]) == 2 && out[1][1] == 4) ? "OK" : "BAD"); ' 2>/dev/null || echo BAD)" [ "$push_check" = "OK" ] || fail "ucode push(array, value) did not behave as expected (saw '$push_check')" # 6. Runtime verification of rag.uc functions (as_string, get_embedding_model, search, sqrt_val, slice) runtime_check="$(ucode -L "$TACHYON_LIB" -e ' let rag = require("diagnostics.rag"); assert(rag.get_embedding_model("OpenAI") == "text-embedding-3-small", "OpenAI"); assert(rag.get_embedding_model("DEEPSEEK") == "deepseek-embedding", "DeepSeek"); assert(rag.get_embedding_model(null, null) == "text-embedding-3-small", "null"); let idx = { chunks: [ { file: "f1.md", heading: "H1", text: "T1", embedding: [1.0, 0.0] }, { file: "f2.md", heading: "H2", text: "T2", embedding: [0.9, 0.1] }, { file: "f3.md", heading: "H3", text: "T3", embedding: [0.8, 0.2] } ] }; let res = rag.search([1.0, 0.0], idx, 2); assert(length(res) == 2, "limit 2"); assert(res[0].chunk.file == "f1.md", "best match"); print("OK"); ' 2>&1 || echo "FAIL")" [ "$runtime_check" = "OK" ] || fail "rag.uc runtime execution failed (saw '$runtime_check')" printf 'rag embeddings checks passed\n'