diff --git a/README.md b/README.md index a0fea59..31db098 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ Noetheris does not claim quantum advantage, does not assess deployed cryptograph | Structural IR validation and hashing | `tests/test_structural_ir.py`, `examples/structural_ir/*.json`, `docs/results/compiled_qubo_solution.json` | | QUBO/Ising energy preservation | `tests/test_qubo.py`, `examples/qubo_ising_qaoa.py`, `docs/results/qaoa_hamiltonian_report.json` | | D-Wave/Ocean boundary | `tests/test_optional_integrations.py`, `tests/test_external_examples.py`, `examples/dwave_ocean_exchange.py`, `examples/external_solver_replay.py`, `docs/results/compiled_qubo_solution.json`, `docs/results/external_solver_replay_examples.json`, `docs/dwave_mapping.md` | +| Solver-boundary evidence schema | `docs/results/solver_boundary_evidence.json`, `docs/results/release_evidence_index.json`, `docs/reproducibility.md`, `docs/benchmarks.md` | | IBM/Qiskit oracle boundary | `tests/test_circuits.py`, `tests/test_optional_integrations.py`, `tests/test_external_examples.py`, `examples/qiskit_oracle_export.py`, `docs/results/oracle_truth_table.json` | | Certificate replay | `tests/test_certificates.py`, `examples/example_energy_certificate.json`, `docs/results/invariant_witness.json` | | CV/GKP diagnostics | `tests/test_cv.py`, `examples/cv_gkp_stabilizer_diagnostics.py`, `docs/results/cv_gkp_diagnostic_certificate.json` | diff --git a/docs/benchmarks.md b/docs/benchmarks.md index 3507be8..7a4d24e 100644 --- a/docs/benchmarks.md +++ b/docs/benchmarks.md @@ -8,6 +8,8 @@ bash scripts/run_benchmarks.sh It produces JSON and CSV artifacts under `benchmarks/results/`. Records include problem hash, compiled-model hash, assignment hash, problem size, variable count, constraint count, solver, seed, deterministic runtime policy, energy, replay status, solver boundary, embedding status, oracle depth estimate, and boundary leakage where applicable. The committed baseline records `runtime_seconds` as `null` because wall-clock timing is host-dependent. +Solver-boundary release evidence lives under `docs/results/solver_boundary_evidence.json`. It records the canonical QUBO exchange hash, local replay status, replay artifact hash, metadata boundary policy, and deterministic optional-ecosystem availability policy for Ocean and Qiskit. Actual local availability of optional packages is reported by examples at runtime and is kept out of committed deterministic benchmark baselines. + For local timing, use: ```bash diff --git a/docs/reproducibility.md b/docs/reproducibility.md index bcb027d..84bc152 100644 --- a/docs/reproducibility.md +++ b/docs/reproducibility.md @@ -29,3 +29,11 @@ bash scripts/run_benchmarks.sh ``` The benchmark runner regenerates `benchmarks/results/noetheris_v0_1_baseline.json` and `.csv`. The committed baseline sets `runtime_seconds` to `null` and records a `runtime_policy` field because local timing is machine-dependent. Structural fields, hashes, seeds, replay status, energies, solver labels, oracle metrics, CV leakage, and model sizes are the reproducibility-critical data. Use `python3 benchmarks/run_measured_benchmarks.py` for host-specific timing with environment metadata. + +## Solver-Boundary Evidence + +```bash +python3 scripts/generate_release_results.py +``` + +The release evidence generator writes `docs/results/solver_boundary_evidence.json`. That artifact records the QUBO exchange hash, replay artifact hash, replay status, replay authority, rejection-code coverage, and solver/embedding metadata boundaries. Optional Ocean and Qiskit availability are intentionally represented as deterministic policy fields with runtime probe commands. The committed baseline does not encode whether a contributor's local machine happened to have `dimod` or Qiskit installed. diff --git a/docs/results/README.md b/docs/results/README.md index 28884e2..e7ba9e3 100644 --- a/docs/results/README.md +++ b/docs/results/README.md @@ -1,6 +1,6 @@ # Release Results -This directory contains deterministic evidence artifacts for Noetheris v0.1.0. +This directory contains deterministic evidence artifacts for Noetheris v0.1.0 and narrow v0.2 solver-boundary work. They are generated from checked-in examples and can be rebuilt with: ```bash @@ -13,6 +13,7 @@ python3 scripts/generate_release_results.py - `invariant_witness.json`: bounded consensus-safety counterexample witness with certificate data. - `compiled_qubo_solution.json`: Structural IR compilation, exact QUBO solution, energy breakdown, D-Wave exchange payload, and local replay of a solver sample. - `external_solver_replay_examples.json`: accepted and rejected external-candidate replay artifacts with explicit hash, assignment-domain, energy, and metadata rejection reasons. +- `solver_boundary_evidence.json`: v0.2 solver-boundary evidence schema with QUBO exchange hash, local replay status, optional Ocean/Qiskit availability policy, and metadata boundary declarations. - `pqc_migration_plan.json`: migration optimizer output, residual risk, dependency analysis, QUBO model, and certificate. - `oracle_truth_table.json`: Boolean predicate truth table, reversible compute/apply/uncompute metrics, and QASM-like text. - `qaoa_hamiltonian_report.json`: QUBO-to-Ising lowering and exact local QAOA p=1 statevector check. @@ -21,4 +22,4 @@ python3 scripts/generate_release_results.py ## Interpretation -These files are release evidence, not hardware benchmark claims. The D-Wave payload is a BINARY QUBO exchange representation; any external solver sample must be replayed locally before it is trusted. Solver and embedding metadata are recorded as externally supplied evidence; local replay does not infer hardware embedding quality. The Qiskit-facing oracle artifacts are small-predicate circuit mappings; they do not claim backend advantage. The CV/GKP certificate uses finite Fock truncation and records boundary effects explicitly. +These files are release evidence, not hardware benchmark claims. The D-Wave payload is a BINARY QUBO exchange representation; any external solver sample must be replayed locally before it is trusted. Solver and embedding metadata are recorded as externally supplied evidence; local replay does not infer hardware embedding quality. Optional Ocean and Qiskit availability is host-dependent, so committed evidence records deterministic probe policy and runtime commands instead of local package state. The Qiskit-facing oracle artifacts are small-predicate circuit mappings; they do not claim backend advantage. The CV/GKP certificate uses finite Fock truncation and records boundary effects explicitly. diff --git a/docs/results/release_evidence_index.json b/docs/results/release_evidence_index.json index f53ed23..d5e7055 100644 --- a/docs/results/release_evidence_index.json +++ b/docs/results/release_evidence_index.json @@ -10,7 +10,14 @@ }, { "bytes": 17838, - "file": "docs/results/external_solver_replay_examples.json" + "file": "docs/results/external_solver_replay_examples.json", + "schema": "noetheris.external_solver_replay.examples.v1" + }, + { + "bytes": 2707, + "file": "docs/results/solver_boundary_evidence.json", + "schema": "noetheris.solver_boundary_evidence.v1", + "scope": "v0.2 deterministic solver-boundary evidence" }, { "bytes": 6529, @@ -35,5 +42,7 @@ ], "regenerate": "python3 scripts/generate_release_results.py", "release": "Noetheris v0.1.0 \u2014 Structural Quantum Security Kernel", + "roadmap_scope": "v0.2 solver-boundary evidence included", + "schema": "noetheris.release_evidence_index.v1", "scope": "deterministic release evidence" } diff --git a/docs/results/solver_boundary_evidence.json b/docs/results/solver_boundary_evidence.json new file mode 100644 index 0000000..602af56 --- /dev/null +++ b/docs/results/solver_boundary_evidence.json @@ -0,0 +1,80 @@ +{ + "candidate_replay": { + "artifact_hash": "sha256:d1888865d53521446dd39af85d8820ba966ce263e239c921edeeea4911dbecd8", + "energy_recomputed": true, + "recomputed_energy": 10.0, + "reported_energy": 10.0, + "schema": "noetheris.external_solver_replay.v1", + "status": "verified", + "verification_authority": "noetheris.local_replay" + }, + "host_independent": true, + "metadata_boundaries": { + "embedding_metadata": { + "authority": "external_tool", + "local_default": { + "embedding": null, + "embedding_status": "not_requested" + }, + "local_interpretation": "recorded_evidence_only" + }, + "hardware_claims": { + "hardware_benchmark": false, + "quantum_advantage": false + }, + "solver_metadata": { + "authority": "external_tool", + "local_interpretation": "recorded_evidence_only" + } + }, + "optional_ecosystem_availability": { + "ocean": { + "availability_field": "ocean_bqm_report.available", + "committed_availability": "not_assumed", + "credential_required": false, + "host_independent": true, + "runtime_probe_command": "python3 examples/dwave_ocean_exchange.py" + }, + "qiskit": { + "availability_field": "qiskit_status.available", + "committed_availability": "not_assumed", + "credential_required": false, + "host_independent": true, + "runtime_probe_command": "python3 examples/qiskit_oracle_export.py" + } + }, + "problem": { + "compiled_model_hash": "sha256:eca1158e2ddfdfe196775a49b8ffbcd46a23a33bf61e18e8229dcda0174612d2", + "problem_hash": "sha256:3cddd03a5881f3b71ba61c3b063f96ec47dba9f9160a634392929eca618d095f", + "problem_type": "invariant" + }, + "qubo_exchange": { + "linear_term_count": 4, + "model_hash": "sha256:abb217c2c5893c3dc6bf88de18b2ad53c9a54dc19799398fdd1bd41d7ad6aad7", + "normalization": { + "duplicate_pairs": "aggregated", + "reversed_pairs": "ordered_by_variable_list", + "self_quadratic": "folded_into_linear" + }, + "quadratic_term_count": 10, + "schema": "noetheris.qubo.exchange.v1", + "variable_count": 5, + "vartype": "BINARY" + }, + "rejection_coverage": { + "case_count": 6, + "reason_codes": [ + "assignment_missing_variables", + "assignment_unknown_variables", + "compiled_model_hash_mismatch", + "embedding_metadata_malformed", + "problem_hash_mismatch", + "reported_energy_mismatch", + "solver_metadata_malformed" + ] + }, + "runtime_policy": "committed evidence excludes wall-clock timing and installed optional package state", + "runtime_seconds": null, + "schema": "noetheris.solver_boundary_evidence.v1", + "scope": "v0.2 deterministic solver-boundary evidence" +} diff --git a/scripts/generate_release_results.py b/scripts/generate_release_results.py index 2281c35..782a89a 100644 --- a/scripts/generate_release_results.py +++ b/scripts/generate_release_results.py @@ -42,6 +42,18 @@ def main() -> None: ) compiled = compile_system(structural, "invariant") solution = solve_exact(compiled) + exchange = qubo_exchange_payload(compiled.model) + sample_replay = replay_external_solution( + compiled, + solution.assignment, + reported_energy=solution.energy, + problem_hash=compiled.problem_hash, + compiled_model_hash=compiled.compiled_model_hash, + solver_metadata={"source": "local_exact_solver"}, + ) + replay_examples = _external_replay_examples( + compiled, solution.assignment, solution.energy + ) _write( "compiled_qubo_solution.json", { @@ -51,21 +63,19 @@ def main() -> None: "energy": solution.energy, }, "explanation": explain_solution(compiled, solution), - "dwave_exchange": qubo_exchange_payload(compiled.model), - "external_sample_replay": replay_external_solution( - compiled, - solution.assignment, - reported_energy=solution.energy, - problem_hash=compiled.problem_hash, - compiled_model_hash=compiled.compiled_model_hash, - solver_metadata={"source": "local_exact_solver"}, - ), + "dwave_exchange": exchange, + "external_sample_replay": sample_replay, }, artifacts, ) _write( "external_solver_replay_examples.json", - _external_replay_examples(compiled, solution.assignment, solution.energy), + replay_examples, + artifacts, + ) + _write( + "solver_boundary_evidence.json", + _solver_boundary_evidence(compiled, exchange, sample_replay, replay_examples), artifacts, ) @@ -113,8 +123,10 @@ def main() -> None: _write( "release_evidence_index.json", { + "schema": "noetheris.release_evidence_index.v1", "release": "Noetheris v0.1.0 — Structural Quantum Security Kernel", "scope": "deterministic release evidence", + "roadmap_scope": "v0.2 solver-boundary evidence included", "regenerate": "python3 scripts/generate_release_results.py", "artifacts": artifacts, }, @@ -126,11 +138,115 @@ def _write(name: str, payload: dict[str, Any], artifacts: list[dict[str, Any]]) path = RESULTS / name path.write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n", encoding="utf-8") artifacts.append( + _artifact_index_entry( + payload, + file=f"docs/results/{name}", + byte_count=path.stat().st_size, + ) + ) + + +def _artifact_index_entry( + payload: dict[str, Any], + *, + file: str, + byte_count: int, +) -> dict[str, Any]: + entry: dict[str, Any] = { + "file": file, + "bytes": byte_count, + } + if "schema" in payload: + entry["schema"] = payload["schema"] + if "scope" in payload: + entry["scope"] = payload["scope"] + return entry + + +def _solver_boundary_evidence( + compiled: Any, + exchange: dict[str, Any], + replay: dict[str, Any], + replay_examples: dict[str, Any], +) -> dict[str, Any]: + reason_codes = sorted( { - "file": f"docs/results/{name}", - "bytes": path.stat().st_size, + reason_code + for candidate in replay_examples["rejected_candidates"] + for reason_code in candidate["reason_codes"] } ) + return { + "schema": "noetheris.solver_boundary_evidence.v1", + "scope": "v0.2 deterministic solver-boundary evidence", + "host_independent": True, + "runtime_seconds": None, + "runtime_policy": ( + "committed evidence excludes wall-clock timing and installed optional " + "package state" + ), + "problem": { + "problem_type": compiled.problem_type, + "problem_hash": compiled.problem_hash, + "compiled_model_hash": compiled.compiled_model_hash, + }, + "qubo_exchange": { + "schema": exchange["format"], + "model_hash": exchange["model_hash"], + "vartype": exchange["vartype"], + "variable_count": len(exchange["variables"]), + "linear_term_count": len(exchange["linear_terms"]), + "quadratic_term_count": len(exchange["quadratic_terms"]), + "normalization": exchange["normalization"], + }, + "candidate_replay": { + "schema": replay["schema"], + "status": replay["status"], + "artifact_hash": replay["artifact_hash"], + "reported_energy": replay["reported_energy"], + "recomputed_energy": replay["recomputed_energy"], + "energy_recomputed": replay["energy_recomputed"], + "verification_authority": replay["verification_authority"], + }, + "rejection_coverage": { + "case_count": len(replay_examples["rejected_candidates"]), + "reason_codes": reason_codes, + }, + "optional_ecosystem_availability": { + "ocean": { + "committed_availability": "not_assumed", + "credential_required": False, + "runtime_probe_command": "python3 examples/dwave_ocean_exchange.py", + "availability_field": "ocean_bqm_report.available", + "host_independent": True, + }, + "qiskit": { + "committed_availability": "not_assumed", + "credential_required": False, + "runtime_probe_command": "python3 examples/qiskit_oracle_export.py", + "availability_field": "qiskit_status.available", + "host_independent": True, + }, + }, + "metadata_boundaries": { + "solver_metadata": { + "authority": "external_tool", + "local_interpretation": "recorded_evidence_only", + }, + "embedding_metadata": { + "authority": "external_tool", + "local_interpretation": "recorded_evidence_only", + "local_default": { + "embedding_status": "not_requested", + "embedding": None, + }, + }, + "hardware_claims": { + "hardware_benchmark": False, + "quantum_advantage": False, + }, + }, + } def _external_replay_examples( diff --git a/tests/test_release_evidence.py b/tests/test_release_evidence.py new file mode 100644 index 0000000..3b6fdc4 --- /dev/null +++ b/tests/test_release_evidence.py @@ -0,0 +1,53 @@ +from __future__ import annotations + +import json +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] + + +def test_solver_boundary_evidence_schema_is_host_independent() -> None: + payload = json.loads( + (ROOT / "docs" / "results" / "solver_boundary_evidence.json").read_text( + encoding="utf-8" + ) + ) + assert payload["schema"] == "noetheris.solver_boundary_evidence.v1" + assert payload["host_independent"] is True + assert payload["runtime_seconds"] is None + assert payload["qubo_exchange"]["model_hash"].startswith("sha256:") + assert payload["candidate_replay"]["status"] == "verified" + assert payload["candidate_replay"]["artifact_hash"].startswith("sha256:") + assert payload["candidate_replay"]["verification_authority"] == "noetheris.local_replay" + assert payload["optional_ecosystem_availability"]["ocean"] == { + "availability_field": "ocean_bqm_report.available", + "committed_availability": "not_assumed", + "credential_required": False, + "host_independent": True, + "runtime_probe_command": "python3 examples/dwave_ocean_exchange.py", + } + assert payload["optional_ecosystem_availability"]["qiskit"] == { + "availability_field": "qiskit_status.available", + "committed_availability": "not_assumed", + "credential_required": False, + "host_independent": True, + "runtime_probe_command": "python3 examples/qiskit_oracle_export.py", + } + assert payload["metadata_boundaries"]["hardware_claims"] == { + "hardware_benchmark": False, + "quantum_advantage": False, + } + + +def test_release_evidence_index_records_solver_boundary_schema() -> None: + payload = json.loads( + (ROOT / "docs" / "results" / "release_evidence_index.json").read_text( + encoding="utf-8" + ) + ) + assert payload["schema"] == "noetheris.release_evidence_index.v1" + artifacts = {item["file"]: item for item in payload["artifacts"]} + solver_boundary = artifacts["docs/results/solver_boundary_evidence.json"] + assert solver_boundary["schema"] == "noetheris.solver_boundary_evidence.v1" + assert solver_boundary["scope"] == "v0.2 deterministic solver-boundary evidence"