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..4437431 --- /dev/null +++ b/.github/workflows/qualify-track-c2-openviking-ov4-exec.yml @@ -0,0 +1,257 @@ +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: | + 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.pgid)" 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.pgid)" 2>/dev/null || true + for i in $(seq 1 30); do + if ! curl --fail --silent --max-time 1 http://127.0.0.1:21933/health >/dev/null 2>&1; then + break + fi + sleep 1 + done + 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.pgid)" 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.pgid)" 2>/dev/null || true + for i in $(seq 1 30); do + 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 + 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.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 + 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 \ No newline at end of file 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" +} 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..3d86355 --- /dev/null +++ b/tests/qualification/track-c2/openviking/ov4-executable-memory.py @@ -0,0 +1,211 @@ +#!/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 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=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"): + 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=memory_root) + 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; root={memory_root!r}; 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"]} + 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.") + 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, 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"]} + 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 + client = None + try: + client = SyncHTTPClient(url=server_url, timeout=1.0) + client.initialize() + 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"} + 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", + "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"], + "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, + } + 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, + "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_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}, + "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, + } + 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()) 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()) 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..d3d995e --- /dev/null +++ b/tests/qualification/track-c2/openviking/verify-ov4-executable.py @@ -0,0 +1,43 @@ +#!/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_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://") 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" 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 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", "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 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")