test: harden offline semantic proof
This commit is contained in:
@@ -7,6 +7,34 @@ root="$(cd "$(dirname "$0")/.." && pwd -P)"
|
||||
# shellcheck source=./unified-deployment-smoke.sh
|
||||
source "$root/scripts/unified-deployment-smoke.sh"
|
||||
|
||||
task13_write_offline_semantic_override() {
|
||||
TASK13_OFFLINE_OVERRIDE="$TASK13_TMP/compose.task13.offline-semantic.yaml"
|
||||
cat >"$TASK13_OFFLINE_OVERRIDE" <<'EOF'
|
||||
networks:
|
||||
thothii:
|
||||
internal: true
|
||||
EOF
|
||||
chmod 0600 "$TASK13_OFFLINE_OVERRIDE"
|
||||
}
|
||||
|
||||
task13_offline_semantic_compose() {
|
||||
docker compose \
|
||||
--project-name "$TASK13_PROJECT" \
|
||||
--project-directory "$TASK13_ROOT" \
|
||||
--env-file "$TASK13_ENV_FILE" \
|
||||
-f "$TASK13_ROOT/compose.yaml" \
|
||||
-f "$TASK13_ROOT/deploy/compose.local.yaml" \
|
||||
-f "$TASK13_OVERRIDE" \
|
||||
-f "$TASK13_OFFLINE_OVERRIDE" \
|
||||
"$@"
|
||||
}
|
||||
|
||||
task13_offline_semantic_compose_logged() {
|
||||
local label="$1"
|
||||
shift
|
||||
task13_run_logged "$label" task13_offline_semantic_compose "$@"
|
||||
}
|
||||
|
||||
task13_wait_internal_embedding_model() {
|
||||
printf '== Wait for the internal embedding model ==\n'
|
||||
for _attempt in $(seq 1 30); do
|
||||
@@ -42,9 +70,49 @@ PY
|
||||
task13_log_failure "internal embedding model readiness"
|
||||
}
|
||||
|
||||
task13_semantic_python_probe() {
|
||||
task13_wait_internal_embedding_model_offline() {
|
||||
printf '== Wait for the internal embedding model ==\n'
|
||||
for _attempt in $(seq 1 30); do
|
||||
if docker run --rm -i --pull never \
|
||||
--label "io.thothii.task13.run=$TASK13_RUN_ID" \
|
||||
--network "$TASK13_NETWORK" \
|
||||
--entrypoint /opt/venv/bin/python \
|
||||
"$TASK13_CORE_IMAGE" - <<'PY' >>"$TASK13_LOG" 2>&1
|
||||
import json
|
||||
import urllib.request
|
||||
import urllib.error
|
||||
|
||||
with urllib.request.urlopen("http://embedding:11434/api/tags", timeout=10) as response:
|
||||
payload = json.load(response)
|
||||
models = [entry.get("name") for entry in payload.get("models", []) if isinstance(entry, dict)]
|
||||
if "qwen3-embedding:0.6b" not in models:
|
||||
raise SystemExit(1)
|
||||
request = urllib.request.Request(
|
||||
"http://embedding:11434/api/embed",
|
||||
data=json.dumps({"model": "qwen3-embedding:0.6b", "input": ["warm semantic smoke"]}).encode("utf-8"),
|
||||
headers={"content-type": "application/json"},
|
||||
method="POST",
|
||||
)
|
||||
try:
|
||||
with urllib.request.urlopen(request, timeout=180) as response:
|
||||
payload = json.load(response)
|
||||
except urllib.error.URLError:
|
||||
raise SystemExit(1)
|
||||
embeddings = payload.get("embeddings")
|
||||
raise SystemExit(0 if isinstance(embeddings, list) and len(embeddings) == 1 and len(embeddings[0]) == 1024 else 1)
|
||||
PY
|
||||
then
|
||||
return 0
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
task13_log_failure "offline internal embedding model readiness"
|
||||
}
|
||||
|
||||
task13_semantic_python_probe_with() {
|
||||
local mode="$1"
|
||||
task13_compose exec -T core /opt/venv/bin/python - "$mode" <<'PY'
|
||||
shift
|
||||
"$@" "$mode" <<'PY'
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
@@ -247,6 +315,20 @@ print(json.dumps({
|
||||
PY
|
||||
}
|
||||
|
||||
task13_semantic_python_probe() {
|
||||
local mode="$1"
|
||||
task13_semantic_python_probe_with "$mode" task13_compose exec -T core /opt/venv/bin/python -
|
||||
}
|
||||
|
||||
task13_semantic_python_probe_offline() {
|
||||
local mode="$1"
|
||||
task13_semantic_python_probe_with "$mode" docker run --rm -i --pull never \
|
||||
--label "io.thothii.task13.run=$TASK13_RUN_ID" \
|
||||
--network "$TASK13_NETWORK" \
|
||||
--entrypoint /opt/venv/bin/python \
|
||||
"$TASK13_CORE_IMAGE" -
|
||||
}
|
||||
|
||||
task13_semantic_seed_and_assert() {
|
||||
local output
|
||||
printf '== Ensure the semantic collection and seed schema/evidence/memory ==\n'
|
||||
@@ -257,14 +339,38 @@ task13_semantic_seed_and_assert() {
|
||||
grep -Fq '"memory"' <<<"$output" || task13_fail "memory semantic verification did not run"
|
||||
}
|
||||
|
||||
task13_assert_offline_semantic_isolation() {
|
||||
local running
|
||||
[[ "$(docker network inspect --format '{{.Internal}}' "$TASK13_NETWORK")" == true ]] \
|
||||
|| task13_fail "offline semantic network still allows egress"
|
||||
running="$(task13_offline_semantic_compose ps --services --status running | sort)"
|
||||
[[ "$running" == $'embedding\nqdrant' ]] \
|
||||
|| task13_fail "offline semantic recreation started non-semantic services"
|
||||
for service in core frontend embedding-model-init; do
|
||||
if docker ps -a --filter "label=com.docker.compose.project=$TASK13_PROJECT" \
|
||||
--filter "label=com.docker.compose.service=$service" --format '{{.ID}}' | grep -q .; then
|
||||
task13_fail "offline semantic recreation invoked bootstrap service $service"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
task13_semantic_verify_persistence() {
|
||||
local output
|
||||
printf '== Restart offline and prove semantic points plus model cache persist ==\n'
|
||||
task13_write_environment /fixtures/offline.git
|
||||
task13_compose_logged "offline semantic recreation" up --detach --force-recreate --wait --wait-timeout 120
|
||||
task13_wait_internal_embedding_model
|
||||
task13_registry_status >>"$TASK13_LOG" 2>&1 || true
|
||||
output="$(task13_semantic_python_probe verify)"
|
||||
task13_write_offline_semantic_override
|
||||
task13_remove_labeled_container "${TASK13_LLM_CONTAINER:-}" >>"$TASK13_LOG" 2>&1 \
|
||||
|| task13_fail "offline semantic phase could not remove the temporary LLM fixture"
|
||||
task13_compose_logged "offline semantic stop" down --remove-orphans --timeout 10
|
||||
task13_offline_semantic_compose_logged "offline semantic recreation" \
|
||||
up --detach --wait --wait-timeout 120 --pull never qdrant embedding
|
||||
TASK13_NETWORK="$(docker network ls \
|
||||
--filter "label=com.docker.compose.project=$TASK13_PROJECT" \
|
||||
--filter 'label=com.docker.compose.network=thothii' --format '{{.Name}}')"
|
||||
[[ -n "$TASK13_NETWORK" && "$TASK13_NETWORK" != *$'\n'* ]] || task13_fail "offline semantic network was not resolved"
|
||||
task13_assert_offline_semantic_isolation
|
||||
task13_wait_internal_embedding_model_offline
|
||||
output="$(task13_semantic_python_probe_offline verify)"
|
||||
printf '%s\n' "$output" >>"$TASK13_LOG"
|
||||
grep -Fq '"schema"' <<<"$output" || task13_fail "schema semantic persistence did not verify"
|
||||
grep -Fq '"evidence"' <<<"$output" || task13_fail "evidence semantic persistence did not verify"
|
||||
|
||||
@@ -1410,6 +1410,25 @@ task13_self_test_public_timeout_contract() {
|
||||
|| task13_fail "direct internal semantic smoke invocation lacks an internal supervisor"
|
||||
}
|
||||
|
||||
task13_self_test_internal_semantic_offline_contract() {
|
||||
local root script
|
||||
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
|
||||
script="$root/scripts/internal-semantic-smoke.sh"
|
||||
grep -Fq 'task13_write_offline_semantic_override' "$script" \
|
||||
|| task13_fail "internal semantic smoke lacks a dedicated offline override"
|
||||
grep -Fq 'task13_offline_semantic_compose_logged "offline semantic recreation" \' "$script" \
|
||||
|| task13_fail "offline semantic recreation must use the isolated offline compose wrapper"
|
||||
grep -Fq 'up --detach --wait --wait-timeout 120 --pull never qdrant embedding' "$script" \
|
||||
|| task13_fail "offline semantic recreation must start only qdrant and embedding with --pull never"
|
||||
grep -Eq 'down --remove-orphans --timeout 10$' "$script" \
|
||||
|| task13_fail "offline semantic phase must stop the stack before isolated recreation"
|
||||
grep -Fq 'internal: true' "$script" \
|
||||
|| task13_fail "offline semantic override must disable network egress"
|
||||
if grep -Eq 'offline semantic recreation.*embedding-model-init|offline semantic recreation.*core|offline semantic recreation.*frontend' "$script"; then
|
||||
task13_fail "offline semantic recreation must exclude bootstrap and non-semantic services"
|
||||
fi
|
||||
}
|
||||
|
||||
task13_self_test_windows_release_contract() {
|
||||
local root script workflow
|
||||
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
|
||||
@@ -1519,6 +1538,7 @@ task13_self_test() {
|
||||
task13_self_test_timeout_process_group
|
||||
task13_self_test_nested_timeout_process_group
|
||||
task13_self_test_public_timeout_contract
|
||||
task13_self_test_internal_semantic_offline_contract
|
||||
task13_self_test_windows_release_contract
|
||||
task13_self_test_server_release_contract
|
||||
task13_self_test_server_auth_hop_contract
|
||||
@@ -1535,6 +1555,7 @@ task13_self_test_case() {
|
||||
timeout-group) task13_self_test_timeout_process_group ;;
|
||||
timeout-nested) task13_self_test_nested_timeout_process_group ;;
|
||||
timeout-public) task13_self_test_public_timeout_contract ;;
|
||||
semantic-offline) task13_self_test_internal_semantic_offline_contract ;;
|
||||
windows) task13_self_test_windows_release_contract ;;
|
||||
server) task13_self_test_server_release_contract ;;
|
||||
server-auth) task13_self_test_server_auth_hop_contract ;;
|
||||
|
||||
Reference in New Issue
Block a user