This is an automated email from the ASF dual-hosted git repository.

zyxxoo pushed a commit to branch refactor/rust-rewrite-design
in repository https://gitbox.apache.org/repos/asf/hugegraph.git


The following commit(s) were added to refs/heads/refactor/rust-rewrite-design 
by this push:
     new b32967d03 test(rust): add Java Rust contract differential oracle
b32967d03 is described below

commit b32967d0394479b3177796a0dccc69fff11136b0
Author: vaughn <[email protected]>
AuthorDate: Sun Sep 13 17:11:23 2026 +0800

    test(rust): add Java Rust contract differential oracle
---
 tools/raft-linearizability/README.md         |  9 +++++++
 tools/raft-linearizability/compare_traces.py | 38 ++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+)

diff --git a/tools/raft-linearizability/README.md 
b/tools/raft-linearizability/README.md
index 07b834afa..3ea5c4714 100644
--- a/tools/raft-linearizability/README.md
+++ b/tools/raft-linearizability/README.md
@@ -26,3 +26,12 @@ For HugeGraph capture, map a committed vertex mutation to 
`write` and a vertex
 lookup to `read`, using the canonical vertex identifier as the register key.
 Record HTTP send/receive monotonic times plus status and body hash in metadata;
 the checker evaluates ordering and values only.
+
+## Java/Rust contract replay
+
+`compare_traces.py` is a dependency-free differential oracle. Give it Java and 
Rust replay traces (arrays or `{ "operations": [...] }`). It compares only 
`op`, `key`, `value`, and `result`, ignoring timestamps and implementation 
metadata.
+
+```bash
+python3 tools/raft-linearizability/compare_traces.py java.json rust.json
+```
+Exit 0 means normalized traces are identical; exit 1 reports divergence.
diff --git a/tools/raft-linearizability/compare_traces.py 
b/tools/raft-linearizability/compare_traces.py
new file mode 100644
index 000000000..3ff78585a
--- /dev/null
+++ b/tools/raft-linearizability/compare_traces.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python3
+"""Compare Java and Rust replay traces using a stable, independent oracle.
+
+Each input is a JSON array (or an object containing ``operations``).  Records
+are compared after selecting the contract fields ``op``, ``key``, ``value``
+and ``result``; transport timestamps and implementation metadata are ignored.
+"""
+import argparse, json, sys
+
+FIELDS = ("op", "key", "value", "result")
+
+def load(path):
+    with open(path, encoding="utf-8") as f:
+        data = json.load(f)
+    if isinstance(data, dict):
+        data = data.get("operations")
+    if not isinstance(data, list):
+        raise ValueError("trace must be an array or {operations: array}")
+    return [{k: row.get(k) for k in FIELDS} for row in data]
+
+def main():
+    ap = argparse.ArgumentParser()
+    ap.add_argument("java_trace"); ap.add_argument("rust_trace")
+    args = ap.parse_args()
+    try:
+        java, rust = load(args.java_trace), load(args.rust_trace)
+    except (OSError, ValueError, json.JSONDecodeError, AttributeError) as e:
+        print(json.dumps({"equal": False, "error": str(e)})); return 2
+    equal = java == rust
+    out = {"equal": equal, "java_count": len(java), "rust_count": len(rust)}
+    if not equal:
+        out["first_difference"] = next(({"index": i, "java": j, "rust": r}
+            for i, (j, r) in enumerate(zip(java, rust)) if j != r), None)
+    print(json.dumps(out, sort_keys=True))
+    return 0 if equal else 1
+
+if __name__ == "__main__":
+    sys.exit(main())

Reply via email to