From f5f47d20e080afac2edaea7cb83cccf16cb3a804 Mon Sep 17 00:00:00 2001 From: AdaWorldAPI Date: Sun, 18 Oct 2026 18:44:44 +0200 Subject: [PATCH 1/9] test(research): add manually bound C-01/C-02 ring gold --- .../research/semantic-ring-bound-gold-v1.json | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 docs/research/semantic-ring-bound-gold-v1.json diff --git a/docs/research/semantic-ring-bound-gold-v1.json b/docs/research/semantic-ring-bound-gold-v1.json new file mode 100644 index 000000000..461c2761c --- /dev/null +++ b/docs/research/semantic-ring-bound-gold-v1.json @@ -0,0 +1,50 @@ +{ + "format": "lance-graph-semantic-ring-bound-gold/v1", + "status": "manual-independent-oracle-input-not-parser-output", + "scope": "C-01/C-02 only; four source-bound relations, with distinct first and last keys", + "sentences": [ + "That key opens a door.", + "That door hides a garden.", + "That garden shelters a fox.", + "That fox carries a key." + ], + "facts": [ + { + "sentence_index": 0, + "subject": "first_sentence.key", + "predicate": "opens", + "object": "door" + }, + { + "sentence_index": 1, + "subject": "door", + "predicate": "hides", + "object": "garden" + }, + { + "sentence_index": 2, + "subject": "garden", + "predicate": "shelters", + "object": "fox" + }, + { + "sentence_index": 3, + "subject": "fox", + "predicate": "carries", + "object": "last_sentence.key" + } + ], + "attested_identity": [ + { + "lhs": "last_sentence.key", + "rhs": "first_sentence.key", + "root": "independent_coref_witness_1" + } + ], + "caveats": [ + "Symbolic bindings are manually authored semantic gold, not DeepNSM-v2 output.", + "The attestation is a synthetic test fixture, not empirical certification.", + "Only an explicitly activated, exact attestation may unify the two key referents.", + "No NodeGuid minting, physical join, Datalog fixpoint, or CE64 truth promotion is performed." + ] +} From 7df4c0376acd3254df59721ddd2371c4caca4d77 Mon Sep 17 00:00:00 2001 From: AdaWorldAPI Date: Sun, 18 Oct 2026 18:44:46 +0200 Subject: [PATCH 2/9] docs: scope the semantic ring oracle and integration gate --- tools/semantic_ring_oracle/README.md | 36 ++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 tools/semantic_ring_oracle/README.md diff --git a/tools/semantic_ring_oracle/README.md b/tools/semantic_ring_oracle/README.md new file mode 100644 index 000000000..01ab3e9d6 --- /dev/null +++ b/tools/semantic_ring_oracle/README.md @@ -0,0 +1,36 @@ +# C-01/C-02 semantic ring reference oracle + +**Scope: test-only independent oracle, not the Rust semantic candidate runtime.** + +The pre-registered C-01 and C-02 fixtures in +`docs/research/versioned-semantic-candidates-fixtures.json` make a strong +claim: rotating a four-sentence ring does not change its justified canonical +relations, but the ring must **not close** unless the last indefinite key is +identified with the first by an explicit, independent witness. + +`docs/research/semantic-ring-bound-gold-v1.json` adds manually annotated +subject/predicate/object bindings. The first and last key remain **different +identities**. The fixture's synthetic attestation can be activated only when +its exact root and endpoints match the registered gold record. Grammar +parsing, NodeGuid/codebook minting and witness verification against a real +source are deliberately **out of scope**. This avoids treating the English +word `key` as a foreign-key join or inventing coreference. + +```sh +python3 tools/semantic_ring_oracle/ring_reference.py +python3 -m unittest discover -s tools/semantic_ring_oracle -p 'test_*.py' -v +``` + +The oracle does not read `case.expected` during evaluation. It checks four +rotations, negative closure, spoofed/misdirected witnesses, missing claims, +duplicate sentence bindings, and a changed predicate that preserves +unlabeled graph topology while changing the semantic claim set. + +**Next integration gate:** have a real DeepNSM/UD binder emit version-pinned +canonical bound relations (or an explicit `Unbound`) with source-root receipts; +compare its output and downstream R2IL/Quack selection against this reference. +A test passing here certifies only the reference fixtures, **not** parsing, +coreference accuracy, semantic alignment, actual independent evidence, a +foreign-address join, or production C-01/C-02 behavior. Do not import the +Python oracle into a production execution path or lower semantic equality to +an unverified mask AND. From 9e97438d6fef292201ecb37b920a18b2819db212 Mon Sep 17 00:00:00 2001 From: AdaWorldAPI Date: Sun, 18 Oct 2026 18:45:13 +0200 Subject: [PATCH 3/9] test: execute independent symbolic ring reference over C-01 C-02 --- tools/semantic_ring_oracle/ring_reference.py | 124 +++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 tools/semantic_ring_oracle/ring_reference.py diff --git a/tools/semantic_ring_oracle/ring_reference.py b/tools/semantic_ring_oracle/ring_reference.py new file mode 100644 index 000000000..b87bdab57 --- /dev/null +++ b/tools/semantic_ring_oracle/ring_reference.py @@ -0,0 +1,124 @@ +"""Independent symbolic C-01/C-02 reference, never a production graph evaluator. + +The binding gold is manually supplied. This module does NOT parse English, +allocate NodeGuids, lower R2IL, or infer the identity of two indefinite keys. +""" + +from __future__ import annotations + +import json +from pathlib import Path +from typing import Any + +ROOT = Path(__file__).resolve().parents[2] +FIXTURES = ROOT / "docs/research/versioned-semantic-candidates-fixtures.json" +GOLD = ROOT / "docs/research/semantic-ring-bound-gold-v1.json" + + +def load_case(case_id: str) -> dict[str, Any]: + fixtures = json.loads(FIXTURES.read_text(encoding="utf-8")) + if fixtures["format"] != "lance-graph-versioned-semantic-candidates/fixtures-v1": + raise ValueError("unexpected fixture version") + matches = [c for c in fixtures["cases"] if c["id"] == case_id] + if len(matches) != 1: + raise ValueError(f"expected one fixture for {case_id}") + return matches[0] + + +def load_gold() -> dict[str, Any]: + gold = json.loads(GOLD.read_text(encoding="utf-8")) + if gold["format"] != "lance-graph-semantic-ring-bound-gold/v1": + raise ValueError("unexpected gold version") + return gold + + +def evaluate( + case: dict[str, Any], + gold: dict[str, Any], + entry_order: list[int], + *, + facts: list[dict[str, Any]] | None = None, +) -> dict[str, Any]: + """Test-only oracle for symbolic bound relations and activated identity. + + It intentionally never consults case['expected']. A result is eligible for + comparison with an implementation only when an independent binder produces + its own claim IDs and relations under an explicit, compatible frame. + """ + if case["id"] not in ("C-01", "C-02"): + raise ValueError("this oracle covers only C-01 and C-02") + source = case["input"] + if source["sentences"] != gold["sentences"]: + raise ValueError("sentence/gold binding drift") + if entry_order not in source["entry_orders"] or sorted(entry_order) != list(range(4)): + raise ValueError("unregistered or incomplete rotation") + atoms = list(gold["facts"] if facts is None else facts) + if len({a["sentence_index"] for a in atoms}) != len(atoms): + raise ValueError("multiple atoms per sentence exceed this narrow oracle") + if any(a["sentence_index"] not in range(4) for a in atoms): + raise ValueError("unbound source sentence") + selected = sorted(atoms, key=lambda a: entry_order.index(a["sentence_index"])) + + witness = source["external_identity_witness"] + roots: tuple[str, ...] = () + redirects: dict[str, str] = {} + if witness is not None: + if witness not in gold["attested_identity"]: + raise ValueError("unattested identity witness") + if not all(witness.get(k) for k in ("lhs", "rhs", "root")): + raise ValueError("incomplete identity witness") + # Only the exact gold attestation licenses the substitution. Neither + # lexical similarity nor thought-popcount licenses any other union. + redirects[witness["lhs"]] = witness["rhs"] + roots = (witness["root"],) + + def canonical(term: str) -> str: + while term in redirects: + term = redirects[term] + return term + + relations = tuple( + sorted((canonical(a["subject"]), a["predicate"], canonical(a["object"])) + for a in selected) + ) + # Reference traversal: require four distinct, source-bound arcs and a + # complete return to the first key, not just a four-row presence count. + adjacency: dict[str, list[tuple[str, int]]] = {} + for a in selected: + adjacency.setdefault(canonical(a["subject"]), []).append( + (canonical(a["object"]), a["sentence_index"]) + ) + current = canonical("first_sentence.key") + visited: set[int] = set() + for _ in range(4): + options = [edge for edge in adjacency.get(current, []) if edge[1] not in visited] + if len(options) != 1: + break + current, source_index = options[0] + visited.add(source_index) + closed = len(visited) == 4 and current == canonical("first_sentence.key") + return { + "cycle_closed": closed, + "coreference_status": "WitnessedInFixture" if roots else "Unresolved", + "relations": relations, + "witness_roots": roots, + "source_sentence_indices": tuple(sorted(visited)), + } + + +def main() -> None: + gold = load_gold() + for case_id in ("C-01", "C-02"): + case = load_case(case_id) + results = [evaluate(case, gold, order) for order in case["input"]["entry_orders"]] + if not all(x == results[0] for x in results): + raise SystemExit(f"{case_id}: rotation changed the canonical answer") + if results[0]["cycle_closed"] != case["expected"]["cycle_closed"]: + raise SystemExit(f"{case_id}: reference mismatched preregistered expected closure") + print(f"{case_id}: rotations={len(results)}, closed={results[0]['cycle_closed']}, " + f"coreference={results[0]['coreference_status']}, roots={results[0]['witness_roots']}") + print("Reference oracle only: no production parser or execution path was tested.") + + +if __name__ == "__main__": + main() From 8aa5e92802184a1a45071f020ee8094baa44f3f1 Mon Sep 17 00:00:00 2001 From: AdaWorldAPI Date: Sun, 18 Oct 2026 18:45:33 +0200 Subject: [PATCH 4/9] test: add 11 adversarial ring oracle cases and mutations --- .../test_ring_reference.py | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 tools/semantic_ring_oracle/test_ring_reference.py diff --git a/tools/semantic_ring_oracle/test_ring_reference.py b/tools/semantic_ring_oracle/test_ring_reference.py new file mode 100644 index 000000000..ffcf19dcb --- /dev/null +++ b/tools/semantic_ring_oracle/test_ring_reference.py @@ -0,0 +1,88 @@ +"""C-01/C-02 falsifiers, including silence and mutation controls.""" + +import copy +import unittest + +from ring_reference import evaluate, load_case, load_gold + + +class RingReferenceTests(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.gold = load_gold() + cls.positive = load_case("C-01") + cls.negative = load_case("C-02") + + def run_case(self, case, **kw): + return evaluate(case, self.gold, case["input"]["entry_orders"][0], **kw) + + def test_witnessed_closure_is_rotation_invariant(self): + readings = [evaluate(self.positive, self.gold, order) + for order in self.positive["input"]["entry_orders"]] + self.assertTrue(all(x == readings[0] for x in readings)) + self.assertTrue(readings[0]["cycle_closed"]) + self.assertEqual(readings[0]["witness_roots"], ("independent_coref_witness_1",)) + self.assertEqual(len(readings[0]["relations"]), 4) + + def test_unwitnessed_ring_remains_open_under_every_rotation(self): + for order in self.negative["input"]["entry_orders"]: + with self.subTest(order=order): + result = evaluate(self.negative, self.gold, order) + self.assertFalse(result["cycle_closed"]) + self.assertEqual(result["coreference_status"], "Unresolved") + self.assertEqual(result["witness_roots"], ()) + self.assertEqual(len(result["relations"]), 4) + + def test_inactive_attestation_is_not_implicit(self): + candidate = copy.deepcopy(self.positive) + candidate["input"]["external_identity_witness"] = None + self.assertFalse(self.run_case(candidate)["cycle_closed"]) + + def test_spoofed_root_does_not_close_cycle(self): + candidate = copy.deepcopy(self.positive) + candidate["input"]["external_identity_witness"]["root"] = "copied_fake_witness" + with self.assertRaisesRegex(ValueError, "unattested"): + self.run_case(candidate) + + def test_wrong_identity_endpoints_are_refused(self): + candidate = copy.deepcopy(self.positive) + candidate["input"]["external_identity_witness"]["rhs"] = "door" + with self.assertRaisesRegex(ValueError, "unattested"): + self.run_case(candidate) + + def test_missing_last_claim_breaks_cycle_even_with_witness(self): + truncated = copy.deepcopy(self.gold["facts"][:-1]) + self.assertFalse(self.run_case(self.positive, facts=truncated)["cycle_closed"]) + + def test_changed_predicate_changes_semantics_not_only_topology(self): + baseline = self.run_case(self.positive) + altered = copy.deepcopy(self.gold["facts"]) + altered[-1]["predicate"] = "destroys" + mutant = self.run_case(self.positive, facts=altered) + self.assertTrue(mutant["cycle_closed"], "unlabeled geometry still cycles") + self.assertNotEqual(mutant["relations"], baseline["relations"], + "different predicates cannot retain claim identity") + + def test_different_last_referent_does_not_close_with_unrelated_witness(self): + changed = copy.deepcopy(self.gold["facts"]) + changed[-1]["object"] = "another.key" + self.assertFalse(self.run_case(self.positive, facts=changed)["cycle_closed"]) + + def test_duplicate_source_binding_refused(self): + doubled = copy.deepcopy(self.gold["facts"]) + doubled[1]["sentence_index"] = 0 + with self.assertRaisesRegex(ValueError, "multiple atoms"): + self.run_case(self.positive, facts=doubled) + + def test_unregistered_rotation_refused(self): + with self.assertRaisesRegex(ValueError, "unregistered"): + evaluate(self.positive, self.gold, [3, 2, 1, 0]) + + def test_fixture_expected_fields_do_not_drive_oracle(self): + candidate = copy.deepcopy(self.negative) + candidate["expected"]["cycle_closed"] = True + self.assertFalse(self.run_case(candidate)["cycle_closed"]) + + +if __name__ == "__main__": + unittest.main() From d5320009bf2938991a3b65bd33ce83f507d5e4e3 Mon Sep 17 00:00:00 2001 From: AdaWorldAPI Date: Sun, 18 Oct 2026 18:46:14 +0200 Subject: [PATCH 5/9] ci: run C-01/C-02 reference and mutation tests on changes --- .github/workflows/semantic-ring-oracle.yml | 33 ++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 .github/workflows/semantic-ring-oracle.yml diff --git a/.github/workflows/semantic-ring-oracle.yml b/.github/workflows/semantic-ring-oracle.yml new file mode 100644 index 000000000..51271d3f4 --- /dev/null +++ b/.github/workflows/semantic-ring-oracle.yml @@ -0,0 +1,33 @@ +name: Semantic ring reference oracle + +on: + pull_request: + paths: + - '.github/workflows/semantic-ring-oracle.yml' + - 'docs/research/versioned-semantic-candidates-fixtures.json' + - 'docs/research/semantic-ring-bound-gold-v1.json' + - 'tools/semantic_ring_oracle/**' + push: + branches: [main] + paths: + - '.github/workflows/semantic-ring-oracle.yml' + - 'docs/research/versioned-semantic-candidates-fixtures.json' + - 'docs/research/semantic-ring-bound-gold-v1.json' + - 'tools/semantic_ring_oracle/**' + +permissions: + contents: read + +jobs: + reference-oracle: + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + - name: Assert C-01/C-02 and negative controls + run: | + python3 tools/semantic_ring_oracle/ring_reference.py + python3 -m unittest discover -s tools/semantic_ring_oracle -p 'test_*.py' -v From 08183ff2805fadff3ef815aa9c5024a7c01ce664 Mon Sep 17 00:00:00 2001 From: AdaWorldAPI Date: Sun, 18 Oct 2026 19:01:20 +0200 Subject: [PATCH 6/9] test: make claim address plus sealed version the ring witness --- .../research/semantic-ring-bound-gold-v1.json | 38 +++++++++++++++---- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/docs/research/semantic-ring-bound-gold-v1.json b/docs/research/semantic-ring-bound-gold-v1.json index 461c2761c..9d08e8847 100644 --- a/docs/research/semantic-ring-bound-gold-v1.json +++ b/docs/research/semantic-ring-bound-gold-v1.json @@ -1,7 +1,7 @@ { - "format": "lance-graph-semantic-ring-bound-gold/v1", - "status": "manual-independent-oracle-input-not-parser-output", - "scope": "C-01/C-02 only; four source-bound relations, with distinct first and last keys", + "format": "lance-graph-semantic-ring-bound-gold/v2", + "status": "manually-bound-symbolic-test-gold-not-production-parser-output", + "scope": "C-01/C-02: identities remain stable; a sealed version witnesses an identity assertion at its claim address", "sentences": [ "That key opens a door.", "That door hides a garden.", @@ -34,17 +34,39 @@ "object": "last_sentence.key" } ], + "read_heads": { + "C-01": { + "dataset": "symbolic-ring", + "branch": "main", + "version": 17 + }, + "C-02": { + "dataset": "symbolic-ring", + "branch": "main", + "version": 16 + } + }, "attested_identity": [ { "lhs": "last_sentence.key", "rhs": "first_sentence.key", - "root": "independent_coref_witness_1" + "claim_address": "corefers(last_sentence.key,first_sentence.key)", + "sealed_in": { + "dataset": "symbolic-ring", + "branch": "main", + "version": 17 + }, + "source_roots": [ + "independent_coref_witness_1" + ] } ], "caveats": [ - "Symbolic bindings are manually authored semantic gold, not DeepNSM-v2 output.", - "The attestation is a synthetic test fixture, not empirical certification.", - "Only an explicitly activated, exact attestation may unify the two key referents.", - "No NodeGuid minting, physical join, Datalog fixpoint, or CE64 truth promotion is performed." + "Identifiers here are fixed manually authored symbolic claim/referent coordinates, not runtime-minted NodeGuids.", + "The version of a claim at its thought address is its historical witness; no separate witness entity or foreign-key lookup is created.", + "The source root is separately retained in the version receipt for evidential independence. Neither the thought slot nor the version number by itself proves that sources are independent.", + "An attestation being present in a version witnesses the assertion in the test history; it does not establish externally observed coreference truth.", + "Read horizons use dataset + branch + version, never a naked version or latest/unbounded temporal default.", + "No production R2IL relation join, CE64 truth promotion, actual Lance manifest or real-world source attestation is claimed." ] } From 686a842bb5c0517be6826a1f1168c735570c42e5 Mon Sep 17 00:00:00 2001 From: AdaWorldAPI Date: Sun, 18 Oct 2026 19:01:51 +0200 Subject: [PATCH 7/9] test: resolve semantic identity assertions by thought address and pinned version --- tools/semantic_ring_oracle/ring_reference.py | 98 +++++++++++++------- 1 file changed, 63 insertions(+), 35 deletions(-) diff --git a/tools/semantic_ring_oracle/ring_reference.py b/tools/semantic_ring_oracle/ring_reference.py index b87bdab57..983243b88 100644 --- a/tools/semantic_ring_oracle/ring_reference.py +++ b/tools/semantic_ring_oracle/ring_reference.py @@ -1,7 +1,9 @@ """Independent symbolic C-01/C-02 reference, never a production graph evaluator. -The binding gold is manually supplied. This module does NOT parse English, -allocate NodeGuids, lower R2IL, or infer the identity of two indefinite keys. +Identity is the fixed coordinate. A sealed version witnesses that the +coreference claim was recorded at that coordinate. Source roots remain a +separate evidential property of the version receipt, not another ID. +This harness does NOT parse language, mint NodeGuids, or execute R2IL. """ from __future__ import annotations @@ -27,31 +29,46 @@ def load_case(case_id: str) -> dict[str, Any]: def load_gold() -> dict[str, Any]: gold = json.loads(GOLD.read_text(encoding="utf-8")) - if gold["format"] != "lance-graph-semantic-ring-bound-gold/v1": + if gold["format"] != "lance-graph-semantic-ring-bound-gold/v2": raise ValueError("unexpected gold version") return gold +def _validated_ref(ref: dict[str, Any]) -> tuple[str, str, int]: + if not isinstance(ref, dict) or set(ref) != {"dataset", "branch", "version"}: + raise ValueError("read reference must pin dataset, branch and version") + dataset, branch, version = ref["dataset"], ref["branch"], ref["version"] + if not isinstance(dataset, str) or not dataset or not isinstance(branch, str) or not branch: + raise ValueError("read reference has unbound dataset/branch") + if type(version) is not int or version < 0: + raise ValueError("read reference version must be an explicit nonnegative integer") + return dataset, branch, version + + def evaluate( case: dict[str, Any], gold: dict[str, Any], entry_order: list[int], *, facts: list[dict[str, Any]] | None = None, + read_ref: dict[str, Any] | None = None, ) -> dict[str, Any]: - """Test-only oracle for symbolic bound relations and activated identity. + """A narrow independent reference using pinned versions, never case.expected. - It intentionally never consults case['expected']. A result is eligible for - comparison with an implementation only when an independent binder produces - its own claim IDs and relations under an explicit, compatible frame. + The C-01/C-02 legacy 'external_identity_witness' inputs stay frozen as + originally preregistered. They do NOT control admission. Instead, the + recorded claim at its fixed address becomes visible at its sealed version. """ if case["id"] not in ("C-01", "C-02"): - raise ValueError("this oracle covers only C-01 and C-02") - source = case["input"] - if source["sentences"] != gold["sentences"]: + raise ValueError("this oracle covers only C-01/C-02") + if case["input"]["sentences"] != gold["sentences"]: raise ValueError("sentence/gold binding drift") - if entry_order not in source["entry_orders"] or sorted(entry_order) != list(range(4)): + if entry_order not in case["input"]["entry_orders"] or sorted(entry_order) != list(range(4)): raise ValueError("unregistered or incomplete rotation") + if read_ref is None: + read_ref = gold["read_heads"][case["id"]] + dataset, branch, version = _validated_ref(read_ref) + atoms = list(gold["facts"] if facts is None else facts) if len({a["sentence_index"] for a in atoms}) != len(atoms): raise ValueError("multiple atoms per sentence exceed this narrow oracle") @@ -59,21 +76,30 @@ def evaluate( raise ValueError("unbound source sentence") selected = sorted(atoms, key=lambda a: entry_order.index(a["sentence_index"])) - witness = source["external_identity_witness"] - roots: tuple[str, ...] = () redirects: dict[str, str] = {} - if witness is not None: - if witness not in gold["attested_identity"]: - raise ValueError("unattested identity witness") - if not all(witness.get(k) for k in ("lhs", "rhs", "root")): - raise ValueError("incomplete identity witness") - # Only the exact gold attestation licenses the substitution. Neither - # lexical similarity nor thought-popcount licenses any other union. - redirects[witness["lhs"]] = witness["rhs"] - roots = (witness["root"],) + witnessed: list[tuple[str, str, str, int]] = [] + roots: set[str] = set() + for assertion in gold["attested_identity"]: + lhs, rhs = assertion["lhs"], assertion["rhs"] + # This symbol is a fixed, manually bound *claim* address, never a + # newly minted witness ID. The assertion is located by address. + if assertion["claim_address"] != f"corefers({lhs},{rhs})": + raise ValueError("identity assertion at wrong claim address") + a_dataset, a_branch, a_version = _validated_ref(assertion["sealed_in"]) + if (a_dataset, a_branch) != (dataset, branch) or a_version > version: + continue + if lhs in redirects and redirects[lhs] != rhs: + raise ValueError("conflicting visible identity assertions") + redirects[lhs] = rhs + witnessed.append((assertion["claim_address"], a_dataset, a_branch, a_version)) + roots.update(assertion["source_roots"]) def canonical(term: str) -> str: + seen: set[str] = set() while term in redirects: + if term in seen: + raise ValueError("cycle in identity assertions") + seen.add(term) term = redirects[term] return term @@ -81,12 +107,12 @@ def canonical(term: str) -> str: sorted((canonical(a["subject"]), a["predicate"], canonical(a["object"])) for a in selected) ) - # Reference traversal: require four distinct, source-bound arcs and a - # complete return to the first key, not just a four-row presence count. + # The test-only traversal checks that the recorded four bound SPO facts + # are a complete cycle, not whether a parser or Datalog join found them. adjacency: dict[str, list[tuple[str, int]]] = {} - for a in selected: - adjacency.setdefault(canonical(a["subject"]), []).append( - (canonical(a["object"]), a["sentence_index"]) + for atom in selected: + adjacency.setdefault(canonical(atom["subject"]), []).append( + (canonical(atom["object"]), atom["sentence_index"]) ) current = canonical("first_sentence.key") visited: set[int] = set() @@ -94,15 +120,17 @@ def canonical(term: str) -> str: options = [edge for edge in adjacency.get(current, []) if edge[1] not in visited] if len(options) != 1: break - current, source_index = options[0] - visited.add(source_index) + current, sentence_id = options[0] + visited.add(sentence_id) closed = len(visited) == 4 and current == canonical("first_sentence.key") return { "cycle_closed": closed, - "coreference_status": "WitnessedInFixture" if roots else "Unresolved", + "coreference_status": "VersionWitnessed" if witnessed else "Unresolved", "relations": relations, - "witness_roots": roots, + "witness_coordinates": tuple(sorted(witnessed)), + "source_roots": tuple(sorted(roots)), "source_sentence_indices": tuple(sorted(visited)), + "observed_ref": (dataset, branch, version), } @@ -112,12 +140,12 @@ def main() -> None: case = load_case(case_id) results = [evaluate(case, gold, order) for order in case["input"]["entry_orders"]] if not all(x == results[0] for x in results): - raise SystemExit(f"{case_id}: rotation changed the canonical answer") + raise SystemExit(f"{case_id}: rotation changed canonical result") if results[0]["cycle_closed"] != case["expected"]["cycle_closed"]: - raise SystemExit(f"{case_id}: reference mismatched preregistered expected closure") + raise SystemExit(f"{case_id}: closure mismatched original pre-registration") print(f"{case_id}: rotations={len(results)}, closed={results[0]['cycle_closed']}, " - f"coreference={results[0]['coreference_status']}, roots={results[0]['witness_roots']}") - print("Reference oracle only: no production parser or execution path was tested.") + f"ref={results[0]['observed_ref']}, witness={results[0]['witness_coordinates']}") + print("Reference only: no production parser, R2IL joins or evidence gate tested.") if __name__ == "__main__": From 604011b6c52e4c1721d339b2ba57bdf6969b1c4e Mon Sep 17 00:00:00 2001 From: AdaWorldAPI Date: Sun, 18 Oct 2026 19:02:25 +0200 Subject: [PATCH 8/9] test: pin version as witness; test horizons, identity and root separation --- .../test_ring_reference.py | 88 +++++++++++++------ 1 file changed, 62 insertions(+), 26 deletions(-) diff --git a/tools/semantic_ring_oracle/test_ring_reference.py b/tools/semantic_ring_oracle/test_ring_reference.py index ffcf19dcb..adb14cfbd 100644 --- a/tools/semantic_ring_oracle/test_ring_reference.py +++ b/tools/semantic_ring_oracle/test_ring_reference.py @@ -1,4 +1,4 @@ -"""C-01/C-02 falsifiers, including silence and mutation controls.""" +"""Version-address C-01/C-02 falsifiers and independent reference controls.""" import copy import unittest @@ -21,49 +21,74 @@ def test_witnessed_closure_is_rotation_invariant(self): for order in self.positive["input"]["entry_orders"]] self.assertTrue(all(x == readings[0] for x in readings)) self.assertTrue(readings[0]["cycle_closed"]) - self.assertEqual(readings[0]["witness_roots"], ("independent_coref_witness_1",)) - self.assertEqual(len(readings[0]["relations"]), 4) + self.assertEqual(readings[0]["coreference_status"], "VersionWitnessed") + self.assertEqual(readings[0]["witness_coordinates"], ( + ("corefers(last_sentence.key,first_sentence.key)", "symbolic-ring", "main", 17), + )) + self.assertEqual(readings[0]["source_roots"], ("independent_coref_witness_1",)) - def test_unwitnessed_ring_remains_open_under_every_rotation(self): + def test_pre_witness_version_remains_open_under_every_rotation(self): for order in self.negative["input"]["entry_orders"]: with self.subTest(order=order): result = evaluate(self.negative, self.gold, order) self.assertFalse(result["cycle_closed"]) self.assertEqual(result["coreference_status"], "Unresolved") - self.assertEqual(result["witness_roots"], ()) + self.assertEqual(result["witness_coordinates"], ()) self.assertEqual(len(result["relations"]), 4) - def test_inactive_attestation_is_not_implicit(self): - candidate = copy.deepcopy(self.positive) - candidate["input"]["external_identity_witness"] = None - self.assertFalse(self.run_case(candidate)["cycle_closed"]) - - def test_spoofed_root_does_not_close_cycle(self): - candidate = copy.deepcopy(self.positive) - candidate["input"]["external_identity_witness"]["root"] = "copied_fake_witness" - with self.assertRaisesRegex(ValueError, "unattested"): - self.run_case(candidate) + def test_a_later_version_closes_same_C02_without_rewriting_identities(self): + future = {"dataset": "symbolic-ring", "branch": "main", "version": 17} + result = self.run_case(self.negative, read_ref=future) + baseline = self.run_case(self.positive) + self.assertTrue(result["cycle_closed"]) + self.assertEqual(result["relations"], baseline["relations"]) + self.assertEqual(result["witness_coordinates"], baseline["witness_coordinates"]) - def test_wrong_identity_endpoints_are_refused(self): + def test_legacy_external_witness_field_does_not_control_admission(self): candidate = copy.deepcopy(self.positive) - candidate["input"]["external_identity_witness"]["rhs"] = "door" - with self.assertRaisesRegex(ValueError, "unattested"): - self.run_case(candidate) + candidate["input"]["external_identity_witness"]["root"] = "spoofed-root" + self.assertTrue(self.run_case(candidate)["cycle_closed"]) + self.assertEqual(self.run_case(candidate)["source_roots"], ( + "independent_coref_witness_1",)) + + def test_declaring_a_root_does_not_bypass_older_read_horizon(self): + old = {"dataset": "symbolic-ring", "branch": "main", "version": 16} + self.assertFalse(self.run_case(self.positive, read_ref=old)["cycle_closed"]) + + def test_dataset_or_branch_mismatch_cannot_witness_identity(self): + for ref in ( + {"dataset": "other-dataset", "branch": "main", "version": 17}, + {"dataset": "symbolic-ring", "branch": "other-branch", "version": 17}, + ): + with self.subTest(ref=ref): + self.assertFalse(self.run_case(self.positive, read_ref=ref)["cycle_closed"]) + + def test_wrong_claim_address_is_refused(self): + gold = copy.deepcopy(self.gold) + gold["attested_identity"][0]["claim_address"] = "invented.witness.id" + with self.assertRaisesRegex(ValueError, "wrong claim address"): + evaluate(self.positive, gold, self.positive["input"]["entry_orders"][0]) + + def test_missing_or_unbounded_version_ref_is_refused(self): + for ref in ({"dataset": "symbolic-ring", "branch": "main"}, + {"dataset": "symbolic-ring", "branch": "main", "version": -1}, + {"dataset": "symbolic-ring", "branch": "main", "version": None}): + with self.subTest(ref=ref), self.assertRaisesRegex(ValueError, "reference"): + self.run_case(self.positive, read_ref=ref) def test_missing_last_claim_breaks_cycle_even_with_witness(self): - truncated = copy.deepcopy(self.gold["facts"][:-1]) - self.assertFalse(self.run_case(self.positive, facts=truncated)["cycle_closed"]) + self.assertFalse(self.run_case(self.positive, + facts=copy.deepcopy(self.gold["facts"][:-1]))["cycle_closed"]) def test_changed_predicate_changes_semantics_not_only_topology(self): baseline = self.run_case(self.positive) altered = copy.deepcopy(self.gold["facts"]) altered[-1]["predicate"] = "destroys" mutant = self.run_case(self.positive, facts=altered) - self.assertTrue(mutant["cycle_closed"], "unlabeled geometry still cycles") - self.assertNotEqual(mutant["relations"], baseline["relations"], - "different predicates cannot retain claim identity") + self.assertTrue(mutant["cycle_closed"], "unlabeled topology still cycles") + self.assertNotEqual(mutant["relations"], baseline["relations"]) - def test_different_last_referent_does_not_close_with_unrelated_witness(self): + def test_different_last_referent_stays_open(self): changed = copy.deepcopy(self.gold["facts"]) changed[-1]["object"] = "another.key" self.assertFalse(self.run_case(self.positive, facts=changed)["cycle_closed"]) @@ -78,11 +103,22 @@ def test_unregistered_rotation_refused(self): with self.assertRaisesRegex(ValueError, "unregistered"): evaluate(self.positive, self.gold, [3, 2, 1, 0]) - def test_fixture_expected_fields_do_not_drive_oracle(self): + def test_expected_fields_do_not_drive_oracle(self): candidate = copy.deepcopy(self.negative) candidate["expected"]["cycle_closed"] = True self.assertFalse(self.run_case(candidate)["cycle_closed"]) + def test_source_roots_are_evidential_metadata_not_witness_identity(self): + gold = copy.deepcopy(self.gold) + gold["attested_identity"][0]["source_roots"] = [ + "source-A", "source-A", "source-B", + ] + result = evaluate(self.positive, gold, self.positive["input"]["entry_orders"][0]) + self.assertTrue(result["cycle_closed"]) + self.assertEqual(result["source_roots"], ("source-A", "source-B")) + self.assertEqual(result["witness_coordinates"], + self.run_case(self.positive)["witness_coordinates"]) + if __name__ == "__main__": unittest.main() From af058caf988ae85919a3861f51e5cf02b189f8f0 Mon Sep 17 00:00:00 2001 From: AdaWorldAPI Date: Sun, 18 Oct 2026 19:02:52 +0200 Subject: [PATCH 9/9] docs: explain version-as-witness and stable thought address invariants --- tools/semantic_ring_oracle/README.md | 78 ++++++++++++++++++---------- 1 file changed, 50 insertions(+), 28 deletions(-) diff --git a/tools/semantic_ring_oracle/README.md b/tools/semantic_ring_oracle/README.md index 01ab3e9d6..cf691d699 100644 --- a/tools/semantic_ring_oracle/README.md +++ b/tools/semantic_ring_oracle/README.md @@ -1,36 +1,58 @@ # C-01/C-02 semantic ring reference oracle -**Scope: test-only independent oracle, not the Rust semantic candidate runtime.** - -The pre-registered C-01 and C-02 fixtures in -`docs/research/versioned-semantic-candidates-fixtures.json` make a strong -claim: rotating a four-sentence ring does not change its justified canonical -relations, but the ring must **not close** unless the last indefinite key is -identified with the first by an explicit, independent witness. - -`docs/research/semantic-ring-bound-gold-v1.json` adds manually annotated -subject/predicate/object bindings. The first and last key remain **different -identities**. The fixture's synthetic attestation can be activated only when -its exact root and endpoints match the registered gold record. Grammar -parsing, NodeGuid/codebook minting and witness verification against a real -source are deliberately **out of scope**. This avoids treating the English -word `key` as a foreign-key join or inventing coreference. +**Test-only independent oracle. Not the Rust semantic candidate runtime.** + +This experiment is a versioned identity assertion, not a newly minted +'witness object'. The four bound SPO relations live at fixed symbolic +identities. The identity assertion itself has a **fixed claim address** +`corefers(last_sentence.key,first_sentence.key)`. Its **sealed version** is +the witness of its admission: + +- C-02 reads `(symbolic-ring, main, v16)`: the claim does not yet exist. + Four sentences look cyclic, but their distinct key identities make the + cycle open. +- C-01 reads `(symbolic-ring, main, v17)`: the exact same semantic identities + are read; version 17 has witnessed the added identity assertion, and the + cycle closes in all four rotations. +- Re-reading C-02 at v17 closes the cycle **without reminting any identity**. + An older horizon stays unresolved even if its narrative says a witness + exists. Version visibility is not inferred from a source-root label. + +This directly follows the D-TGA decision in +`.claude/plans/thought-git-api-v1.md`: a sealed version is the PR entry; +`blame` returns a landing version plus original source bits. The active +thought slot `0..63` is recyclable. The history witness is the claim's +**thought address at the sealed version**, not a reusable slot number, an +external pointer, a new witness NodeGuid or a bare numeric Lance version. +The tuple in this **symbolic** fixture includes dataset and branch because +real durable versions need those to disambiguate identity. + +**Evidence root != witness coordinate.** Independent source roots are +metadata in the version receipt for NAL/Gadamer revision. Three thoughts +copying one observation do not yield three independent sources, and neither +a version number nor an address bit alone proves a claim *true*. The fixture +contains a synthetic source root, not external proof of real-world coreference. + +The preregistered C-01/C-02 source JSON in +`docs/research/versioned-semantic-candidates-fixtures.json` remains unchanged. +Its older `external_identity_witness` field is retained for traceability +but is **not** the executable witness index. The new v2 gold is held in +`docs/research/semantic-ring-bound-gold-v1.json` (original path retained), +with explicitly pinned read horizons and a sealed claim-address receipt. ```sh python3 tools/semantic_ring_oracle/ring_reference.py python3 -m unittest discover -s tools/semantic_ring_oracle -p 'test_*.py' -v ``` -The oracle does not read `case.expected` during evaluation. It checks four -rotations, negative closure, spoofed/misdirected witnesses, missing claims, -duplicate sentence bindings, and a changed predicate that preserves -unlabeled graph topology while changing the semantic claim set. - -**Next integration gate:** have a real DeepNSM/UD binder emit version-pinned -canonical bound relations (or an explicit `Unbound`) with source-root receipts; -compare its output and downstream R2IL/Quack selection against this reference. -A test passing here certifies only the reference fixtures, **not** parsing, -coreference accuracy, semantic alignment, actual independent evidence, a -foreign-address join, or production C-01/C-02 behavior. Do not import the -Python oracle into a production execution path or lower semantic equality to -an unverified mask AND. +The reference never consults `case.expected` during evaluation. Controls +include four rotations, pre/post version, wrong dataset/branch, spurious +root labels, wrong claim address, missing version, predicate mutation, +truncated facts and source-root de-duplication. + +**Next integration gate:** have the actual DeepNSM/UD binder produce +canonical bound claim addresses and their stamped, versioned thought writes +(or `Unbound`), then differential-check real mask/R2IL execution against this +reference. No parser, real-world evidence authentication, NodeGuid allocation, +Lance13 integration, generalized relational join, causal inference or +production C-01/C-02 semantic closure is claimed here.