test: harden offline semantic proof

This commit is contained in:
2026-08-08 20:42:14 +02:00
parent 8240fa4472
commit bff21507df
2 changed files with 133 additions and 6 deletions
+112 -6
View File
@@ -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"
+21
View File
@@ -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 ;;