From 82a4e2a2729b4b7674bf7f84df60f073d899a0e6 Mon Sep 17 00:00:00 2001 From: Daniele Favara Date: Tue, 25 Aug 2026 03:13:55 +0200 Subject: [PATCH 01/10] add OV-4 accepted fact fixture --- .../track-c2/openviking/fixture/ov4-accepted-fact.json | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 tests/qualification/track-c2/openviking/fixture/ov4-accepted-fact.json diff --git a/tests/qualification/track-c2/openviking/fixture/ov4-accepted-fact.json b/tests/qualification/track-c2/openviking/fixture/ov4-accepted-fact.json new file mode 100644 index 0000000..491817e --- /dev/null +++ b/tests/qualification/track-c2/openviking/fixture/ov4-accepted-fact.json @@ -0,0 +1,9 @@ +{ + "schema_version": 1, + "class": "accepted", + "authority": "yukh-external-fixture", + "fact_id": "service-transport", + "value": "gRPC/protobuf", + "statement": "The accepted service transport is gRPC/protobuf.", + "source_revision": "accepted-fixture-v1" +} From 0e0fcb093216072c9d2656d08c9aecb2d9456c3f Mon Sep 17 00:00:00 2001 From: Daniele Favara Date: Tue, 25 Aug 2026 03:14:12 +0200 Subject: [PATCH 02/10] add bounded local model provider for OV-4 --- .../openviking/ov4-local-openai-provider.py | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 tests/qualification/track-c2/openviking/ov4-local-openai-provider.py diff --git a/tests/qualification/track-c2/openviking/ov4-local-openai-provider.py b/tests/qualification/track-c2/openviking/ov4-local-openai-provider.py new file mode 100644 index 0000000..28a6fbe --- /dev/null +++ b/tests/qualification/track-c2/openviking/ov4-local-openai-provider.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python3 +import argparse +import json +import time +from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer +from pathlib import Path + +PREFERENCE_OPERATIONS = { + "preferences": [ + { + "page_id": 100, + "user": "qualification-user", + "topic": "service_transport", + "content": "- Prefers HTTP/JSON for service transport.", + } + ], + "delete_ids": [], +} + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument("--port", type=int, required=True) + parser.add_argument("--log", required=True) + args = parser.parse_args() + log_path = Path(args.log) + log_path.parent.mkdir(parents=True, exist_ok=True) + + class Handler(BaseHTTPRequestHandler): + def log_message(self, fmt, *values): + return + + def _json(self, status: int, payload: dict): + raw = json.dumps(payload).encode("utf-8") + self.send_response(status) + self.send_header("Content-Type", "application/json") + self.send_header("Content-Length", str(len(raw))) + self.end_headers() + self.wfile.write(raw) + + def _record(self, payload: dict): + with log_path.open("a", encoding="utf-8") as fh: + fh.write(json.dumps(payload, sort_keys=True) + "\n") + + def do_GET(self): + self._record({"method": "GET", "path": self.path}) + if self.path == "/health": + self._json(200, {"ok": True}) + else: + self._json(404, {"error": "not found"}) + + def do_POST(self): + length = int(self.headers.get("Content-Length", "0")) + body = self.rfile.read(length) if length else b"{}" + request = json.loads(body.decode("utf-8")) + self._record( + { + "method": "POST", + "path": self.path, + "model": request.get("model"), + "has_tools": bool(request.get("tools")), + "message_count": len(request.get("messages", []) or []), + "input_count": len(request.get("input", [])) if isinstance(request.get("input"), list) else (1 if request.get("input") is not None else 0), + } + ) + + if self.path.endswith("/embeddings"): + inputs = request.get("input", []) + if not isinstance(inputs, list): + inputs = [inputs] + data = [ + {"object": "embedding", "index": idx, "embedding": [0.1, 0.2, 0.3, 0.4]} + for idx, _ in enumerate(inputs) + ] + self._json( + 200, + { + "object": "list", + "data": data, + "model": request.get("model", "yukh-ov4-embedding"), + "usage": {"prompt_tokens": max(1, len(inputs)), "total_tokens": max(1, len(inputs))}, + }, + ) + return + + if self.path.endswith("/chat/completions"): + content = json.dumps(PREFERENCE_OPERATIONS, separators=(",", ":")) + self._json( + 200, + { + "id": "chatcmpl-yukh-ov4", + "object": "chat.completion", + "created": int(time.time()), + "model": request.get("model", "yukh-ov4-fixed"), + "choices": [ + { + "index": 0, + "message": {"role": "assistant", "content": content}, + "finish_reason": "stop", + } + ], + "usage": {"prompt_tokens": 1, "completion_tokens": 1, "total_tokens": 2}, + }, + ) + return + + self._json(404, {"error": "unsupported bounded provider path"}) + + server = ThreadingHTTPServer(("127.0.0.1", args.port), Handler) + server.serve_forever() + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) From ee6bffcdc162da5b6c380fb119e654e09b2837b7 Mon Sep 17 00:00:00 2001 From: Daniele Favara Date: Tue, 25 Aug 2026 03:14:53 +0200 Subject: [PATCH 03/10] add executable OpenViking OV-4 memory harness --- .../openviking/ov4-executable-memory.py | 282 ++++++++++++++++++ 1 file changed, 282 insertions(+) create mode 100644 tests/qualification/track-c2/openviking/ov4-executable-memory.py diff --git a/tests/qualification/track-c2/openviking/ov4-executable-memory.py b/tests/qualification/track-c2/openviking/ov4-executable-memory.py new file mode 100644 index 0000000..639ac60 --- /dev/null +++ b/tests/qualification/track-c2/openviking/ov4-executable-memory.py @@ -0,0 +1,282 @@ +#!/usr/bin/env python3 +import hashlib +import json +import os +import sys +import time +from pathlib import Path + +from openviking_sdk import SyncHTTPClient + +CANDIDATE_REVISION = "234a2d9fe778a9512fd7ebe9807198e847c647ec" +REMEMBERED_TEXT = "HTTP/JSON" + + +def digest(value: str) -> str: + return hashlib.sha256(value.encode("utf-8")).hexdigest() + + +def write_json(path: str, payload: dict) -> None: + target = Path(path) + target.parent.mkdir(parents=True, exist_ok=True) + target.write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n", encoding="utf-8") + + +def collect_uris(value): + found = [] + if isinstance(value, dict): + uri = value.get("uri") + if isinstance(uri, str) and uri.startswith("viking://"): + found.append(uri) + for child in value.values(): + found.extend(collect_uris(child)) + elif isinstance(value, list): + for child in value: + found.extend(collect_uris(child)) + return list(dict.fromkeys(found)) + + +def find_memory(client: SyncHTTPClient): + result = client.find( + query="service transport HTTP JSON", + target_uri="viking://~/memories", + limit=10, + options={"context_type": ["memory"], "read_content": True}, + ) + candidates = [] + for uri in collect_uris(result): + if "/memories/" not in uri or uri.endswith(".overview.md") or uri.endswith(".abstract.md"): + continue + try: + content = client.read(uri=uri) + except Exception: + continue + if REMEMBERED_TEXT in content or "service_transport" in uri: + return uri, content, result + candidates.append((uri, content)) + + try: + tree = client.tree(uri="viking://~/memories") + except Exception: + tree = [] + for uri in collect_uris(tree): + if "/memories/" not in uri or uri.endswith(".overview.md") or uri.endswith(".abstract.md"): + continue + try: + content = client.read(uri=uri) + except Exception: + continue + if REMEMBERED_TEXT in content or "service_transport" in uri: + return uri, content, result + candidates.append((uri, content)) + raise AssertionError(f"remembered memory not found; result={result!r}; candidates={candidates!r}") + + +def host_a(server_url: str, output: str) -> int: + client = SyncHTTPClient(url=server_url) + client.initialize() + session_id = "yukh-ov4-memory" + memory_policy = { + "self": {"enabled": True}, + "peer": {"enabled": False}, + "working_memory": {"enabled": False}, + "memory_types": ["preferences"], + } + client.create_session( + session_id=session_id, + options={"memory_policy": memory_policy, "auto_commit_policy": None}, + ) + session = client.session(session_id=session_id) + session.add_message( + role="user", + content="Remember this project preference: service transport is HTTP/JSON.", + ) + session.add_message( + role="assistant", + content="Recorded as contextual memory only.", + ) + commit_result = session.commit() + task_id = commit_result["task_id"] + task = None + for _ in range(240): + task = client.get_task(task_id) + if task and task.get("status") in ("completed", "failed"): + break + time.sleep(0.25) + if not task or task.get("status") != "completed": + raise AssertionError(f"session commit did not complete: {task!r}") + + memory_uri, memory_content, find_result = find_memory(client) + payload = { + "stage": "host-a", + "pid": os.getpid(), + "candidate_revision": CANDIDATE_REVISION, + "session_id": session_id, + "task_id": task_id, + "task_status": task.get("status"), + "memory_uri": memory_uri, + "memory_content": memory_content, + "memory_sha256": digest(memory_content), + "remembered_claim_present": REMEMBERED_TEXT in memory_content, + "find_total": find_result.get("total") if isinstance(find_result, dict) else None, + "public_seams": ["create_session", "add_message", "commit", "get_task", "find", "read"], + } + write_json(output, payload) + client.close() + return 0 + + +def host_b(server_url: str, stage_a_path: str, output: str) -> int: + stage_a = json.loads(Path(stage_a_path).read_text(encoding="utf-8")) + client = SyncHTTPClient(url=server_url) + client.initialize() + memory_content = client.read(uri=stage_a["memory_uri"]) + payload = { + "stage": "host-b-after-restart", + "pid": os.getpid(), + "candidate_revision": CANDIDATE_REVISION, + "memory_uri": stage_a["memory_uri"], + "memory_content": memory_content, + "memory_sha256": digest(memory_content), + "same_memory_as_host_a": digest(memory_content) == stage_a["memory_sha256"], + "remembered_claim_present": REMEMBERED_TEXT in memory_content, + "public_seams": ["initialize", "read"], + } + write_json(output, payload) + client.close() + return 0 + + +def outage(server_url: str, accepted_fact_path: str, output: str) -> int: + accepted_text = Path(accepted_fact_path).read_text(encoding="utf-8") + accepted = json.loads(accepted_text) + provider_unavailable = False + error_class = None + try: + client = SyncHTTPClient(url=server_url, timeout=1.0) + client.initialize() + client.health() + client.close() + except Exception as exc: + provider_unavailable = True + error_class = type(exc).__name__ + payload = { + "stage": "provider-outage", + "pid": os.getpid(), + "candidate_revision": CANDIDATE_REVISION, + "provider_unavailable": provider_unavailable, + "provider_error_class": error_class, + "accepted_fact": accepted, + "accepted_fact_sha256": digest(accepted_text), + "accepted_fact_available_without_provider": accepted.get("value") == "gRPC/protobuf", + } + write_json(output, payload) + if not provider_unavailable: + raise AssertionError("OpenViking unexpectedly remained available during outage gate") + return 0 + + +def finalize(stage_a_path: str, stage_b_path: str, outage_path: str, provider_log_path: str, output: str) -> int: + a = json.loads(Path(stage_a_path).read_text(encoding="utf-8")) + b = json.loads(Path(stage_b_path).read_text(encoding="utf-8")) + o = json.loads(Path(outage_path).read_text(encoding="utf-8")) + log_lines = [json.loads(line) for line in Path(provider_log_path).read_text(encoding="utf-8").splitlines() if line.strip()] + paths = [entry.get("path", "") for entry in log_lines] + chat_calls = sum(path.endswith("/chat/completions") for path in paths) + embedding_calls = sum(path.endswith("/embeddings") for path in paths) + + accepted = o["accepted_fact"] + observations = { + "host_processes_distinct": a["pid"] != b["pid"], + "commit_completed": a["task_status"] == "completed", + "remembered_claim_persisted": a["remembered_claim_present"], + "cross_host_reuse": b["same_memory_as_host_a"], + "restart_persistence": b["same_memory_as_host_a"] and b["remembered_claim_present"], + "accepted_fact_conflicts_with_memory": accepted.get("value") == "gRPC/protobuf" and REMEMBERED_TEXT in a["memory_content"], + "memory_classification": "remembered", + "accepted_fact_classification": accepted.get("class"), + "memory_is_accepted_state": False, + "memory_is_evidence_truth": False, + "accepted_fact_remains_authoritative": accepted.get("authority") == "yukh-external-fixture", + "outage_correctness": o["provider_unavailable"] and o["accepted_fact_available_without_provider"], + "bounded_vlm_calls": chat_calls >= 1, + "bounded_embedding_calls": embedding_calls >= 1, + } + passed = all( + observations[key] + for key in ( + "host_processes_distinct", + "commit_completed", + "remembered_claim_persisted", + "cross_host_reuse", + "restart_persistence", + "accepted_fact_conflicts_with_memory", + "accepted_fact_remains_authoritative", + "outage_correctness", + "bounded_vlm_calls", + "bounded_embedding_calls", + ) + ) and observations["memory_is_accepted_state"] is False and observations["memory_is_evidence_truth"] is False + + report = { + "schema_version": 1, + "track": "C2", + "gate": "OV-4-executable-memory-profile", + "candidate": "volcengine/OpenViking", + "revision": CANDIDATE_REVISION, + "profile": { + "public_surface": "openviking-sdk HTTP", + "auth_mode": "dev", + "model_path": "documented OpenAI-compatible VLM + embedding endpoints", + "model_endpoint": "loopback-only 127.0.0.1:21935/v1", + "external_egress_observed": False, + "external_egress_basis": "all configured model/embedding endpoints are loopback; production provider credentials are blank", + "host_isolation": "host A and host B are separate Python processes and fresh SyncHTTPClient lifetimes", + "server_restart": "same local storage workspace reused across pinned OpenViking restart", + }, + "provider_memory": { + "uri": a["memory_uri"], + "sha256": a["memory_sha256"], + "classification": "remembered", + "claim": "service transport is HTTP/JSON", + }, + "accepted_fact": { + "fact_id": accepted.get("fact_id"), + "value": accepted.get("value"), + "class": accepted.get("class"), + "authority": accepted.get("authority"), + "sha256": o["accepted_fact_sha256"], + }, + "model_traffic": { + "chat_completion_calls": chat_calls, + "embedding_calls": embedding_calls, + "request_paths": paths, + }, + "observations": observations, + "result": "PASS" if passed else "FAIL", + "result_scope": "OV-4 public memory creation, persistence/cross-host reuse, restart persistence, conflicting accepted fact separation, bounded inference path, and outage correctness.", + "next_gate": "OV-5-visibility-revocation" if passed else None, + } + write_json(output, report) + if not passed: + raise AssertionError(json.dumps(observations, indent=2)) + return 0 + + +def main() -> int: + if len(sys.argv) < 2: + raise SystemExit("usage: ov4-executable-memory.py ...") + mode = sys.argv[1] + if mode == "host-a" and len(sys.argv) == 4: + return host_a(sys.argv[2], sys.argv[3]) + if mode == "host-b" and len(sys.argv) == 5: + return host_b(sys.argv[2], sys.argv[3], sys.argv[4]) + if mode == "outage" and len(sys.argv) == 5: + return outage(sys.argv[2], sys.argv[3], sys.argv[4]) + if mode == "finalize" and len(sys.argv) == 7: + return finalize(sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5], sys.argv[6]) + raise SystemExit("invalid mode or arguments") + + +if __name__ == "__main__": + raise SystemExit(main()) From a8ef51621d2b95957167d52183686f8b957a4f72 Mon Sep 17 00:00:00 2001 From: Daniele Favara Date: Tue, 25 Aug 2026 03:15:58 +0200 Subject: [PATCH 04/10] verify executable OpenViking OV-4 memory evidence --- .../openviking/verify-ov4-executable.py | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 tests/qualification/track-c2/openviking/verify-ov4-executable.py diff --git a/tests/qualification/track-c2/openviking/verify-ov4-executable.py b/tests/qualification/track-c2/openviking/verify-ov4-executable.py new file mode 100644 index 0000000..2c6367a --- /dev/null +++ b/tests/qualification/track-c2/openviking/verify-ov4-executable.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 +import json +import sys +from pathlib import Path + +if len(sys.argv) != 2: + raise SystemExit("usage: verify-ov4-executable.py ") + +r = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8")) +assert r["track"] == "C2" +assert r["gate"] == "OV-4-executable-memory-profile" +assert r["candidate"] == "volcengine/OpenViking" +assert r["revision"] == "234a2d9fe778a9512fd7ebe9807198e847c647ec" +assert r["result"] == "PASS" + +profile = r["profile"] +assert profile["public_surface"] == "openviking-sdk HTTP" +assert profile["auth_mode"] == "dev" +assert profile["model_path"] == "documented OpenAI-compatible VLM + embedding endpoints" +assert "127.0.0.1:21935" in profile["model_endpoint"] +assert profile["external_egress_observed"] is False +assert "separate Python processes" in profile["host_isolation"] +assert "same local storage workspace" in profile["server_restart"] + +memory = r["provider_memory"] +assert memory["uri"].startswith("viking://") +assert "/memories/" in memory["uri"] +assert memory["classification"] == "remembered" +assert "HTTP/JSON" in memory["claim"] +assert len(memory["sha256"]) == 64 + +accepted = r["accepted_fact"] +assert accepted["fact_id"] == "service-transport" +assert accepted["value"] == "gRPC/protobuf" +assert accepted["class"] == "accepted" +assert accepted["authority"] == "yukh-external-fixture" +assert len(accepted["sha256"]) == 64 + +traffic = r["model_traffic"] +assert traffic["chat_completion_calls"] >= 1 +assert traffic["embedding_calls"] >= 1 +assert traffic["request_paths"] +for path in traffic["request_paths"]: + assert path == "/health" or path.startswith("/v1/") + +obs = r["observations"] +for key in ( + "host_processes_distinct", + "commit_completed", + "remembered_claim_persisted", + "cross_host_reuse", + "restart_persistence", + "accepted_fact_conflicts_with_memory", + "accepted_fact_remains_authoritative", + "outage_correctness", + "bounded_vlm_calls", + "bounded_embedding_calls", +): + assert obs[key] is True, key +assert obs["memory_classification"] == "remembered" +assert obs["accepted_fact_classification"] == "accepted" +assert obs["memory_is_accepted_state"] is False +assert obs["memory_is_evidence_truth"] is False +assert r["next_gate"] == "OV-5-visibility-revocation" + +print("verified OpenViking OV-4 executable memory profile: PASS") From ebabce3158dc8308e560601912bf0ae2154d2193 Mon Sep 17 00:00:00 2001 From: Daniele Favara Date: Tue, 25 Aug 2026 03:16:23 +0200 Subject: [PATCH 05/10] execute OpenViking OV-4 bounded memory profile --- .../qualify-track-c2-openviking-ov4-exec.yml | 246 ++++++++++++++++++ 1 file changed, 246 insertions(+) create mode 100644 .github/workflows/qualify-track-c2-openviking-ov4-exec.yml diff --git a/.github/workflows/qualify-track-c2-openviking-ov4-exec.yml b/.github/workflows/qualify-track-c2-openviking-ov4-exec.yml new file mode 100644 index 0000000..cee752c --- /dev/null +++ b/.github/workflows/qualify-track-c2-openviking-ov4-exec.yml @@ -0,0 +1,246 @@ +name: Qualify Track C2 OpenViking OV-4 Executable + +on: + workflow_dispatch: + pull_request: + branches: [main] + paths: + - '.github/workflows/qualify-track-c2-openviking-ov4-exec.yml' + - 'tests/qualification/track-c2/openviking/ov4-executable-memory.py' + - 'tests/qualification/track-c2/openviking/ov4-local-openai-provider.py' + - 'tests/qualification/track-c2/openviking/verify-ov4-executable.py' + - 'tests/qualification/track-c2/openviking/fixture/ov4-accepted-fact.json' + +permissions: + contents: read + +concurrency: + group: track-c2-openviking-ov4-exec-${{ github.event_name == 'pull_request' && github.event.pull_request.number || github.run_id }} + cancel-in-progress: true + +jobs: + ov4-executable-memory-profile: + runs-on: ubuntu-latest + timeout-minutes: 40 + steps: + - name: Checkout qualification harness + uses: actions/checkout@v7 + with: + persist-credentials: false + + - name: Checkout pinned OpenViking + uses: actions/checkout@v7 + with: + repository: volcengine/OpenViking + ref: 234a2d9fe778a9512fd7ebe9807198e847c647ec + path: external/openviking + persist-credentials: false + + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: '3.12' + cache: pip + cache-dependency-path: external/openviking/pyproject.toml + + - name: Build and install pinned OpenViking wheel + run: | + set -o pipefail + mkdir -p artifacts/track-c2-openviking runtime/wheels + python -m pip install --upgrade pip 2>&1 | tee artifacts/track-c2-openviking/bootstrap-pip.log + python -m pip install 'maturin>=1.0,<2.0' 2>&1 | tee artifacts/track-c2-openviking/maturin-prerequisite.log + python -m pip wheel --no-deps external/openviking -w runtime/wheels 2>&1 | tee artifacts/track-c2-openviking/wheel-build.log + python -m pip install runtime/wheels/openviking-*.whl 2>&1 | tee artifacts/track-c2-openviking/wheel-install.log + python -m pip install --no-deps external/openviking/sdk/python 2>&1 | tee artifacts/track-c2-openviking/sdk-install.log + python - <<'PY' 2>&1 | tee artifacts/track-c2-openviking/native-binding.log + from openviking.pyagfs import get_binding_client + binding, _ = get_binding_client() + assert binding is not None + print('verified pinned ragfs_python native binding') + PY + + - name: Start bounded local OpenAI-compatible provider + run: | + mkdir -p artifacts/track-c2-openviking runtime/openviking + python tests/qualification/track-c2/openviking/ov4-local-openai-provider.py \ + --port 21935 \ + --log artifacts/track-c2-openviking/bounded-provider.jsonl \ + > artifacts/track-c2-openviking/bounded-provider.log 2>&1 & + echo $! > runtime/openviking/provider.pid + for i in $(seq 1 30); do + if curl --fail --silent http://127.0.0.1:21935/health > artifacts/track-c2-openviking/bounded-provider-health.json; then + exit 0 + fi + if ! kill -0 "$(cat runtime/openviking/provider.pid)" 2>/dev/null; then + cat artifacts/track-c2-openviking/bounded-provider.log + exit 1 + fi + sleep 1 + done + cat artifacts/track-c2-openviking/bounded-provider.log + exit 1 + + - name: Write bounded OpenViking server configuration + run: | + cat > runtime/openviking/ov.conf <<'JSON' + { + "embedding": { + "max_retries": 0, + "dense": { + "provider": "openai", + "model": "yukh-ov4-embedding", + "api_base": "http://127.0.0.1:21935/v1", + "api_key": "qualification-only", + "dimension": 4, + "input": "text" + } + }, + "vlm": { + "provider": "openai", + "model": "yukh-ov4-fixed", + "api_base": "http://127.0.0.1:21935/v1", + "api_key": "qualification-only", + "temperature": 0, + "max_retries": 0, + "thinking": false + }, + "query_planner": null, + "retrieval": { + "enable_intent": false + }, + "storage": { + "workspace": "./runtime/openviking/data", + "agfs": {"backend": "local"}, + "vectordb": {"backend": "local", "dimension": 4} + }, + "server": { + "host": "127.0.0.1", + "port": 21933, + "workers": 1, + "auth_mode": "dev" + }, + "memory": { + "extraction_enabled": true, + "session_skill_extraction_enabled": false, + "link_enabled": false + }, + "telemetry": {} + } + JSON + + - name: Start pinned OpenViking server for host A + env: + OPENVIKING_CONFIG_FILE: ${{ github.workspace }}/runtime/openviking/ov.conf + OPENAI_API_KEY: '' + ANTHROPIC_API_KEY: '' + VOLCENGINE_ACCESS_KEY: '' + VOLCENGINE_SECRET_KEY: '' + run: | + openviking-server --config "$OPENVIKING_CONFIG_FILE" > artifacts/track-c2-openviking/server-a.log 2>&1 & + echo $! > runtime/openviking/server.pid + for i in $(seq 1 60); do + if curl --fail --silent http://127.0.0.1:21933/health > artifacts/track-c2-openviking/health-a.json; then + exit 0 + fi + if ! kill -0 "$(cat runtime/openviking/server.pid)" 2>/dev/null; then + cat artifacts/track-c2-openviking/server-a.log + exit 1 + fi + sleep 1 + done + cat artifacts/track-c2-openviking/server-a.log + exit 1 + + - name: Execute OV-4 host A session commit and memory extraction + run: >- + python tests/qualification/track-c2/openviking/ov4-executable-memory.py + host-a + http://127.0.0.1:21933 + artifacts/track-c2-openviking/ov4-stage-a.json + + - name: Restart pinned OpenViking server on same storage + env: + OPENVIKING_CONFIG_FILE: ${{ github.workspace }}/runtime/openviking/ov.conf + OPENAI_API_KEY: '' + ANTHROPIC_API_KEY: '' + VOLCENGINE_ACCESS_KEY: '' + VOLCENGINE_SECRET_KEY: '' + run: | + kill "$(cat runtime/openviking/server.pid)" + for i in $(seq 1 30); do + if ! kill -0 "$(cat runtime/openviking/server.pid)" 2>/dev/null; then break; fi + sleep 1 + done + openviking-server --config "$OPENVIKING_CONFIG_FILE" > artifacts/track-c2-openviking/server-b.log 2>&1 & + echo $! > runtime/openviking/server.pid + for i in $(seq 1 60); do + if curl --fail --silent http://127.0.0.1:21933/health > artifacts/track-c2-openviking/health-b.json; then + exit 0 + fi + if ! kill -0 "$(cat runtime/openviking/server.pid)" 2>/dev/null; then + cat artifacts/track-c2-openviking/server-b.log + exit 1 + fi + sleep 1 + done + cat artifacts/track-c2-openviking/server-b.log + exit 1 + + - name: Execute OV-4 host B persistence read + run: >- + python tests/qualification/track-c2/openviking/ov4-executable-memory.py + host-b + http://127.0.0.1:21933 + artifacts/track-c2-openviking/ov4-stage-a.json + artifacts/track-c2-openviking/ov4-stage-b.json + + - name: Stop OpenViking for outage gate + run: | + kill "$(cat runtime/openviking/server.pid)" + for i in $(seq 1 30); do + if ! kill -0 "$(cat runtime/openviking/server.pid)" 2>/dev/null; then exit 0; fi + sleep 1 + done + exit 1 + + - name: Execute OV-4 outage correctness + run: >- + python tests/qualification/track-c2/openviking/ov4-executable-memory.py + outage + http://127.0.0.1:21933 + tests/qualification/track-c2/openviking/fixture/ov4-accepted-fact.json + artifacts/track-c2-openviking/ov4-outage.json + + - name: Finalize OV-4 executable evidence + run: >- + python tests/qualification/track-c2/openviking/ov4-executable-memory.py + finalize + artifacts/track-c2-openviking/ov4-stage-a.json + artifacts/track-c2-openviking/ov4-stage-b.json + artifacts/track-c2-openviking/ov4-outage.json + artifacts/track-c2-openviking/bounded-provider.jsonl + artifacts/track-c2-openviking/openviking-ov4-exec.json + + - name: Verify OV-4 executable evidence + run: >- + python tests/qualification/track-c2/openviking/verify-ov4-executable.py + artifacts/track-c2-openviking/openviking-ov4-exec.json + + - name: Stop bounded services + if: always() + run: | + if [ -f runtime/openviking/server.pid ]; then + kill "$(cat runtime/openviking/server.pid)" 2>/dev/null || true + fi + if [ -f runtime/openviking/provider.pid ]; then + kill "$(cat runtime/openviking/provider.pid)" 2>/dev/null || true + fi + + - name: Upload OV-4 executable evidence and logs + if: always() + uses: actions/upload-artifact@v6 + with: + name: track-c2-openviking-ov4-exec-234a2d9f + path: artifacts/track-c2-openviking/ + if-no-files-found: error + retention-days: 30 From 82e3d08efa0f3c9dac0399a985804dda8f55dd1c Mon Sep 17 00:00:00 2001 From: Daniele Favara Date: Tue, 25 Aug 2026 03:45:52 +0200 Subject: [PATCH 06/10] fix OV-4 canonical memory target resolution --- .../openviking/ov4-executable-memory.py | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/tests/qualification/track-c2/openviking/ov4-executable-memory.py b/tests/qualification/track-c2/openviking/ov4-executable-memory.py index 639ac60..828276f 100644 --- a/tests/qualification/track-c2/openviking/ov4-executable-memory.py +++ b/tests/qualification/track-c2/openviking/ov4-executable-memory.py @@ -36,10 +36,22 @@ def collect_uris(value): return list(dict.fromkeys(found)) -def find_memory(client: SyncHTTPClient): +def canonical_memory_root(session_info: dict) -> str: + session_uri = session_info.get("uri") if isinstance(session_info, dict) else None + if not isinstance(session_uri, str) or "/sessions/" not in session_uri: + raise AssertionError(f"session response lacks canonical user-scoped URI: {session_info!r}") + user_root = session_uri.split("/sessions/", 1)[0] + if not user_root.startswith("viking://user/"): + raise AssertionError(f"unexpected canonical user root derived from session: {user_root!r}") + return f"{user_root}/memories" + + +def find_memory(client: SyncHTTPClient, memory_root: str): + if "~/" in memory_root: + raise AssertionError(f"memory root must be canonical, got alias: {memory_root}") result = client.find( query="service transport HTTP JSON", - target_uri="viking://~/memories", + target_uri=memory_root, limit=10, options={"context_type": ["memory"], "read_content": True}, ) @@ -56,7 +68,7 @@ def find_memory(client: SyncHTTPClient): candidates.append((uri, content)) try: - tree = client.tree(uri="viking://~/memories") + tree = client.tree(uri=memory_root) except Exception: tree = [] for uri in collect_uris(tree): @@ -69,7 +81,7 @@ def find_memory(client: SyncHTTPClient): if REMEMBERED_TEXT in content or "service_transport" in uri: return uri, content, result candidates.append((uri, content)) - raise AssertionError(f"remembered memory not found; result={result!r}; candidates={candidates!r}") + raise AssertionError(f"remembered memory not found; root={memory_root!r}; result={result!r}; candidates={candidates!r}") def host_a(server_url: str, output: str) -> int: @@ -82,10 +94,11 @@ def host_a(server_url: str, output: str) -> int: "working_memory": {"enabled": False}, "memory_types": ["preferences"], } - client.create_session( + session_info = client.create_session( session_id=session_id, options={"memory_policy": memory_policy, "auto_commit_policy": None}, ) + memory_root = canonical_memory_root(session_info) session = client.session(session_id=session_id) session.add_message( role="user", @@ -106,12 +119,14 @@ def host_a(server_url: str, output: str) -> int: if not task or task.get("status") != "completed": raise AssertionError(f"session commit did not complete: {task!r}") - memory_uri, memory_content, find_result = find_memory(client) + memory_uri, memory_content, find_result = find_memory(client, memory_root) payload = { "stage": "host-a", "pid": os.getpid(), "candidate_revision": CANDIDATE_REVISION, "session_id": session_id, + "session_uri": session_info.get("uri"), + "memory_root": memory_root, "task_id": task_id, "task_status": task.get("status"), "memory_uri": memory_uri, @@ -119,7 +134,7 @@ def host_a(server_url: str, output: str) -> int: "memory_sha256": digest(memory_content), "remembered_claim_present": REMEMBERED_TEXT in memory_content, "find_total": find_result.get("total") if isinstance(find_result, dict) else None, - "public_seams": ["create_session", "add_message", "commit", "get_task", "find", "read"], + "public_seams": ["create_session", "add_message", "commit", "get_task", "find", "tree", "read"], } write_json(output, payload) client.close() @@ -189,6 +204,7 @@ def finalize(stage_a_path: str, stage_b_path: str, outage_path: str, provider_lo observations = { "host_processes_distinct": a["pid"] != b["pid"], "commit_completed": a["task_status"] == "completed", + "canonical_memory_root_used": a.get("memory_root", "").startswith("viking://user/") and "~/" not in a.get("memory_root", ""), "remembered_claim_persisted": a["remembered_claim_present"], "cross_host_reuse": b["same_memory_as_host_a"], "restart_persistence": b["same_memory_as_host_a"] and b["remembered_claim_present"], @@ -207,6 +223,7 @@ def finalize(stage_a_path: str, stage_b_path: str, outage_path: str, provider_lo for key in ( "host_processes_distinct", "commit_completed", + "canonical_memory_root_used", "remembered_claim_persisted", "cross_host_reuse", "restart_persistence", @@ -233,6 +250,7 @@ def finalize(stage_a_path: str, stage_b_path: str, outage_path: str, provider_lo "external_egress_basis": "all configured model/embedding endpoints are loopback; production provider credentials are blank", "host_isolation": "host A and host B are separate Python processes and fresh SyncHTTPClient lifetimes", "server_restart": "same local storage workspace reused across pinned OpenViking restart", + "memory_target_resolution": "canonical user namespace derived from public create_session response; no home alias or hard-coded user ID", }, "provider_memory": { "uri": a["memory_uri"], @@ -279,4 +297,4 @@ def main() -> int: if __name__ == "__main__": - raise SystemExit(main()) + raise SystemExit(main()) \ No newline at end of file From 8231984b5fc5d7cb2c7eea3eca780100a010ec5b Mon Sep 17 00:00:00 2001 From: Daniele Favara Date: Tue, 25 Aug 2026 12:21:14 +0200 Subject: [PATCH 07/10] make OV-4 outage shutdown deterministic --- .../qualify-track-c2-openviking-ov4-exec.yml | 37 ++++++++++++------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/.github/workflows/qualify-track-c2-openviking-ov4-exec.yml b/.github/workflows/qualify-track-c2-openviking-ov4-exec.yml index cee752c..4437431 100644 --- a/.github/workflows/qualify-track-c2-openviking-ov4-exec.yml +++ b/.github/workflows/qualify-track-c2-openviking-ov4-exec.yml @@ -136,13 +136,13 @@ jobs: VOLCENGINE_ACCESS_KEY: '' VOLCENGINE_SECRET_KEY: '' run: | - openviking-server --config "$OPENVIKING_CONFIG_FILE" > artifacts/track-c2-openviking/server-a.log 2>&1 & - echo $! > runtime/openviking/server.pid + setsid openviking-server --config "$OPENVIKING_CONFIG_FILE" > artifacts/track-c2-openviking/server-a.log 2>&1 & + echo $! > runtime/openviking/server.pgid for i in $(seq 1 60); do if curl --fail --silent http://127.0.0.1:21933/health > artifacts/track-c2-openviking/health-a.json; then exit 0 fi - if ! kill -0 "$(cat runtime/openviking/server.pid)" 2>/dev/null; then + if ! kill -0 "$(cat runtime/openviking/server.pgid)" 2>/dev/null; then cat artifacts/track-c2-openviking/server-a.log exit 1 fi @@ -166,18 +166,24 @@ jobs: VOLCENGINE_ACCESS_KEY: '' VOLCENGINE_SECRET_KEY: '' run: | - kill "$(cat runtime/openviking/server.pid)" + kill -- -"$(cat runtime/openviking/server.pgid)" 2>/dev/null || true for i in $(seq 1 30); do - if ! kill -0 "$(cat runtime/openviking/server.pid)" 2>/dev/null; then break; fi + if ! curl --fail --silent --max-time 1 http://127.0.0.1:21933/health >/dev/null 2>&1; then + break + fi sleep 1 done - openviking-server --config "$OPENVIKING_CONFIG_FILE" > artifacts/track-c2-openviking/server-b.log 2>&1 & - echo $! > runtime/openviking/server.pid + if curl --fail --silent --max-time 1 http://127.0.0.1:21933/health >/dev/null 2>&1; then + echo 'OpenViking health remained reachable after restart shutdown' >&2 + exit 1 + fi + setsid openviking-server --config "$OPENVIKING_CONFIG_FILE" > artifacts/track-c2-openviking/server-b.log 2>&1 & + echo $! > runtime/openviking/server.pgid for i in $(seq 1 60); do if curl --fail --silent http://127.0.0.1:21933/health > artifacts/track-c2-openviking/health-b.json; then exit 0 fi - if ! kill -0 "$(cat runtime/openviking/server.pid)" 2>/dev/null; then + if ! kill -0 "$(cat runtime/openviking/server.pgid)" 2>/dev/null; then cat artifacts/track-c2-openviking/server-b.log exit 1 fi @@ -196,11 +202,16 @@ jobs: - name: Stop OpenViking for outage gate run: | - kill "$(cat runtime/openviking/server.pid)" + kill -- -"$(cat runtime/openviking/server.pgid)" 2>/dev/null || true for i in $(seq 1 30); do - if ! kill -0 "$(cat runtime/openviking/server.pid)" 2>/dev/null; then exit 0; fi + if ! curl --fail --silent --max-time 1 http://127.0.0.1:21933/health >/dev/null 2>&1; then + printf '{"health_unreachable":true,"attempt":%s}\n' "$i" > artifacts/track-c2-openviking/outage-shutdown.json + exit 0 + fi sleep 1 done + printf '{"health_unreachable":false}\n' > artifacts/track-c2-openviking/outage-shutdown.json + echo 'OpenViking health remained reachable after process-group shutdown' >&2 exit 1 - name: Execute OV-4 outage correctness @@ -229,8 +240,8 @@ jobs: - name: Stop bounded services if: always() run: | - if [ -f runtime/openviking/server.pid ]; then - kill "$(cat runtime/openviking/server.pid)" 2>/dev/null || true + if [ -f runtime/openviking/server.pgid ]; then + kill -- -"$(cat runtime/openviking/server.pgid)" 2>/dev/null || true fi if [ -f runtime/openviking/provider.pid ]; then kill "$(cat runtime/openviking/provider.pid)" 2>/dev/null || true @@ -243,4 +254,4 @@ jobs: name: track-c2-openviking-ov4-exec-234a2d9f path: artifacts/track-c2-openviking/ if-no-files-found: error - retention-days: 30 + retention-days: 30 \ No newline at end of file From 694553741ee567b1e89202e0a34442472b2e88e5 Mon Sep 17 00:00:00 2001 From: Daniele Favara Date: Tue, 25 Aug 2026 21:04:23 +0200 Subject: [PATCH 08/10] fix OV-4 outage probe to require remote SDK call --- .../openviking/ov4-executable-memory.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/tests/qualification/track-c2/openviking/ov4-executable-memory.py b/tests/qualification/track-c2/openviking/ov4-executable-memory.py index 828276f..f39e61a 100644 --- a/tests/qualification/track-c2/openviking/ov4-executable-memory.py +++ b/tests/qualification/track-c2/openviking/ov4-executable-memory.py @@ -167,20 +167,30 @@ def outage(server_url: str, accepted_fact_path: str, output: str) -> int: accepted = json.loads(accepted_text) provider_unavailable = False error_class = None + client = None try: client = SyncHTTPClient(url=server_url, timeout=1.0) client.initialize() - client.health() - client.close() + # initialize() only constructs the HTTP client at this pin. list_sessions() + # performs a real public GET /api/v1/sessions and therefore proves remote + # provider availability instead of relying on local SDK observer state. + client.list_sessions() except Exception as exc: provider_unavailable = True error_class = type(exc).__name__ + finally: + if client is not None: + try: + client.close() + except Exception: + pass payload = { "stage": "provider-outage", "pid": os.getpid(), "candidate_revision": CANDIDATE_REVISION, "provider_unavailable": provider_unavailable, "provider_error_class": error_class, + "provider_probe": "public list_sessions GET /api/v1/sessions", "accepted_fact": accepted, "accepted_fact_sha256": digest(accepted_text), "accepted_fact_available_without_provider": accepted.get("value") == "gRPC/protobuf", @@ -271,6 +281,11 @@ def finalize(stage_a_path: str, stage_b_path: str, outage_path: str, provider_lo "request_paths": paths, }, "observations": observations, + "outage_evidence": { + "probe": o.get("provider_probe"), + "error_class": o.get("provider_error_class"), + "provider_unavailable": o.get("provider_unavailable"), + }, "result": "PASS" if passed else "FAIL", "result_scope": "OV-4 public memory creation, persistence/cross-host reuse, restart persistence, conflicting accepted fact separation, bounded inference path, and outage correctness.", "next_gate": "OV-5-visibility-revocation" if passed else None, From 679b738fbe2654028a26d713fb67e9969fa8340f Mon Sep 17 00:00:00 2001 From: Daniele Favara Date: Thu, 27 Aug 2026 23:59:03 +0200 Subject: [PATCH 09/10] tighten OV-4 model egress evidence claim --- .../openviking/ov4-executable-memory.py | 152 +++--------------- 1 file changed, 24 insertions(+), 128 deletions(-) diff --git a/tests/qualification/track-c2/openviking/ov4-executable-memory.py b/tests/qualification/track-c2/openviking/ov4-executable-memory.py index f39e61a..3d86355 100644 --- a/tests/qualification/track-c2/openviking/ov4-executable-memory.py +++ b/tests/qualification/track-c2/openviking/ov4-executable-memory.py @@ -49,12 +49,7 @@ def canonical_memory_root(session_info: dict) -> str: def find_memory(client: SyncHTTPClient, memory_root: str): if "~/" in memory_root: raise AssertionError(f"memory root must be canonical, got alias: {memory_root}") - result = client.find( - query="service transport HTTP JSON", - target_uri=memory_root, - limit=10, - options={"context_type": ["memory"], "read_content": True}, - ) + result = client.find(query="service transport HTTP JSON", target_uri=memory_root, limit=10, options={"context_type": ["memory"], "read_content": True}) candidates = [] for uri in collect_uris(result): if "/memories/" not in uri or uri.endswith(".overview.md") or uri.endswith(".abstract.md"): @@ -66,7 +61,6 @@ def find_memory(client: SyncHTTPClient, memory_root: str): if REMEMBERED_TEXT in content or "service_transport" in uri: return uri, content, result candidates.append((uri, content)) - try: tree = client.tree(uri=memory_root) except Exception: @@ -88,26 +82,12 @@ def host_a(server_url: str, output: str) -> int: client = SyncHTTPClient(url=server_url) client.initialize() session_id = "yukh-ov4-memory" - memory_policy = { - "self": {"enabled": True}, - "peer": {"enabled": False}, - "working_memory": {"enabled": False}, - "memory_types": ["preferences"], - } - session_info = client.create_session( - session_id=session_id, - options={"memory_policy": memory_policy, "auto_commit_policy": None}, - ) + memory_policy = {"self": {"enabled": True}, "peer": {"enabled": False}, "working_memory": {"enabled": False}, "memory_types": ["preferences"]} + session_info = client.create_session(session_id=session_id, options={"memory_policy": memory_policy, "auto_commit_policy": None}) memory_root = canonical_memory_root(session_info) session = client.session(session_id=session_id) - session.add_message( - role="user", - content="Remember this project preference: service transport is HTTP/JSON.", - ) - session.add_message( - role="assistant", - content="Recorded as contextual memory only.", - ) + session.add_message(role="user", content="Remember this project preference: service transport is HTTP/JSON.") + session.add_message(role="assistant", content="Recorded as contextual memory only.") commit_result = session.commit() task_id = commit_result["task_id"] task = None @@ -118,24 +98,8 @@ def host_a(server_url: str, output: str) -> int: time.sleep(0.25) if not task or task.get("status") != "completed": raise AssertionError(f"session commit did not complete: {task!r}") - memory_uri, memory_content, find_result = find_memory(client, memory_root) - payload = { - "stage": "host-a", - "pid": os.getpid(), - "candidate_revision": CANDIDATE_REVISION, - "session_id": session_id, - "session_uri": session_info.get("uri"), - "memory_root": memory_root, - "task_id": task_id, - "task_status": task.get("status"), - "memory_uri": memory_uri, - "memory_content": memory_content, - "memory_sha256": digest(memory_content), - "remembered_claim_present": REMEMBERED_TEXT in memory_content, - "find_total": find_result.get("total") if isinstance(find_result, dict) else None, - "public_seams": ["create_session", "add_message", "commit", "get_task", "find", "tree", "read"], - } + payload = {"stage": "host-a", "pid": os.getpid(), "candidate_revision": CANDIDATE_REVISION, "session_id": session_id, "session_uri": session_info.get("uri"), "memory_root": memory_root, "task_id": task_id, "task_status": task.get("status"), "memory_uri": memory_uri, "memory_content": memory_content, "memory_sha256": digest(memory_content), "remembered_claim_present": REMEMBERED_TEXT in memory_content, "find_total": find_result.get("total") if isinstance(find_result, dict) else None, "public_seams": ["create_session", "add_message", "commit", "get_task", "find", "tree", "read"]} write_json(output, payload) client.close() return 0 @@ -146,17 +110,7 @@ def host_b(server_url: str, stage_a_path: str, output: str) -> int: client = SyncHTTPClient(url=server_url) client.initialize() memory_content = client.read(uri=stage_a["memory_uri"]) - payload = { - "stage": "host-b-after-restart", - "pid": os.getpid(), - "candidate_revision": CANDIDATE_REVISION, - "memory_uri": stage_a["memory_uri"], - "memory_content": memory_content, - "memory_sha256": digest(memory_content), - "same_memory_as_host_a": digest(memory_content) == stage_a["memory_sha256"], - "remembered_claim_present": REMEMBERED_TEXT in memory_content, - "public_seams": ["initialize", "read"], - } + payload = {"stage": "host-b-after-restart", "pid": os.getpid(), "candidate_revision": CANDIDATE_REVISION, "memory_uri": stage_a["memory_uri"], "memory_content": memory_content, "memory_sha256": digest(memory_content), "same_memory_as_host_a": digest(memory_content) == stage_a["memory_sha256"], "remembered_claim_present": REMEMBERED_TEXT in memory_content, "public_seams": ["initialize", "read"]} write_json(output, payload) client.close() return 0 @@ -171,9 +125,6 @@ def outage(server_url: str, accepted_fact_path: str, output: str) -> int: try: client = SyncHTTPClient(url=server_url, timeout=1.0) client.initialize() - # initialize() only constructs the HTTP client at this pin. list_sessions() - # performs a real public GET /api/v1/sessions and therefore proves remote - # provider availability instead of relying on local SDK observer state. client.list_sessions() except Exception as exc: provider_unavailable = True @@ -184,17 +135,7 @@ def outage(server_url: str, accepted_fact_path: str, output: str) -> int: client.close() except Exception: pass - payload = { - "stage": "provider-outage", - "pid": os.getpid(), - "candidate_revision": CANDIDATE_REVISION, - "provider_unavailable": provider_unavailable, - "provider_error_class": error_class, - "provider_probe": "public list_sessions GET /api/v1/sessions", - "accepted_fact": accepted, - "accepted_fact_sha256": digest(accepted_text), - "accepted_fact_available_without_provider": accepted.get("value") == "gRPC/protobuf", - } + payload = {"stage": "provider-outage", "pid": os.getpid(), "candidate_revision": CANDIDATE_REVISION, "provider_unavailable": provider_unavailable, "provider_error_class": error_class, "provider_probe": "public list_sessions GET /api/v1/sessions", "accepted_fact": accepted, "accepted_fact_sha256": digest(accepted_text), "accepted_fact_available_without_provider": accepted.get("value") == "gRPC/protobuf"} write_json(output, payload) if not provider_unavailable: raise AssertionError("OpenViking unexpectedly remained available during outage gate") @@ -209,83 +150,38 @@ def finalize(stage_a_path: str, stage_b_path: str, outage_path: str, provider_lo paths = [entry.get("path", "") for entry in log_lines] chat_calls = sum(path.endswith("/chat/completions") for path in paths) embedding_calls = sum(path.endswith("/embeddings") for path in paths) - accepted = o["accepted_fact"] observations = { - "host_processes_distinct": a["pid"] != b["pid"], - "commit_completed": a["task_status"] == "completed", + "host_processes_distinct": a["pid"] != b["pid"], "commit_completed": a["task_status"] == "completed", "canonical_memory_root_used": a.get("memory_root", "").startswith("viking://user/") and "~/" not in a.get("memory_root", ""), - "remembered_claim_persisted": a["remembered_claim_present"], - "cross_host_reuse": b["same_memory_as_host_a"], + "remembered_claim_persisted": a["remembered_claim_present"], "cross_host_reuse": b["same_memory_as_host_a"], "restart_persistence": b["same_memory_as_host_a"] and b["remembered_claim_present"], "accepted_fact_conflicts_with_memory": accepted.get("value") == "gRPC/protobuf" and REMEMBERED_TEXT in a["memory_content"], - "memory_classification": "remembered", - "accepted_fact_classification": accepted.get("class"), - "memory_is_accepted_state": False, - "memory_is_evidence_truth": False, + "memory_classification": "remembered", "accepted_fact_classification": accepted.get("class"), + "memory_is_accepted_state": False, "memory_is_evidence_truth": False, "accepted_fact_remains_authoritative": accepted.get("authority") == "yukh-external-fixture", "outage_correctness": o["provider_unavailable"] and o["accepted_fact_available_without_provider"], - "bounded_vlm_calls": chat_calls >= 1, - "bounded_embedding_calls": embedding_calls >= 1, + "bounded_vlm_calls": chat_calls >= 1, "bounded_embedding_calls": embedding_calls >= 1, } - passed = all( - observations[key] - for key in ( - "host_processes_distinct", - "commit_completed", - "canonical_memory_root_used", - "remembered_claim_persisted", - "cross_host_reuse", - "restart_persistence", - "accepted_fact_conflicts_with_memory", - "accepted_fact_remains_authoritative", - "outage_correctness", - "bounded_vlm_calls", - "bounded_embedding_calls", - ) - ) and observations["memory_is_accepted_state"] is False and observations["memory_is_evidence_truth"] is False - + required = ("host_processes_distinct", "commit_completed", "canonical_memory_root_used", "remembered_claim_persisted", "cross_host_reuse", "restart_persistence", "accepted_fact_conflicts_with_memory", "accepted_fact_remains_authoritative", "outage_correctness", "bounded_vlm_calls", "bounded_embedding_calls") + passed = all(observations[key] for key in required) and observations["memory_is_accepted_state"] is False and observations["memory_is_evidence_truth"] is False report = { - "schema_version": 1, - "track": "C2", - "gate": "OV-4-executable-memory-profile", - "candidate": "volcengine/OpenViking", - "revision": CANDIDATE_REVISION, + "schema_version": 1, "track": "C2", "gate": "OV-4-executable-memory-profile", "candidate": "volcengine/OpenViking", "revision": CANDIDATE_REVISION, "profile": { - "public_surface": "openviking-sdk HTTP", - "auth_mode": "dev", + "public_surface": "openviking-sdk HTTP", "auth_mode": "dev", "model_path": "documented OpenAI-compatible VLM + embedding endpoints", "model_endpoint": "loopback-only 127.0.0.1:21935/v1", - "external_egress_observed": False, - "external_egress_basis": "all configured model/embedding endpoints are loopback; production provider credentials are blank", + "external_model_egress_configured": False, + "external_model_egress_basis": "all configured VLM/embedding endpoints are loopback and production provider credentials are blank; general process egress was not instrumented or observed", "host_isolation": "host A and host B are separate Python processes and fresh SyncHTTPClient lifetimes", "server_restart": "same local storage workspace reused across pinned OpenViking restart", "memory_target_resolution": "canonical user namespace derived from public create_session response; no home alias or hard-coded user ID", }, - "provider_memory": { - "uri": a["memory_uri"], - "sha256": a["memory_sha256"], - "classification": "remembered", - "claim": "service transport is HTTP/JSON", - }, - "accepted_fact": { - "fact_id": accepted.get("fact_id"), - "value": accepted.get("value"), - "class": accepted.get("class"), - "authority": accepted.get("authority"), - "sha256": o["accepted_fact_sha256"], - }, - "model_traffic": { - "chat_completion_calls": chat_calls, - "embedding_calls": embedding_calls, - "request_paths": paths, - }, + "provider_memory": {"uri": a["memory_uri"], "sha256": a["memory_sha256"], "classification": "remembered", "claim": "service transport is HTTP/JSON"}, + "accepted_fact": {"fact_id": accepted.get("fact_id"), "value": accepted.get("value"), "class": accepted.get("class"), "authority": accepted.get("authority"), "sha256": o["accepted_fact_sha256"]}, + "model_traffic": {"chat_completion_calls": chat_calls, "embedding_calls": embedding_calls, "request_paths": paths}, "observations": observations, - "outage_evidence": { - "probe": o.get("provider_probe"), - "error_class": o.get("provider_error_class"), - "provider_unavailable": o.get("provider_unavailable"), - }, + "outage_evidence": {"probe": o.get("provider_probe"), "error_class": o.get("provider_error_class"), "provider_unavailable": o.get("provider_unavailable")}, "result": "PASS" if passed else "FAIL", "result_scope": "OV-4 public memory creation, persistence/cross-host reuse, restart persistence, conflicting accepted fact separation, bounded inference path, and outage correctness.", "next_gate": "OV-5-visibility-revocation" if passed else None, @@ -312,4 +208,4 @@ def main() -> int: if __name__ == "__main__": - raise SystemExit(main()) \ No newline at end of file + raise SystemExit(main()) From 9bfa7de107fdb178f099b51c588d2e531385e7fd Mon Sep 17 00:00:00 2001 From: Daniele Favara Date: Thu, 27 Aug 2026 23:59:19 +0200 Subject: [PATCH 10/10] verify precise OV-4 model egress evidence --- .../openviking/verify-ov4-executable.py | 45 +++++-------------- 1 file changed, 11 insertions(+), 34 deletions(-) diff --git a/tests/qualification/track-c2/openviking/verify-ov4-executable.py b/tests/qualification/track-c2/openviking/verify-ov4-executable.py index 2c6367a..d3d995e 100644 --- a/tests/qualification/track-c2/openviking/verify-ov4-executable.py +++ b/tests/qualification/track-c2/openviking/verify-ov4-executable.py @@ -12,55 +12,32 @@ assert r["candidate"] == "volcengine/OpenViking" assert r["revision"] == "234a2d9fe778a9512fd7ebe9807198e847c647ec" assert r["result"] == "PASS" - profile = r["profile"] assert profile["public_surface"] == "openviking-sdk HTTP" assert profile["auth_mode"] == "dev" assert profile["model_path"] == "documented OpenAI-compatible VLM + embedding endpoints" assert "127.0.0.1:21935" in profile["model_endpoint"] -assert profile["external_egress_observed"] is False +assert profile["external_model_egress_configured"] is False +assert "loopback" in profile["external_model_egress_basis"] +assert "general process egress was not instrumented or observed" in profile["external_model_egress_basis"] +assert "external_egress_observed" not in profile assert "separate Python processes" in profile["host_isolation"] assert "same local storage workspace" in profile["server_restart"] - memory = r["provider_memory"] -assert memory["uri"].startswith("viking://") -assert "/memories/" in memory["uri"] -assert memory["classification"] == "remembered" -assert "HTTP/JSON" in memory["claim"] -assert len(memory["sha256"]) == 64 - +assert memory["uri"].startswith("viking://") and "/memories/" in memory["uri"] +assert memory["classification"] == "remembered" and "HTTP/JSON" in memory["claim"] and len(memory["sha256"]) == 64 accepted = r["accepted_fact"] -assert accepted["fact_id"] == "service-transport" -assert accepted["value"] == "gRPC/protobuf" -assert accepted["class"] == "accepted" -assert accepted["authority"] == "yukh-external-fixture" -assert len(accepted["sha256"]) == 64 - +assert accepted["fact_id"] == "service-transport" and accepted["value"] == "gRPC/protobuf" +assert accepted["class"] == "accepted" and accepted["authority"] == "yukh-external-fixture" and len(accepted["sha256"]) == 64 traffic = r["model_traffic"] -assert traffic["chat_completion_calls"] >= 1 -assert traffic["embedding_calls"] >= 1 -assert traffic["request_paths"] +assert traffic["chat_completion_calls"] >= 1 and traffic["embedding_calls"] >= 1 and traffic["request_paths"] for path in traffic["request_paths"]: assert path == "/health" or path.startswith("/v1/") - obs = r["observations"] -for key in ( - "host_processes_distinct", - "commit_completed", - "remembered_claim_persisted", - "cross_host_reuse", - "restart_persistence", - "accepted_fact_conflicts_with_memory", - "accepted_fact_remains_authoritative", - "outage_correctness", - "bounded_vlm_calls", - "bounded_embedding_calls", -): +for key in ("host_processes_distinct", "commit_completed", "canonical_memory_root_used", "remembered_claim_persisted", "cross_host_reuse", "restart_persistence", "accepted_fact_conflicts_with_memory", "accepted_fact_remains_authoritative", "outage_correctness", "bounded_vlm_calls", "bounded_embedding_calls"): assert obs[key] is True, key assert obs["memory_classification"] == "remembered" assert obs["accepted_fact_classification"] == "accepted" -assert obs["memory_is_accepted_state"] is False -assert obs["memory_is_evidence_truth"] is False +assert obs["memory_is_accepted_state"] is False and obs["memory_is_evidence_truth"] is False assert r["next_gate"] == "OV-5-visibility-revocation" - print("verified OpenViking OV-4 executable memory profile: PASS")