From 924fd8e43fa03c71d981e3bc7e21ed89ee6ce311 Mon Sep 17 00:00:00 2001 From: sicarii Date: Sun, 23 Aug 2026 21:28:56 -0400 Subject: [PATCH 01/22] Add Linux aarch64 host support: re-pin formal lanes + wire provisioner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extends the JACKAL runtime and its Codex plugin to Linux aarch64 alongside the existing macOS arm64 support, non-destructively — the macOS release identity (MANIFEST.sha256, proof identities, compat floor) stays byte-clean and every macOS code path falls through unchanged. Re-pin (formal lanes on Linux): - release/tools/repin_linux.py derives a per-host release/MANIFEST..sha256 that rebinds only the compiled-binary rows, the proof-identity rows, and the compiler pin from live bytes; all other rows are copied verbatim from the macOS manifest. - Host-suffixed Linux proof identities, a Linux compat floor, and a Linux lean-admission-audit are generated from the locally built Lean checkers. - release_validate.py, gaussian_release.py, int_cert_release.py, formal_receipt.py and lean_admission_audit.py prefer host-suffixed evidence and fall back to the pinned macOS records. - The ten jackal-*-release wrappers select the per-host manifest and identity. All ten formal lanes emit status=formal-bounded with re-verified receipts. Provisioner (install the Linux runtime): - release/build_package_linux.sh builds jackal-v1.7.3-linux-aarch64.tar.gz, passing full identity + semantic validation (plugin identity_match, formal smokes, receipt replays). The atomic no-replace publish uses renameat2 (RENAME_NOREPLACE) on Linux. - provision_runtime.py: SUPPORTED_HOSTS + RELEASE_PINS gain linux-aarch64; resolve_host/release_pin/rename_exclusive_for_host select per host; provision() binds the host release pin; byte caps fit the largest runtime; a POSIX launch_mcp.sh joins launch_mcp.zsh with a byte-identical probe. - mcp/server.py locator + package-metadata checks use effective_release_pins. - A ubuntu-24.04-arm CI job runs the plugin gates on Linux. Note: the domain-pack protocol-v1 verifier host-gates to macOS in pinned shared source, so its staged QA is skipped for a local build (JACKAL_LOCAL_BUILD=1); the ~4 domain-pack/program tools fail closed on Linux, and the archival v1.7.0 lane stays macOS bytes. 37/41 tools work on Linux, including every formal-bounded lane. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/jackal-codex-plugin.yml | 51 + jackal-atan-rat-release | 8 +- jackal-cert-release | 12 +- jackal-cos-rat-release | 8 +- jackal-exp-rat-release | 8 +- jackal-gaussian-release | 12 +- jackal-int-cert-release | 12 +- jackal-ln-rat-release | 8 +- jackal-sin-rat-release | 8 +- jackal-sqrt-rat-release | 8 +- jackal-tanh-rat-release | 8 +- plugins/jackel/.mcp.json | 4 +- plugins/jackel/PLUGIN_IDENTITY.sha256 | 13 +- plugins/jackel/README.md | 25 +- plugins/jackel/mcp/server.py | 20 +- plugins/jackel/scripts/launch_mcp.sh | 66 + plugins/jackel/scripts/launch_mcp.zsh | 6 +- plugins/jackel/scripts/provision_runtime.py | 224 ++- plugins/jackel/skills/jackel/SKILL.md | 40 +- release/MANIFEST.linux-aarch64.sha256 | 49 + release/build_package_linux.sh | 1328 +++++++++++++++++ release/capability_inventory_v1.json | 2 +- release/compat/v172_floor.linux-aarch64.json | 79 + ...gaussian_proof_identity.linux-aarch64.json | 486 ++++++ ...ert_proof_identity_v172.linux-aarch64.json | 687 +++++++++ ...an_admission_audit_v173.linux-aarch64.json | 803 ++++++++++ ...nge_proof_identity_v172.linux-aarch64.json | 562 +++++++ release/tools/bake_linux_compat_pins.py | 25 + release/tools/repin_linux.py | 162 ++ tests/codex_plugin/live_acceptance.py | 15 +- tests/codex_plugin/test_live_acceptance.py | 12 +- tests/codex_plugin/test_mcp_adapter.py | 13 + tests/codex_plugin/test_plugin_metadata.py | 155 +- .../codex_plugin/test_runtime_provisioner.py | 166 ++- tests/release_validate.py | 7 + tools/capability_drift_gate.py | 1 + tools/formal_receipt.py | 30 +- tools/gaussian_release.py | 3 + tools/int_cert_release.py | 4 + tools/lean_admission_audit.py | 27 +- 40 files changed, 5025 insertions(+), 132 deletions(-) create mode 100755 plugins/jackel/scripts/launch_mcp.sh create mode 100644 release/MANIFEST.linux-aarch64.sha256 create mode 100755 release/build_package_linux.sh create mode 100644 release/compat/v172_floor.linux-aarch64.json create mode 100644 release/evidence/gaussian_proof_identity.linux-aarch64.json create mode 100644 release/evidence/int_cert_proof_identity_v172.linux-aarch64.json create mode 100644 release/evidence/lean_admission_audit_v173.linux-aarch64.json create mode 100644 release/evidence/range_proof_identity_v172.linux-aarch64.json create mode 100644 release/tools/bake_linux_compat_pins.py create mode 100755 release/tools/repin_linux.py diff --git a/.github/workflows/jackal-codex-plugin.yml b/.github/workflows/jackal-codex-plugin.yml index 9385323..f57be99 100644 --- a/.github/workflows/jackal-codex-plugin.yml +++ b/.github/workflows/jackal-codex-plugin.yml @@ -12,6 +12,57 @@ env: PYTHONDONTWRITEBYTECODE: "1" jobs: + linux-aarch64-plugin: + name: Linux aarch64 plugin gates + runs-on: ubuntu-24.04-arm + timeout-minutes: 20 + steps: + - name: Check out exact revision + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + with: + fetch-depth: 0 + persist-credentials: false + + - name: Require the supported host and fixed Python prerequisite + run: | + test "$(uname -s)" = Linux + test "$(uname -m)" = aarch64 + test -x /usr/bin/python3 + /usr/bin/python3 -c 'import sys; assert sys.version_info >= (3, 10)' + + - name: Require the host atomic no-replace rename primitive + run: | + /usr/bin/python3 -c ' + import ctypes + libc = ctypes.CDLL(None, use_errno=True) + assert callable(getattr(libc, "renameat2", None)), "glibc renameat2 is required" + ' + + - name: Verify canonical capability and documentation contracts + run: | + /usr/bin/python3 -B tools/capability_inventory.py --check + /usr/bin/python3 -B tools/capability_drift_gate.py + /usr/bin/python3 -B -m unittest \ + tests.capability_inventory_test \ + tests.capability_drift_gate_test -v + + - name: Run complete Codex plugin unit suite + run: /usr/bin/python3 -B -m unittest discover -s tests/codex_plugin -v + + - name: Verify exact plugin identity + run: /usr/bin/python3 -B plugins/jackel/scripts/verify_plugin.py + + - name: Portable launcher starts and refuses for the documented reason + run: | + cd plugins/jackel + set +e + output=$(/bin/sh scripts/launch_mcp.sh provision --check 2>&1) + status=$? + set -e + printf '%s\n' "$output" + test "$status" -eq 1 + printf '%s\n' "$output" | grep -q "no published release asset for host linux-aarch64" + macos-arm64-plugin: name: macOS arm64 plugin gates runs-on: macos-14 diff --git a/jackal-atan-rat-release b/jackal-atan-rat-release index c8a5b78..069fd9a 100755 --- a/jackal-atan-rat-release +++ b/jackal-atan-rat-release @@ -20,7 +20,13 @@ set -eu ROOT=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) PRODUCER="$ROOT/tools/atan_rat_producer.py" CHECKER="$ROOT/proofs/lean/.lake/build/bin/jackal_cert_check" -MANIFEST="$ROOT/release/MANIFEST.sha256" +# Per-host release identity: a source build on this host produces +# byte-different compiled artifacts (jackal-native + Lean checkers), so it +# carries its own MANIFEST..sha256. The macOS arm64 manifest remains +# the default when no host-specific one is present. +HOST_TAG="$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m)" +MANIFEST="$ROOT/release/MANIFEST.$HOST_TAG.sha256" +[ -f "$MANIFEST" ] || MANIFEST="$ROOT/release/MANIFEST.sha256" PROOF_ID="$ROOT/release/evidence/range_proof_identity_v172.json" INVENTORY="$ROOT/release/coverage/formal_coverage_inventory.json" diff --git a/jackal-cert-release b/jackal-cert-release index 8d2f62f..e9c5740 100755 --- a/jackal-cert-release +++ b/jackal-cert-release @@ -18,7 +18,15 @@ set -eu ROOT=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) EVALUATOR="$ROOT/jackal-native" CHECKER="$ROOT/proofs/lean/.lake/build/bin/jackal_cert_check" -MANIFEST="$ROOT/release/MANIFEST.sha256" +# Per-host release identity: a source build on this host produces +# byte-different compiled artifacts (jackal-native + Lean checkers), so it +# carries its own MANIFEST..sha256. The macOS arm64 manifest remains +# the default when no host-specific one is present. +HOST_TAG="$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m)" +MANIFEST="$ROOT/release/MANIFEST.$HOST_TAG.sha256" +[ -f "$MANIFEST" ] || MANIFEST="$ROOT/release/MANIFEST.sha256" +PROOF_ID="$ROOT/release/evidence/range_proof_identity_v172.$HOST_TAG.json" +[ -f "$PROOF_ID" ] || PROOF_ID="$ROOT/release/evidence/range_proof_identity_v172.json" if [ "$#" -ne 4 ]; then echo "usage: jackal-cert-release \"\" " >&2 @@ -50,7 +58,7 @@ exec python3 -I -S -B "$ROOT/tools/isolated_entry.py" range \ --expected-source "$EXPECTED_SOURCE" \ --inventory "$ROOT/release/coverage/formal_coverage_inventory.json" \ --expected-inventory "$EXPECTED_INVENTORY" \ - --proof-identity "$ROOT/release/evidence/range_proof_identity_v172.json" \ + --proof-identity "$PROOF_ID" \ --expected-proof-identity-file "$EXPECTED_PROOF_FILE" \ --expected-proof-identity-digest "$EXPECTED_PROOF_DIGEST" \ --release-epoch v1.7.2 --formal-receipt "$4" diff --git a/jackal-cos-rat-release b/jackal-cos-rat-release index 3692d9b..b6b0690 100755 --- a/jackal-cos-rat-release +++ b/jackal-cos-rat-release @@ -21,7 +21,13 @@ set -eu ROOT=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) PRODUCER="$ROOT/tools/sin_rat_producer.py" CHECKER="$ROOT/proofs/lean/.lake/build/bin/jackal_cert_check" -MANIFEST="$ROOT/release/MANIFEST.sha256" +# Per-host release identity: a source build on this host produces +# byte-different compiled artifacts (jackal-native + Lean checkers), so it +# carries its own MANIFEST..sha256. The macOS arm64 manifest remains +# the default when no host-specific one is present. +HOST_TAG="$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m)" +MANIFEST="$ROOT/release/MANIFEST.$HOST_TAG.sha256" +[ -f "$MANIFEST" ] || MANIFEST="$ROOT/release/MANIFEST.sha256" PROOF_ID="$ROOT/release/evidence/range_proof_identity_v172.json" INVENTORY="$ROOT/release/coverage/formal_coverage_inventory.json" diff --git a/jackal-exp-rat-release b/jackal-exp-rat-release index 711e83b..0402fb8 100755 --- a/jackal-exp-rat-release +++ b/jackal-exp-rat-release @@ -21,7 +21,13 @@ set -eu ROOT=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) PRODUCER="$ROOT/tools/exp_rat_producer.py" CHECKER="$ROOT/proofs/lean/.lake/build/bin/jackal_cert_check" -MANIFEST="$ROOT/release/MANIFEST.sha256" +# Per-host release identity: a source build on this host produces +# byte-different compiled artifacts (jackal-native + Lean checkers), so it +# carries its own MANIFEST..sha256. The macOS arm64 manifest remains +# the default when no host-specific one is present. +HOST_TAG="$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m)" +MANIFEST="$ROOT/release/MANIFEST.$HOST_TAG.sha256" +[ -f "$MANIFEST" ] || MANIFEST="$ROOT/release/MANIFEST.sha256" PROOF_ID="$ROOT/release/evidence/range_proof_identity_v172.json" INVENTORY="$ROOT/release/coverage/formal_coverage_inventory.json" diff --git a/jackal-gaussian-release b/jackal-gaussian-release index 8bcee20..d5ad623 100755 --- a/jackal-gaussian-release +++ b/jackal-gaussian-release @@ -2,7 +2,15 @@ # Fail-closed root wrapper for theorem-backed Gaussian integration. set -eu ROOT=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) -MANIFEST="$ROOT/release/MANIFEST.sha256" +# Per-host release identity: a source build on this host produces +# byte-different compiled artifacts (jackal-native + Lean checkers), so it +# carries its own MANIFEST..sha256. The macOS arm64 manifest remains +# the default when no host-specific one is present. +HOST_TAG="$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m)" +MANIFEST="$ROOT/release/MANIFEST.$HOST_TAG.sha256" +[ -f "$MANIFEST" ] || MANIFEST="$ROOT/release/MANIFEST.sha256" +PROOF_ID="$ROOT/release/evidence/gaussian_proof_identity.$HOST_TAG.json" +[ -f "$PROOF_ID" ] || PROOF_ID="$ROOT/release/evidence/gaussian_proof_identity.json" PRODUCER="$ROOT/tools/gaussian_certificate.py" CHECKER="$ROOT/proofs/lean/.lake/build/bin/jackal_gaussian_check" @@ -32,7 +40,7 @@ exec python3 -I -S -B "$ROOT/tools/isolated_entry.py" gaussian \ --expected-producer "$EXPECTED_PRODUCER" --expected-checker "$EXPECTED_CHECKER" \ --inventory "$ROOT/release/coverage/formal_coverage_inventory.json" \ --expected-inventory "$EXPECTED_INVENTORY" \ - --proof-identity "$ROOT/release/evidence/gaussian_proof_identity.json" \ + --proof-identity "$PROOF_ID" \ --expected-proof-identity-file "$EXPECTED_PROOF_FILE" \ --expected-proof-identity-digest "$EXPECTED_PROOF_DIGEST" \ --receipt "$5" --release-epoch v1.5.0 --timeout "$TIMEOUT" diff --git a/jackal-int-cert-release b/jackal-int-cert-release index ed630c2..759625a 100755 --- a/jackal-int-cert-release +++ b/jackal-int-cert-release @@ -17,7 +17,15 @@ set -eu ROOT=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) PRODUCER="$ROOT/tools/int_cert_producer.py" CHECKER="$ROOT/proofs/lean/.lake/build/bin/jackal_int_cert_check" -MANIFEST="$ROOT/release/MANIFEST.sha256" +# Per-host release identity: a source build on this host produces +# byte-different compiled artifacts (jackal-native + Lean checkers), so it +# carries its own MANIFEST..sha256. The macOS arm64 manifest remains +# the default when no host-specific one is present. +HOST_TAG="$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m)" +MANIFEST="$ROOT/release/MANIFEST.$HOST_TAG.sha256" +[ -f "$MANIFEST" ] || MANIFEST="$ROOT/release/MANIFEST.sha256" +PROOF_ID="$ROOT/release/evidence/int_cert_proof_identity_v172.$HOST_TAG.json" +[ -f "$PROOF_ID" ] || PROOF_ID="$ROOT/release/evidence/int_cert_proof_identity_v172.json" if [ "$#" -ne 5 ]; then echo "usage: jackal-int-cert-release \"\" " >&2 @@ -48,7 +56,7 @@ exec python3 -I -S -B "$ROOT/tools/isolated_entry.py" int-cert \ --receipt "$5" \ --inventory "$ROOT/release/coverage/formal_coverage_inventory.json" \ --expected-inventory "$EXPECTED_INVENTORY" \ - --proof-identity "$ROOT/release/evidence/int_cert_proof_identity_v172.json" \ + --proof-identity "$PROOF_ID" \ --expected-proof-identity-file "$EXPECTED_PROOF_FILE" \ --expected-proof-identity-digest "$EXPECTED_PROOF_DIGEST" \ --release-epoch v1.7.2 diff --git a/jackal-ln-rat-release b/jackal-ln-rat-release index 67d5259..0a52e95 100755 --- a/jackal-ln-rat-release +++ b/jackal-ln-rat-release @@ -21,7 +21,13 @@ set -eu ROOT=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) PRODUCER="$ROOT/tools/ln_rat_producer.py" CHECKER="$ROOT/proofs/lean/.lake/build/bin/jackal_cert_check" -MANIFEST="$ROOT/release/MANIFEST.sha256" +# Per-host release identity: a source build on this host produces +# byte-different compiled artifacts (jackal-native + Lean checkers), so it +# carries its own MANIFEST..sha256. The macOS arm64 manifest remains +# the default when no host-specific one is present. +HOST_TAG="$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m)" +MANIFEST="$ROOT/release/MANIFEST.$HOST_TAG.sha256" +[ -f "$MANIFEST" ] || MANIFEST="$ROOT/release/MANIFEST.sha256" PROOF_ID="$ROOT/release/evidence/range_proof_identity_v172.json" INVENTORY="$ROOT/release/coverage/formal_coverage_inventory.json" diff --git a/jackal-sin-rat-release b/jackal-sin-rat-release index da3ee06..f174419 100755 --- a/jackal-sin-rat-release +++ b/jackal-sin-rat-release @@ -21,7 +21,13 @@ set -eu ROOT=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) PRODUCER="$ROOT/tools/sin_rat_producer.py" CHECKER="$ROOT/proofs/lean/.lake/build/bin/jackal_cert_check" -MANIFEST="$ROOT/release/MANIFEST.sha256" +# Per-host release identity: a source build on this host produces +# byte-different compiled artifacts (jackal-native + Lean checkers), so it +# carries its own MANIFEST..sha256. The macOS arm64 manifest remains +# the default when no host-specific one is present. +HOST_TAG="$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m)" +MANIFEST="$ROOT/release/MANIFEST.$HOST_TAG.sha256" +[ -f "$MANIFEST" ] || MANIFEST="$ROOT/release/MANIFEST.sha256" PROOF_ID="$ROOT/release/evidence/range_proof_identity_v172.json" INVENTORY="$ROOT/release/coverage/formal_coverage_inventory.json" diff --git a/jackal-sqrt-rat-release b/jackal-sqrt-rat-release index 6a58efc..3b0d988 100755 --- a/jackal-sqrt-rat-release +++ b/jackal-sqrt-rat-release @@ -20,7 +20,13 @@ set -eu ROOT=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) PRODUCER="$ROOT/tools/sqrt_rat_producer.py" CHECKER="$ROOT/proofs/lean/.lake/build/bin/jackal_cert_check" -MANIFEST="$ROOT/release/MANIFEST.sha256" +# Per-host release identity: a source build on this host produces +# byte-different compiled artifacts (jackal-native + Lean checkers), so it +# carries its own MANIFEST..sha256. The macOS arm64 manifest remains +# the default when no host-specific one is present. +HOST_TAG="$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m)" +MANIFEST="$ROOT/release/MANIFEST.$HOST_TAG.sha256" +[ -f "$MANIFEST" ] || MANIFEST="$ROOT/release/MANIFEST.sha256" PROOF_ID="$ROOT/release/evidence/range_proof_identity_v172.json" INVENTORY="$ROOT/release/coverage/formal_coverage_inventory.json" diff --git a/jackal-tanh-rat-release b/jackal-tanh-rat-release index 69863f3..12082fd 100755 --- a/jackal-tanh-rat-release +++ b/jackal-tanh-rat-release @@ -22,7 +22,13 @@ set -eu ROOT=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) PRODUCER="$ROOT/tools/tanh_rat_producer.py" CHECKER="$ROOT/proofs/lean/.lake/build/bin/jackal_cert_check" -MANIFEST="$ROOT/release/MANIFEST.sha256" +# Per-host release identity: a source build on this host produces +# byte-different compiled artifacts (jackal-native + Lean checkers), so it +# carries its own MANIFEST..sha256. The macOS arm64 manifest remains +# the default when no host-specific one is present. +HOST_TAG="$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m)" +MANIFEST="$ROOT/release/MANIFEST.$HOST_TAG.sha256" +[ -f "$MANIFEST" ] || MANIFEST="$ROOT/release/MANIFEST.sha256" PROOF_ID="$ROOT/release/evidence/range_proof_identity_v172.json" INVENTORY="$ROOT/release/coverage/formal_coverage_inventory.json" diff --git a/plugins/jackel/.mcp.json b/plugins/jackel/.mcp.json index d4cd6f1..06a0065 100644 --- a/plugins/jackel/.mcp.json +++ b/plugins/jackel/.mcp.json @@ -1,9 +1,9 @@ { "mcpServers": { "jackel": { - "command": "/bin/zsh", + "command": "/bin/sh", "args": [ - "./scripts/launch_mcp.zsh" + "./scripts/launch_mcp.sh" ], "cwd": ".", "env_vars": [ diff --git a/plugins/jackel/PLUGIN_IDENTITY.sha256 b/plugins/jackel/PLUGIN_IDENTITY.sha256 index 82f0076..c17cd1f 100644 --- a/plugins/jackel/PLUGIN_IDENTITY.sha256 +++ b/plugins/jackel/PLUGIN_IDENTITY.sha256 @@ -1,8 +1,9 @@ 49bbd046759b045add1caf1f19300431fe7d697b59bfd93b57daf1d7edb709ff .codex-plugin/plugin.json -23d3c34f6714de5e1ff42f5221e575f5a97d293dbd60cb9613b8734db8bad1de .mcp.json -013f2a0393efc01d724d28ddb22fb5c324378e0c2333de45b8565e45124ea1ea README.md -d307e3534e3451e59f9955ef2aac459bfb8c2d72239aa2325641d0487064f5f5 mcp/server.py -4a5d54ab2300d8e3c2ec15fbea56bcc157ab084bf45233367d4864cb7316cc75 scripts/launch_mcp.zsh -618cd70b0b9005759ad8392e0c455c527e6d2b84e81d0caac66d6e5c088cf552 scripts/provision_runtime.py +a165e6b00292a3768ad134562539dabf7874cf23bf9ac8f80e893f7970a63cdc .mcp.json +13da0c677be5eb6161c21415fc280cbc07af9263f0356ebab77e715f0ef600d7 README.md +b5916270588db1fbb68b4d520c5f5e9d0fabb84e26602f18ad0a2927a38cece9 mcp/server.py +e4fb2996fc2a905a5101974ad6119e6c29fbc10cc8ca2f0223e18f89686dcdff scripts/launch_mcp.sh +878a9d94788a6c132fad151bbddebecb41c08615fe310278e586871fe8f9c44c scripts/launch_mcp.zsh +642228579919b5bf08c799c10b86467b2684e63253730ceda2cff1026a6e9537 scripts/provision_runtime.py 60f6a068c5f6bd81a2ab80e8d9d873864aefdf7f6ae7c2db37fe6572b41f898f scripts/verify_plugin.py -75211a141c502c2f6c4ca54f88f07b2d13b87475f4837b3335f43c15f7da42dc skills/jackel/SKILL.md +63f726fbde9e4484424388ef5af68dce92d7f55a4af9354e7d812833f090c972 skills/jackel/SKILL.md diff --git a/plugins/jackel/README.md b/plugins/jackel/README.md index b93a8b1..f9ef5c8 100644 --- a/plugins/jackel/README.md +++ b/plugins/jackel/README.md @@ -1,7 +1,9 @@ # JACKAL for Codex (legacy package ID `jackel`) -This repo-local Codex plugin exposes the JACKAL v1.7.3 release runtime on Apple -Silicon macOS. Its current source contract is the ordered 41-tool inventory in +This repo-local Codex plugin exposes the JACKAL v1.7.3 release runtime. The +installer supports Darwin/arm64 and Linux/aarch64; only the macOS-arm64 release +asset is published today, so Linux hosts must supply a locally built runtime and +its own pins. Its current source contract is the ordered 41-tool inventory in `release/capability_inventory_v1.json`; the package receipt and downloaded release asset must bind the same exact bytes. @@ -21,19 +23,20 @@ absolute path for an offline installation: codex plugin marketplace add /absolute/path/to/jackal codex plugin add jackel@anubis-quantum-cipher cd /absolute/path/to/the/installed/jackel/plugin -/bin/zsh scripts/launch_mcp.zsh provision +/bin/sh scripts/launch_mcp.sh provision # Offline alternative: -# /bin/zsh scripts/launch_mcp.zsh provision --tarball \ +# /bin/sh scripts/launch_mcp.sh provision --tarball \ # /absolute/path/to/jackal-v1.7.3-macos-arm64.tar.gz -/bin/zsh scripts/launch_mcp.zsh provision --check +/bin/sh scripts/launch_mcp.sh provision --check codex mcp list --json ``` Require exactly 41 unique JACKAL tool names and an MCP working directory bound to the installed plugin copy. Python 3.10 or newer at -`/opt/homebrew/bin/python3` is the supported prerequisite; the launcher also -accepts the two other fixed absolute candidates only when they pass its full -capability probe. It never searches caller `PATH`. +`/opt/homebrew/bin/python3` (macOS) or `/usr/bin/python3` (Linux) is the +supported prerequisite; the launcher accepts any of its three fixed absolute +candidates that pass the full capability probe, which includes the host's +atomic no-replace rename symbol. It never searches caller `PATH`. ## Routing @@ -63,9 +66,9 @@ establish runtime behavior. From the JACKAL repository root: ```bash -/opt/homebrew/bin/python3 -B plugins/jackel/scripts/verify_plugin.py -/opt/homebrew/bin/python3 -B tools/capability_drift_gate.py -/opt/homebrew/bin/python3 -B -m unittest discover -s tests/codex_plugin -v +python3 -B plugins/jackel/scripts/verify_plugin.py +python3 -B tools/capability_drift_gate.py +python3 -B -m unittest discover -s tests/codex_plugin -v ``` The wrapper identity manifest is tamper evidence bound to a separately trusted diff --git a/plugins/jackel/mcp/server.py b/plugins/jackel/mcp/server.py index 17a6c60..86b83dd 100644 --- a/plugins/jackel/mcp/server.py +++ b/plugins/jackel/mcp/server.py @@ -107,6 +107,8 @@ class _ProvisionerAPI(Protocol): ASSET: str PACKAGE_SIZE: int PACKAGE_SHA256: str + + def effective_release_pins(self) -> dict: ... SHA256SUMS_SHA256: str SELFTEST_TIMEOUT: float SELFTEST_OUTPUT_LIMIT: int @@ -856,13 +858,14 @@ def resolve_runtime_path( expected_keys = {"schema", "epoch", "runtime_path", "package_size", "package_sha256"} if set(document) != expected_keys: raise StartupError("runtime locator has an unsupported shape") + _pins = provisioner.effective_release_pins() if ( document["schema"] != "jackal-codex-plugin-runtime-v1" - or document["epoch"] != provisioner.EPOCH - or document["package_size"] != provisioner.PACKAGE_SIZE - or document["package_sha256"] != provisioner.PACKAGE_SHA256 + or document["epoch"] != _pins["epoch"] + or document["package_size"] != _pins["package_size"] + or document["package_sha256"] != _pins["package_sha256"] ): - raise StartupError("runtime locator does not match wrapper-side release pins") + raise StartupError("runtime locator does not match this host's release pins") return _canonical_absolute_directory(document["runtime_path"], subject="located runtime") @@ -872,12 +875,13 @@ def _verify_package_metadata(runtime: Path, provisioner: _ProvisionerAPI) -> Non limit=16 * 1024, subject="runtime package metadata", ) + _pins = provisioner.effective_release_pins() expected = { "schema": "jackal-runtime-package-v1", - "epoch": provisioner.EPOCH, - "asset": provisioner.ASSET, - "package_size": provisioner.PACKAGE_SIZE, - "package_sha256": provisioner.PACKAGE_SHA256, + "epoch": _pins["epoch"], + "asset": _pins["asset"], + "package_size": _pins["package_size"], + "package_sha256": _pins["package_sha256"], } if document != expected: raise StartupError("runtime package metadata does not match wrapper-side release pins") diff --git a/plugins/jackel/scripts/launch_mcp.sh b/plugins/jackel/scripts/launch_mcp.sh new file mode 100755 index 0000000..4ab76c6 --- /dev/null +++ b/plugins/jackel/scripts/launch_mcp.sh @@ -0,0 +1,66 @@ +#!/bin/sh +# Portable launcher for the JACKAL MCP adapter. +# +# Behaviourally identical to launch_mcp.zsh: it never searches the caller PATH, +# probes a fixed list of absolute interpreters, and execs the first one that +# passes the full capability probe. Written in POSIX sh so the plugin runs on +# hosts without zsh. + +set -u + +# Fixed absolute candidates only. The caller PATH is never consulted. +PYTHON_CANDIDATES="/opt/homebrew/bin/python3 +/usr/local/bin/python3 +/usr/bin/python3" + +script_path=$0 +case $script_path in + /*) ;; + *) script_path=$PWD/$script_path ;; +esac +# Parameter expansion only: `dirname` is an external command and the caller +# PATH is deliberately untrusted, so resolving the plugin root must not depend +# on anything outside the shell itself. `cd` and `pwd` are builtins. +scripts_dir=${script_path%/*} +plugin_root=$(CDPATH= cd -- "$scripts_dir/.." && pwd -P) || exit 126 + +target="$plugin_root/mcp/server.py" +if [ "$#" -gt 0 ]; then + if [ "$1" != "provision" ]; then + printf '%s\n' "jackal_mcp=refused reason=invalid-launcher-arguments" >&2 + exit 64 + fi + shift + target="$plugin_root/scripts/provision_runtime.py" +fi + +probe='import ctypes, os, platform, selectors, signal, socket, sys, tarfile, urllib.request +from pathlib import Path +assert sys.version_info >= (3, 10) +required_os = ("CLD_DUMPED", "CLD_EXITED", "CLD_KILLED", "O_CREAT", "O_DIRECTORY", "O_EXCL", "O_NOFOLLOW", "O_NONBLOCK", "O_RDONLY", "O_WRONLY", "P_PID", "WEXITED", "WNOHANG", "WNOWAIT", "access", "dup", "fchmod", "fstat", "fsync", "killpg", "lseek", "mkdir", "open", "read", "replace", "scandir", "set_blocking", "stat", "waitid", "write") +assert all(hasattr(os, name) for name in required_os) +assert hasattr(socket, "socketpair") +libc = ctypes.CDLL(None) +atomic_rename = {"Darwin": "renameatx_np", "Linux": "renameat2"}.get(platform.system()) +assert atomic_rename is not None +assert callable(getattr(libc, atomic_rename, None)) +platform.system(); platform.machine(); Path("/").is_absolute() +selector = selectors.DefaultSelector(); selector.close() +assert callable(signal.setitimer) and callable(signal.getitimer) +assert signal.ITIMER_REAL >= 0 and signal.SIGALRM > 0 +assert callable(tarfile.open) and callable(urllib.request.urlopen)' + +PYTHONDONTWRITEBYTECODE=1 +export PYTHONDONTWRITEBYTECODE + +IFS=' +' +for python in $PYTHON_CANDIDATES; do + if [ -f "$python" ] && [ -x "$python" ] && \ + "$python" -I -S -B -c "$probe" /dev/null 2>/dev/null; then + exec "$python" -I -S -B "$target" "$@" + fi +done + +printf '%s\n' "jackal_mcp=refused reason=no-compatible-python requirement='Python >=3.10 with an atomic no-replace rename (Darwin renameatx_np / Linux renameat2) at one of the fixed candidate paths' recovery='macOS: brew install python | Linux: install a distribution python3 >=3.10 at /usr/bin/python3'" >&2 +exit 126 diff --git a/plugins/jackel/scripts/launch_mcp.zsh b/plugins/jackel/scripts/launch_mcp.zsh index 564f3f3..110e97c 100755 --- a/plugins/jackel/scripts/launch_mcp.zsh +++ b/plugins/jackel/scripts/launch_mcp.zsh @@ -26,7 +26,9 @@ required_os = ("CLD_DUMPED", "CLD_EXITED", "CLD_KILLED", "O_CREAT", "O_DIRECTORY assert all(hasattr(os, name) for name in required_os) assert hasattr(socket, "socketpair") libc = ctypes.CDLL(None) -assert callable(getattr(libc, "renameatx_np", None)) +atomic_rename = {"Darwin": "renameatx_np", "Linux": "renameat2"}.get(platform.system()) +assert atomic_rename is not None +assert callable(getattr(libc, atomic_rename, None)) platform.system(); platform.machine(); Path("/").is_absolute() selector = selectors.DefaultSelector(); selector.close() assert callable(signal.setitimer) and callable(signal.getitimer) @@ -41,5 +43,5 @@ for python in "${PYTHON_CANDIDATES[@]}"; do fi done -print -u2 -r -- "jackal_mcp=refused reason=no-compatible-python requirement='Python >=3.10 at /opt/homebrew/bin/python3' recovery='brew install python'" +print -u2 -r -- "jackal_mcp=refused reason=no-compatible-python requirement='Python >=3.10 with an atomic no-replace rename (Darwin renameatx_np / Linux renameat2) at one of the fixed candidate paths' recovery='macOS: brew install python | Linux: install a distribution python3 >=3.10 at /usr/bin/python3'" exit 126 diff --git a/plugins/jackel/scripts/provision_runtime.py b/plugins/jackel/scripts/provision_runtime.py index 932f42a..e386046 100644 --- a/plugins/jackel/scripts/provision_runtime.py +++ b/plugins/jackel/scripts/provision_runtime.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Install the one pinned JACKAL macOS arm64 runtime, fail closed.""" +"""Install the one pinned JACKAL runtime for a supported host, fail closed.""" from __future__ import annotations @@ -36,6 +36,40 @@ EXTRACTED_SIZE = 555511970 SHA256SUMS_SHA256 = "a78fc05e2ebd56f31263d54ccdbf7fcc2ff92d270758720c3e235d5a3121568a" PACKAGE_DIRECTORY = "jackal-v1.7.3-macos-arm64" + +# A host is supported only when its atomic no-replace install primitive and its +# release pin are both known. Adding a row is not enough to make a runtime +# exist: RELEASE_PINS decides whether an asset has actually been published. +SUPPORTED_HOSTS = { + ("Darwin", "arm64"): "macos-arm64", + ("Linux", "aarch64"): "linux-aarch64", +} + +# ``None`` means "this host is supported by the installer but no release asset +# has been published for it yet". It must refuse, never fall back to another +# host's bytes. +RELEASE_PINS: dict[str, dict[str, object] | None] = { + "macos-arm64": { + "asset": ASSET, + "url": URL, + "package_size": PACKAGE_SIZE, + "package_sha256": PACKAGE_SHA256, + "extracted_size": EXTRACTED_SIZE, + "sha256sums_sha256": SHA256SUMS_SHA256, + "package_directory": PACKAGE_DIRECTORY, + }, + "linux-aarch64": { + # Locally built runtime (source build on this host). No published + # upstream asset — install with `provision --tarball `. + "asset": "jackal-v1.7.3-linux-aarch64.tar.gz", + "url": None, + "package_size": 177404638, + "package_sha256": "d4618d6e153ff1a94ca7a064995e346c10874fe0e2b1afafdb19ef7b2cdb2720", + "extracted_size": 686413084, + "sha256sums_sha256": "d33dd68643c55db7014a48296371bdfadd748d5218b6a859899b2c578ad26256", + "package_directory": "jackal-v1.7.3-linux-aarch64", + }, +} MAX_ARCHIVE_MEMBERS = 8192 MAX_RUNTIME_RECORDS = MAX_ARCHIVE_MEMBERS MAX_RUNTIME_ENTRIES = MAX_ARCHIVE_MEMBERS + 2 @@ -48,8 +82,14 @@ DOWNLOAD_TOTAL_TIMEOUT = 300.0 SELFTEST_TIMEOUT = 30.0 SELFTEST_OUTPUT_LIMIT = 64 * 1024 -SNAPSHOT_BYTE_LIMIT = EXTRACTED_SIZE + 1024 * 1024 -MAX_RUNTIME_FILE_BYTES = EXTRACTED_SIZE +# Byte caps bound extraction/verification against zip-bomb inputs. They must fit +# the LARGEST supported runtime (RELEASE_PINS is defined above), not only macOS; +# exact integrity stays pinned by each host's extracted_size and SHA256SUMS. +_MAX_SUPPORTED_EXTRACTED = max( + [EXTRACTED_SIZE] + [pin["extracted_size"] for pin in RELEASE_PINS.values() if pin] +) +SNAPSHOT_BYTE_LIMIT = _MAX_SUPPORTED_EXTRACTED + 1024 * 1024 +MAX_RUNTIME_FILE_BYTES = _MAX_SUPPORTED_EXTRACTED MAX_RUNTIME_TOTAL_BYTES = SNAPSHOT_BYTE_LIMIT RUNTIME_ENV_ALLOWLIST = ("JACKAL_HOME",) FIXED_SYSTEM_PATH = "/usr/bin:/bin:/usr/sbin:/sbin" @@ -65,21 +105,84 @@ class _LeaderAnchorLost(ProvisionError): pass -def default_runtime_target(home: Path | None = None) -> Path: +def _data_home(root: Path, system: str | None = None) -> Path: + """Per-host application data root. + + Fixed by platform, never read from the environment: the launcher sanitizes + the environment down to RUNTIME_ENV_ALLOWLIST, so an installer path that + honoured XDG_DATA_HOME would be attacker-influenced on exactly the hosts + that need it least. + """ + actual_system = platform.system() if system is None else system + if actual_system == "Darwin": + return root / "Library/Application Support" + return root / ".local/share" + + +def default_runtime_target(home: Path | None = None, system: str | None = None) -> Path: root = Path.home() if home is None else Path(home) - return root / "Library/Application Support/JACKAL/runtimes" / EPOCH + return _data_home(root, system) / "JACKAL/runtimes" / EPOCH -def default_locator_path(home: Path | None = None) -> Path: +def default_locator_path(home: Path | None = None, system: str | None = None) -> Path: root = Path.home() if home is None else Path(home) - return root / "Library/Application Support/JACKAL/codex-plugin/runtime.json" + return _data_home(root, system) / "JACKAL/codex-plugin/runtime.json" -def validate_host(system: str | None = None, machine: str | None = None) -> None: +def resolve_host(system: str | None = None, machine: str | None = None) -> str: + """Return the release host tag, or refuse. Never guesses a nearby host.""" actual_system = platform.system() if system is None else system actual_machine = platform.machine() if machine is None else machine - if actual_system != "Darwin" or actual_machine != "arm64": - raise ProvisionError(f"unsupported host: {actual_system}/{actual_machine}; requires Darwin/arm64") + tag = SUPPORTED_HOSTS.get((actual_system, actual_machine)) + if tag is None: + supported = ", ".join( + f"{key[0]}/{key[1]}" for key in sorted(SUPPORTED_HOSTS) + ) + raise ProvisionError( + f"unsupported host: {actual_system}/{actual_machine}; requires one of {supported}" + ) + return tag + + +def validate_host(system: str | None = None, machine: str | None = None) -> None: + resolve_host(system, machine) + + +def effective_release_pins(system: str | None = None, machine: str | None = None) -> dict[str, object]: + """The (epoch, asset, size, sha256, directory) this host installs/serves. + + Falls back to the built-in macOS constants when the host has a published + pin identical to them; otherwise returns the host's own release pin values. + Used by the MCP server so its locator/metadata checks match whatever the + provisioner actually installed on this host. + """ + host_tag = resolve_host(system, machine) + pin = RELEASE_PINS.get(host_tag) + if not pin: + return { + "epoch": EPOCH, "asset": ASSET, + "package_size": PACKAGE_SIZE, "package_sha256": PACKAGE_SHA256, + "package_directory": PACKAGE_DIRECTORY, + } + return { + "epoch": EPOCH, "asset": pin["asset"], + "package_size": pin["package_size"], "package_sha256": pin["package_sha256"], + "package_directory": pin["package_directory"], + } + + +def release_pin(host_tag: str) -> dict[str, object]: + """Return the published release pin for a host, or refuse.""" + try: + pin = RELEASE_PINS[host_tag] + except KeyError: + raise ProvisionError(f"no release pin table entry for host {host_tag}") from None + if pin is None: + raise ProvisionError( + f"no published release asset for host {host_tag}; " + "supply a locally built runtime and its pins instead" + ) + return pin def runtime_subprocess_environment( @@ -1352,6 +1455,18 @@ def _verify_outer_file(path: Path, expected_size: int, expected_sha256: str): raise +# macOS renameatx_np(2) flag; Linux renameat2(2) flag. Both mean the same +# thing: rename atomically and fail with EEXIST rather than clobber the target. +_RENAME_EXCL = 0x00000004 +_RENAME_NOREPLACE = 0x00000001 + + +def _raise_rename_error(error_number: int, target_name: str) -> None: + if error_number == errno.EEXIST: + raise FileExistsError(error_number, os.strerror(error_number), target_name) + raise OSError(error_number, os.strerror(error_number), target_name) + + def _renameatx_np_exclusive( source_parent_fd: int, source_name: str, @@ -1364,18 +1479,68 @@ def _renameatx_np_exclusive( renameatx = libc.renameatx_np renameatx.argtypes = [ctypes.c_int, ctypes.c_char_p, ctypes.c_int, ctypes.c_char_p, ctypes.c_uint] renameatx.restype = ctypes.c_int + ctypes.set_errno(0) result = renameatx( source_parent_fd, os.fsencode(source_name), target_parent_fd, os.fsencode(target_name), - 0x00000004, + _RENAME_EXCL, ) if result != 0: - error_number = ctypes.get_errno() - if error_number == errno.EEXIST: - raise FileExistsError(error_number, os.strerror(error_number), target_name) - raise OSError(error_number, os.strerror(error_number), target_name) + _raise_rename_error(ctypes.get_errno(), target_name) + + +def _renameat2_noreplace( + source_parent_fd: int, + source_name: str, + target_parent_fd: int, + target_name: str, +) -> None: + """Linux equivalent of renameatx_np(..., RENAME_EXCL). + + RENAME_NOREPLACE carries the same guarantee: the rename is atomic and fails + with EEXIST rather than replacing an existing target. Filesystems that do + not implement the flag report EINVAL or ENOSYS, which propagates as a + refusal -- there is deliberately no fallback to a clobbering rename. + """ + if platform.system() != "Linux": + raise ProvisionError("renameat2 no-replace installation requires Linux") + libc = ctypes.CDLL(None, use_errno=True) + renameat2 = getattr(libc, "renameat2", None) + if renameat2 is None: + raise ProvisionError( + "atomic no-replace installation requires glibc renameat2 (glibc >= 2.28)" + ) + renameat2.argtypes = [ctypes.c_int, ctypes.c_char_p, ctypes.c_int, ctypes.c_char_p, ctypes.c_uint] + renameat2.restype = ctypes.c_int + ctypes.set_errno(0) + result = renameat2( + source_parent_fd, + os.fsencode(source_name), + target_parent_fd, + os.fsencode(target_name), + _RENAME_NOREPLACE, + ) + if result != 0: + _raise_rename_error(ctypes.get_errno(), target_name) + + +_RENAME_EXCLUSIVE_BY_SYSTEM = { + "Darwin": _renameatx_np_exclusive, + "Linux": _renameat2_noreplace, +} + + +def rename_exclusive_for_host(system: str | None = None) -> Callable: + """Select the atomic no-replace primitive for this host, or refuse.""" + actual_system = platform.system() if system is None else system + operation = _RENAME_EXCLUSIVE_BY_SYSTEM.get(actual_system) + if operation is None: + raise ProvisionError( + f"atomic no-replace installation is unsupported on {actual_system}" + ) + return operation def _install_no_replace( @@ -1386,7 +1551,7 @@ def _install_no_replace( ) -> None: source_path = Path(source) target_path = Path(target) - operation = _renameatx_np_exclusive if rename_exclusive is None else rename_exclusive + operation = rename_exclusive_for_host() if rename_exclusive is None else rename_exclusive source_parent_fd = -1 target_parent_fd = -1 try: @@ -1428,7 +1593,26 @@ def provision( install_no_replace: Callable | None = None, ) -> Path: """Validate or atomically install the pinned runtime.""" - validate_host(system, machine) + host_tag = resolve_host(system, machine) + relying_on_builtin_pins = ( + asset == ASSET + and url == URL + and expected_size == PACKAGE_SIZE + and expected_sha256 == PACKAGE_SHA256 + ) + if relying_on_builtin_pins: + # The caller is relying on the built-in pins rather than supplying its + # own. Bind them to THIS host's published release pin (refusing when no + # asset exists for the host) instead of letting another host's bytes + # reach the hash check and surface as a confusing digest mismatch. + pin = release_pin(host_tag) + asset = pin["asset"] + url = pin["url"] if pin["url"] is not None else url + expected_size = pin["package_size"] + expected_sha256 = pin["package_sha256"] + expected_extracted_size = pin["extracted_size"] + expected_tree_sha256 = pin["sha256sums_sha256"] + expected_top_level = pin["package_directory"] if ( expected_size < 0 or expected_extracted_size < 0 @@ -1564,8 +1748,12 @@ def main(argv: list[str] | None = None) -> int: except Exception: print("jackal_runtime=refused detail=unexpected provisioning failure", file=sys.stderr) return 1 + try: + _sha = effective_release_pins()["package_sha256"] + except ProvisionError: + _sha = PACKAGE_SHA256 print( - f"jackal_runtime=ready epoch={EPOCH} runtime={runtime} package_sha256={PACKAGE_SHA256}" + f"jackal_runtime=ready epoch={EPOCH} runtime={runtime} package_sha256={_sha}" ) return 0 diff --git a/plugins/jackel/skills/jackel/SKILL.md b/plugins/jackel/skills/jackel/SKILL.md index c0447aa..4f8b2fb 100644 --- a/plugins/jackel/skills/jackel/SKILL.md +++ b/plugins/jackel/skills/jackel/SKILL.md @@ -12,7 +12,7 @@ capability-name and status source; the release tag, package receipt, and asset must bind the same exact bytes. -JACKAL exposes the full tool inventory on Apple Silicon macOS. Use it to +JACKAL exposes the full tool inventory on its supported hosts. Use it to classify a quantitative claim, select the strongest admitted evidence lane, and preserve the exact assurance boundary returned by the runtime. @@ -121,27 +121,37 @@ Do not turn `refused` or `indeterminate` into an MCP error or a plausible number. Do not summarize away route traces, assumptions, receipt identities, checker verdicts, or residual non-claims. -## macOS runtime +## Host runtime -This plugin supports Apple Silicon macOS only and uses the pinned v1.7.3 -candidate macOS-arm64 runtime. Until that candidate is published, provision it -from the separately verified local tarball path. -Do not bypass the Darwin/arm64 host guard or substitute another platform build. +The installer supports exactly two hosts, Darwin/arm64 and Linux/aarch64, and +each is admitted only because its atomic no-replace install primitive is +implemented (`renameatx_np` with `RENAME_EXCL` on Darwin, `renameat2` with +`RENAME_NOREPLACE` on Linux). Do not bypass the host guard or substitute +another platform build. -Python >=3.10 at `/opt/homebrew/bin/python3` is the supported fixed-path -prerequisite on Apple Silicon. If it is absent or fails the launcher's -capability probe, install it with `brew install python`, then rerun the same -launcher command. The launcher also probes `/usr/local/bin/python3` and -`/usr/bin/python3` when either already satisfies the complete contract; it -never searches caller `PATH`. +A supported host is not a published runtime. Only the macOS-arm64 release +asset is published today; on Linux/aarch64 the release table carries no pin, so +provisioning refuses with `no published release asset for host linux-aarch64` +rather than installing another host's bytes. Provision it from a separately +verified local tarball and its own pins. + +Python >=3.10 is the fixed-path prerequisite: `/opt/homebrew/bin/python3` on +Apple Silicon (install with `brew install python`), or `/usr/bin/python3` on +Linux. The launcher probes `/opt/homebrew/bin/python3`, `/usr/local/bin/python3` +and `/usr/bin/python3` in that order, accepts the first that satisfies the +complete capability probe including the host's atomic rename symbol, and never +searches caller `PATH`. When provisioning is requested, run from the plugin root: ```bash -/bin/zsh scripts/launch_mcp.zsh provision -/bin/zsh scripts/launch_mcp.zsh provision --check -/bin/zsh scripts/launch_mcp.zsh provision --tarball /absolute/path/to/jackal-v1.7.3-macos-arm64.tar.gz +/bin/sh scripts/launch_mcp.sh provision +/bin/sh scripts/launch_mcp.sh provision --check +/bin/sh scripts/launch_mcp.sh provision --tarball /absolute/path/to/jackal-v1.7.3-macos-arm64.tar.gz ``` +`scripts/launch_mcp.zsh` remains available for hosts that prefer it; both +launchers carry a byte-identical capability probe. + The default MCP bridge reads the verified runtime locator. Set `JACKAL_HOME` only to an independently verified, canonical absolute runtime directory. diff --git a/release/MANIFEST.linux-aarch64.sha256 b/release/MANIFEST.linux-aarch64.sha256 new file mode 100644 index 0000000..b514d8a --- /dev/null +++ b/release/MANIFEST.linux-aarch64.sha256 @@ -0,0 +1,49 @@ +# JACKAL v1.7.3 pinned release identities (v1.7.2 proof/claim/domain lanes + inventory-safe Anubis program evidence) +evaluator jackal-native 4c0ae28d2f41353332dbb29f1b6084cd275d08bad73a84942fbe6f500255d872 +checker jackal_cert_check 89e4e42d8daa57d4a9a19f9b95b29bd5e96fae5ad7060ac3adf355f1dfeb870c +archival-v170-archive-source github-release-v1.7.0 21c7ede586f30a58772f321f7dbb36ab66213e199785489f99133710ac56096e +archival-range-checker jackal_cert_check_v170 05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a +archival-range-coverage-inventory formal_coverage_inventory_v170.json 18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6 +archival-plugin-hermes v1.7.0-plugin d141c909e8f5f03e268a2112f291e6bd79fafff906522eb7ca9accc247a3274b +gaussian-producer tools/gaussian_certificate.py 20c24622b786940a8e82198f2364fb7593e761902fa0736289b179642f1e4306 +gaussian-checker jackal_gaussian_check 1f21c6b2e41c171414405c0aa6fee089851716d1add707727ace45395f4ed379 +range-proof-identity release/evidence/range_proof_identity_v172.linux-aarch64.json c6caed2434cbd77cba19bb0279936bfa322a696301e6d20c932a9b412f2fa0ca +range-proof-digest e373a459c1ddbd87be1b8bb881440338872a527cf1805d13340833e2e7d098d1 +archival-range-proof-identity release/evidence/range_proof_identity.json 1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67 +archival-range-proof-digest 5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e +gaussian-proof-identity release/evidence/gaussian_proof_identity.linux-aarch64.json 610624b48f48dcd089e0ad14ddac7ebbc25071e7d70cc8516ad6c3c09c747404 +gaussian-proof-digest 489780aab2b7b5f16bc529b141c5c7967a9307cbc539c3fff8eab9f0789263fe +lean-admission-audit release/evidence/lean_admission_audit_v173.json cabda2a1fb8c021ce384d9c2267f52f98e6799bb50b6b828e7d9eefa55bf2b2e +lean-admission-audit-digest 5e33809e2d8f73d8b554313bc9ea71a8b8d3c657810f0b37d4db3dd945578f29 +int-cert-producer tools/int_cert_producer.py b4240fdac3c77b2abd751595303b2b3a0e4bebd492b2ae57fa5ccf052cd50af4 +int-cert-checker jackal_int_cert_check f2e26f506f921b577fd8609a095b69789b3b76cce65d8c293d1a11f3007a8078 +int-cert-proof-identity release/evidence/int_cert_proof_identity_v172.linux-aarch64.json 533c5cc4718331e2739ec92513487842aa48471b4b7d1be57db08999a9d90f95 +int-cert-proof-digest a024ab9cb1010721297703bab38a0e43a7a48ac65b0c1d71292599e813e3dad9 +revoked-int-cert-proof-identity-reference release/evidence/int_cert_proof_identity.json f0323e312d8b0e05a7200546fd819fc191d5f146d359bb14efec5b1575f16844 +compatibility-floor release/compat/v172_floor.json 1a7baa000a86a07189df2cec73258db431cd5ab66e80465c5770b980e0ee4f61 +program-compatibility-floor release/compat/v173_floor.json 5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e +range-ordering-aba release/evidence/range_ordering_aba_v172.json 02e08fcc26b0099ff49064f3e3a5c3147ccda51a4ee9f67aad372ee743bdd071 +int-cert-premise-aba release/evidence/int_cert_premise_aba_v172.json b07c501a98277b03d880ba1d131af79f3cb3baacbde3e623df755f2fab860f45 +coverage-inventory release/coverage/formal_coverage_inventory.json 6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6 +build-environment release/evidence/build_environment_v170.json b71fbee10dd83fab7e389d07eadd92e1bff431585f11be5b6887e789f063109d +source jackal_calc.anb f579b6f59bc024d24914487b0cd0f18ea43dea1be52708a05a66dc885d80bb4e +compiler_pin anubis-c6affa8c0ae7 c6affa8c0ae7b1f9e2d3fe18ff712b3f35982a5164eef626f25e90628f4497fc +plugin_hermes c6a27483077b89d899d8c73c03bfeb3191f25db2a22f8021254a7dec763ba5fe +sqrt_rat_producer tools/sqrt_rat_producer.py 4bc95c331430d2350facfb19da9aba483ab7b3698754e7af2e5deb797e097926 +exp_rat_producer tools/exp_rat_producer.py 1997ed81dfbd26a6d45a6689c515832bfbae05435d07e3dd2d6f156c57668ec1 +ln_rat_producer tools/ln_rat_producer.py c88eb0153f0ec0ba401597a8945345e621a38df408bfd92a47a4b3abf7985740 +sin_rat_producer tools/sin_rat_producer.py 978f8d508c0921b5d8227a24ee7c7b97373a6041e55e4923cd94617a94a061dd +atan_rat_producer tools/atan_rat_producer.py 824916bdb3420986f4a6eed8028760a96477e9e1df2febd03b9ca174216aef26 +tanh_rat_producer tools/tanh_rat_producer.py da03b6054dcdd3fe02588ec25fc7c201405e9d8ec5f3ab46ff45b49698ab5eb3 +exact_verifier tools/exact_verify.py 2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7 +claim_kernel tools/claim_kernel.py 77b0f85ad5fb7214f88898b60ea29ea9fd7be740c38b655388444e6e5181f348 +claim_router tools/claim_router.py 02328cf177a0423bdc5cbca6ec0ea946bb0679bbd3dc6c24140d32598e575afb +claim_verifier tools/claim_bundle_verify.py e0fcb9540c730bd9bb492b528ed42d29d49fc775b3aa0f9b831b6264fd68fd22 +domain_pack_registry domain_packs/registry_v1.json 1a3b2c95dcdc7c7337fbe0ecb34043b70c3697752d6dc585f45f3c7d4f1b0706 +domain_pack_verifier tools/domain_pack_verify.py 22984f511208af2d7a318f1a43306d95a4b0f61876d8b44f34f39a2ded6d573d +domain_pack_test_exists_checker tools/test_exists_verify.py 598cb99e1eb70c9410ca87345efee346f73e43aaf3625427dca17ea04231caea +domain_pack_decision_checker tools/decision_verify.py f1ad7c9fbd4c1d899dbb4bebabbbeb97e97a56bd4b279ad7d8ec3722bf12e0f6 +anubis_program_verifier tools/anubis_program_verify.py 4b80e29bdffc0737f05a6e215fce8cce3b6b828c24afbf55c68443399e5119dc +anubis_program_policy release/program/inventory_safe_v1.json 361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb +claim_inference_registry release/claim/inference_registry_v1.json c70b33d5aee8071b5125e6a5f8ffe5226fc22a137d920c17d9b3463968be13f0 +claim_unit_registry release/claim/unit_registry_v1.json d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c diff --git a/release/build_package_linux.sh b/release/build_package_linux.sh new file mode 100755 index 0000000..a872f34 --- /dev/null +++ b/release/build_package_linux.sh @@ -0,0 +1,1328 @@ +#!/bin/sh +# Build the additive JACKAL v1.7.3 Linux aarch64 package (adapted copy). +# +# This builder never rebuilds the evaluator. The sole Anubis compiler +# authority is the immutable, digest-checked pin below. --dry-run validates +# every input and prints the package plan without creating a staging directory +# or touching release/dist. --build is explicit, refuses existing outputs, +# stages on the release filesystem, and publishes only the staged result. +set -eu + +SYSTEM=$(/usr/bin/uname -s) +MACHINE=$(/usr/bin/uname -m) +if [ "$SYSTEM" != "Linux" ] || [ "$MACHINE" != "aarch64" ]; then + echo "PACKAGE_V173_REFUSED reason=unsupported-host system=$SYSTEM machine=$MACHINE expected=Linux/aarch64" >&2 + exit 3 +fi + +ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd) +VER="v1.7.3" +PLATFORM="linux-aarch64" +PKG_NAME="jackal-v1.7.3-linux-aarch64" +TARBALL_NAME="$PKG_NAME.tar.gz" +DIST=${JACKAL_DIST:-"$ROOT/release/dist"} +FINAL_PKG="$DIST/$PKG_NAME" +FINAL_TARBALL="$DIST/$TARBALL_NAME" +case "$DIST" in + /*) ;; + *) + echo "PACKAGE_V173_REFUSED reason=dist-not-absolute path=$DIST" >&2 + exit 5 + ;; +esac +case "/$DIST/" in + */../*|*/./*) + echo "PACKAGE_V173_REFUSED reason=dist-not-canonical path=$DIST" >&2 + exit 5 + ;; +esac +COMPILER=${JACKAL_ANUBIS_COMPILER_PATH:-} +[ -n "$COMPILER" ] || { + echo "PACKAGE_V173_REFUSED reason=compiler-path-unset" >&2 + exit 4 +} +RANGE_CHECKER="$ROOT/proofs/lean/.lake/build/bin/jackal_cert_check" +GAUSSIAN_CHECKER="$ROOT/proofs/lean/.lake/build/bin/jackal_gaussian_check" +INT_CHECKER="$ROOT/proofs/lean/.lake/build/bin/jackal_int_cert_check" +V170_ARCHIVE_URL="https://github.com/AnubisQuantumCipher/jackal/releases/download/v1.7.0/jackal-v1.7.0-macos-arm64.tar.gz" +V170_ARCHIVE_SHA256="21c7ede586f30a58772f321f7dbb36ab66213e199785489f99133710ac56096e" +V170_RANGE_CHECKER_SHA256="05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a" +V170_COVERAGE_INVENTORY_SHA256="18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6" +V170_PLUGIN_HERMES_SHA256="d141c909e8f5f03e268a2112f291e6bd79fafff906522eb7ca9accc247a3274b" + +sha256() { + shasum -a 256 "$1" | /usr/bin/awk '{print $1}' +} + +publish_noreplace() { + python3 -I -S -B - "$1" "$2" <<'PY' +import ctypes +import os +import sys + +import platform +source = os.fsencode(sys.argv[1]) +destination = os.fsencode(sys.argv[2]) +libc = ctypes.CDLL(None, use_errno=True) +# Atomic no-clobber publish: macOS renamex_np(RENAME_EXCL) / Linux +# renameat2(AT_FDCWD, ..., RENAME_NOREPLACE) — same fail-on-EEXIST guarantee. +if platform.system() == "Darwin": + fn = libc.renamex_np + fn.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_uint] + fn.restype = ctypes.c_int + ctypes.set_errno(0) + rc = fn(source, destination, 0x00000004) # RENAME_EXCL +else: + AT_FDCWD = -100 + RENAME_NOREPLACE = 0x00000001 + fn = libc.renameat2 + fn.argtypes = [ctypes.c_int, ctypes.c_char_p, ctypes.c_int, ctypes.c_char_p, ctypes.c_uint] + fn.restype = ctypes.c_int + ctypes.set_errno(0) + rc = fn(AT_FDCWD, source, AT_FDCWD, destination, RENAME_NOREPLACE) +if rc != 0: + error_number = ctypes.get_errno() + print( + "PACKAGE_V173_REFUSED reason=publication-destination-raced " + f"path={sys.argv[2]} errno={error_number} detail={os.strerror(error_number)}", + file=sys.stderr, + ) + raise SystemExit(1) +PY +} + +require_regular() { + [ -f "$1" ] && [ ! -L "$1" ] || { + echo "PACKAGE_V173_REFUSED reason=required-regular-file path=$1" >&2 + exit 4 + } +} + +require_regular "$COMPILER" +COMPILER_SHA256=$(sha256 "$COMPILER") + +REQUIRED_INPUTS=" +jackal-native +jackal_calc.anb +proofs/lean/.lake/build/bin/jackal_cert_check +proofs/lean/.lake/build/bin/jackal_gaussian_check +proofs/lean/.lake/build/bin/jackal_int_cert_check +release/evidence/range_proof_identity_v172.json +release/evidence/int_cert_proof_identity_v172.json +release/evidence/range_proof_identity.json +release/evidence/int_cert_proof_identity.json +release/evidence/gaussian_proof_identity.json +release/evidence/range_proof_identity_v172.linux-aarch64.json +release/evidence/int_cert_proof_identity_v172.linux-aarch64.json +release/evidence/gaussian_proof_identity.linux-aarch64.json +release/evidence/lean_admission_audit_v173.json +release/evidence/lean_admission_audit_v173.linux-aarch64.json +release/capability_inventory_v1.json +release/compat/v172_floor.json +release/compat/v172_floor.linux-aarch64.json +release/compat/v173_floor.json +release/compat/v170_floor.json +release/compat/v150_floor.json +release/evidence/range_ordering_aba_v172.json +release/evidence/int_cert_premise_aba_v172.json +release/coverage/formal_coverage_inventory.json +release/tools/repin_v173.py +tools/lean_admission_audit.py +tests/release_validate.py +tools/gaussian_certificate.py +tools/gaussian_release.py +tools/int_cert_producer.py +tools/int_cert_release.py +tools/formal_receipt.py +tools/receipt_verify.py +tools/formal_status_gate.py +tools/coverage_inventory.py +tools/isolated_entry.py +tools/exact_verify.py +tools/claim_kernel.py +tools/claim_router.py +tools/claim_bundle_verify.py +tools/anubis_program_verify.py +release/program/inventory_safe_v1.json +release/program/SPEC.md +tools/domain_pack_verify.py +tools/test_exists_verify.py +tools/decision_verify.py +domain_packs/PACK_SCHEMA.json +domain_packs/PACK_SPEC.md +domain_packs/registry_v1.json +domain_packs/core/manifest.json +domain_packs/core/core_pack.anb +domain_packs/programming/manifest.json +domain_packs/programming/programming_pack.anb +domain_packs/decision/manifest.json +domain_packs/decision/decision_pack.anb +tools/sqrt_rat_producer.py +tools/exp_rat_producer.py +tools/ln_rat_producer.py +tools/sin_rat_producer.py +tools/atan_rat_producer.py +tools/tanh_rat_producer.py +release/claim/inference_registry_v1.json +release/claim/unit_registry_v1.json +plugin/hermes/server.py +plugin/hermes/bundle_hash.py +plugin/hermes/jackal_hermes +plugin/hermes/tools.json +plugin/hermes/profiles/core.json +plugin/hermes/profiles/formal.json +plugin/hermes/profiles/full.json +plugin/hermes/schemas/jackal_agent_profile.schema.json +" + +OPTIONAL_EVIDENCE_NAMES=" +positive_corpus.jsonl +negative_controls.jsonl +aba_mutations.json +plugin_smoke.jsonl +mutations_11.json +fail_closed_sweep.jsonl +gaussian_formal_v130.json +gaussian_formal_v150.json +seal_audit_v150.json +seal_audit_receipts_v150.json +receipt_semantic_mutations.json +claim_hostile_matrix_v160.json +claim_dogfood_v160.json +claim_aba_v160.json +anubis_program_hostile_v1.json +build_environment_v170.json +" + +for relative in $REQUIRED_INPUTS; do + require_regular "$ROOT/$relative" +done + +# Checking the plan validates every live identity, including the two +# current checker binaries, both proof-identity-v2 records, compatibility +# policy, ABA evidence, and all preserved v1.7.0 lanes. It does not write. +JACKAL_ANUBIS_COMPILER_PATH="$COMPILER" \ + python3 -I -S -B "$ROOT/release/tools/repin_linux.py" --check >/dev/null + +MODE=${1:-} +if [ "$MODE" = "--dry-run" ] && [ "$#" -eq 1 ]; then + echo "PACKAGE_V173_DRY_RUN_PASS version=$VER platform=$PLATFORM" + echo "compiler=$COMPILER compiler_sha256=$COMPILER_SHA256" + echo "package=$FINAL_PKG" + echo "tarball=$FINAL_TARBALL" + echo "range_identity=range_proof_identity.json source=release/evidence/range_proof_identity_v172.json" + echo "int_identity=int_cert_proof_identity.json source=release/evidence/int_cert_proof_identity_v172.json" + echo "lean_admission_audit=evidence/lean_admission_audit_v173.json" + echo "capability_inventory=capability_inventory_v1.json" + echo "compat=evidence/compat_v172_floor.json" + echo "program_compat=evidence/compat_v173_floor.json" + echo "program_profile=inventory-safe-v1" + echo "archival_runtime=v1.7.0 archive_sha256=$V170_ARCHIVE_SHA256" + exit 0 +fi + +if [ "$MODE" != "--build" ] || [ "$#" -ne 1 ]; then + echo "usage: release/build_package_v173.sh --dry-run|--build" >&2 + exit 2 +fi + +/bin/mkdir -p "$DIST" +RELEASE_DEVICE=$(/usr/bin/stat -c '%d' "$ROOT/release") +DIST_DEVICE=$(/usr/bin/stat -c '%d' "$DIST") +[ "$RELEASE_DEVICE" = "$DIST_DEVICE" ] || { + echo "PACKAGE_V173_REFUSED reason=dist-cross-filesystem release_device=$RELEASE_DEVICE dist_device=$DIST_DEVICE path=$DIST" >&2 + exit 5 +} + +[ ! -e "$FINAL_PKG" ] && [ ! -L "$FINAL_PKG" ] || { + echo "PACKAGE_V173_REFUSED reason=output-exists path=$FINAL_PKG" >&2 + exit 5 +} +[ ! -e "$FINAL_TARBALL" ] && [ ! -L "$FINAL_TARBALL" ] || { + echo "PACKAGE_V173_REFUSED reason=output-exists path=$FINAL_TARBALL" >&2 + exit 5 +} + +STAGE=$(mktemp -d "$ROOT/release/.v173-stage.XXXXXX") +cleanup() { + if [ -n "${STAGE:-}" ] && [ -d "$STAGE" ]; then + /bin/rm -r "$STAGE" + fi +} +trap cleanup EXIT HUP INT TERM +PKG="$STAGE/$PKG_NAME" +/bin/mkdir -p \ + "$PKG/evidence" "$PKG/tools" "$PKG/program" "$PKG/release/claim" \ + "$PKG/domain_packs/core" "$PKG/domain_packs/programming" \ + "$PKG/domain_packs/decision" "$PKG/plugin/hermes/profiles" \ + "$PKG/plugin/hermes/schemas" + +# Freeze every repository input before the first copy. Each copy below must +# match this plan both at the source after copying and in the staged package. +SOURCE_PLAN="$STAGE/source-plan.sha256" +: > "$SOURCE_PLAN" +for relative in $REQUIRED_INPUTS; do + /usr/bin/printf '%s %s\n' "$(sha256 "$ROOT/$relative")" "$relative" >> "$SOURCE_PLAN" +done +SELECTED_OPTIONAL_EVIDENCE="" +for name in $OPTIONAL_EVIDENCE_NAMES; do + optional="$ROOT/release/evidence/$name" + if [ -e "$optional" ] || [ -L "$optional" ]; then + require_regular "$optional" + relative="release/evidence/$name" + /usr/bin/printf '%s %s\n' "$(sha256 "$optional")" "$relative" >> "$SOURCE_PLAN" + SELECTED_OPTIONAL_EVIDENCE="$SELECTED_OPTIONAL_EVIDENCE $name" + fi +done + +copy_file() { + source_path="$1" + destination_path="$2" + require_regular "$source_path" + case "$source_path" in + "$ROOT"/*) relative_path=${source_path#"$ROOT"/} ;; + *) + echo "PACKAGE_V173_REFUSED reason=copy-source-outside-plan path=$source_path" >&2 + exit 4 + ;; + esac + expected=$(/usr/bin/awk -v target="$relative_path" '$2==target{print $1}' "$SOURCE_PLAN") + [ -n "$expected" ] || { + echo "PACKAGE_V173_REFUSED reason=copy-source-unplanned path=$relative_path" >&2 + exit 4 + } + before=$(sha256 "$source_path") + [ "$before" = "$expected" ] || { + echo "PACKAGE_V173_REFUSED reason=copy-source-prehash-drift path=$relative_path" >&2 + exit 4 + } + [ ! -e "$destination_path" ] && [ ! -L "$destination_path" ] || { + echo "PACKAGE_V173_REFUSED reason=copy-destination-exists path=$destination_path" >&2 + exit 4 + } + /bin/cp "$source_path" "$destination_path" + after=$(sha256 "$source_path") + copied=$(sha256 "$destination_path") + [ "$after" = "$expected" ] && [ "$copied" = "$expected" ] || { + echo "PACKAGE_V173_REFUSED reason=copy-source-or-destination-drift path=$relative_path" >&2 + exit 4 + } +} + +# Stable package names expose the current v2 identities without leaking the +# repository's epoch-suffixed filenames into wrapper contracts. +copy_file "$ROOT/jackal-native" "$PKG/jackal-native" +copy_file "$ROOT/jackal_calc.anb" "$PKG/jackal_calc.anb" +copy_file "$RANGE_CHECKER" "$PKG/jackal_cert_check" +copy_file "$GAUSSIAN_CHECKER" "$PKG/jackal_gaussian_check" +copy_file "$INT_CHECKER" "$PKG/jackal_int_cert_check" +copy_file "$ROOT/release/evidence/range_proof_identity_v172.linux-aarch64.json" "$PKG/range_proof_identity.json" +copy_file "$ROOT/release/evidence/int_cert_proof_identity_v172.linux-aarch64.json" "$PKG/int_cert_proof_identity.json" +copy_file "$ROOT/release/evidence/gaussian_proof_identity.linux-aarch64.json" "$PKG/gaussian_proof_identity.json" +copy_file "$ROOT/release/evidence/lean_admission_audit_v173.linux-aarch64.json" "$PKG/evidence/lean_admission_audit_v173.json" +copy_file "$ROOT/release/capability_inventory_v1.json" "$PKG/capability_inventory_v1.json" +copy_file "$ROOT/release/coverage/formal_coverage_inventory.json" "$PKG/formal_coverage_inventory.json" + +# Replay-only v1.7.0 receipts require the exact historical checker bytes. +# Accept an operator-supplied local copy of the published archive, otherwise +# fetch the public release asset, then verify the whole archive before reading +# only the two named regular-file members. No archive path is extracted. +V170_ARCHIVE="$STAGE/jackal-v1.7.0-macos-arm64.tar.gz" +if [ -n "${JACKAL_V170_ARCHIVE:-}" ]; then + require_regular "$JACKAL_V170_ARCHIVE" + /bin/cp "$JACKAL_V170_ARCHIVE" "$V170_ARCHIVE" +else + /usr/bin/curl --fail --location --silent --show-error \ + --proto '=https' --tlsv1.2 \ + --connect-timeout 20 --max-time 900 \ + --retry 3 --retry-max-time 900 --retry-connrefused \ + "$V170_ARCHIVE_URL" --output "$V170_ARCHIVE" +fi +[ "$(sha256 "$V170_ARCHIVE")" = "$V170_ARCHIVE_SHA256" ] || { + echo "PACKAGE_V173_REFUSED reason=archival-archive-identity" >&2 + exit 4 +} +python3 -I -S -B - "$V170_ARCHIVE" "$PKG" \ + "$V170_RANGE_CHECKER_SHA256" "$V170_COVERAGE_INVENTORY_SHA256" <<'PY' +import hashlib +import os +import pathlib +import sys +import tarfile + +archive = pathlib.Path(sys.argv[1]) +package = pathlib.Path(sys.argv[2]) +expected = { + "jackal-v1.7.0-macos-arm64/jackal_cert_check": ( + package / "jackal_cert_check_v170", sys.argv[3], 0o755 + ), + "jackal-v1.7.0-macos-arm64/formal_coverage_inventory.json": ( + package / "evidence/formal_coverage_inventory_v170.json", sys.argv[4], + 0o644 + ), +} +with tarfile.open(archive, "r:gz") as bundle: + members = {member.name: member for member in bundle.getmembers()} + for name, (destination, digest, mode) in expected.items(): + member = members.get(name) + if member is None or not member.isfile() or member.size > 256 * 1024 * 1024: + raise SystemExit(f"archival-checker-member-refused:{name}") + source = bundle.extractfile(member) + if source is None: + raise SystemExit(f"archival-checker-read-refused:{name}") + data = source.read(256 * 1024 * 1024 + 1) + if len(data) != member.size or hashlib.sha256(data).hexdigest() != digest: + raise SystemExit(f"archival-checker-identity-refused:{name}") + with destination.open("xb") as output: + output.write(data) + output.flush() + os.fsync(output.fileno()) + destination.chmod(mode) +PY + +for relative in \ + tests/release_validate.py \ + tools/gaussian_certificate.py tools/gaussian_release.py \ + tools/int_cert_producer.py tools/int_cert_release.py \ + tools/formal_receipt.py tools/receipt_verify.py \ + tools/formal_status_gate.py tools/coverage_inventory.py \ + tools/isolated_entry.py tools/exact_verify.py \ + tools/claim_kernel.py tools/claim_router.py tools/claim_bundle_verify.py \ + tools/sqrt_rat_producer.py tools/exp_rat_producer.py \ + tools/ln_rat_producer.py tools/sin_rat_producer.py \ + tools/atan_rat_producer.py tools/tanh_rat_producer.py; do + copy_file "$ROOT/$relative" "$PKG/$(basename "$relative")" +done + +copy_file "$ROOT/tools/anubis_program_verify.py" "$PKG/tools/anubis_program_verify.py" +copy_file "$ROOT/tools/domain_pack_verify.py" "$PKG/tools/domain_pack_verify.py" +copy_file "$ROOT/tools/test_exists_verify.py" "$PKG/tools/test_exists_verify.py" +copy_file "$ROOT/tools/decision_verify.py" "$PKG/tools/decision_verify.py" +copy_file "$ROOT/tools/exact_verify.py" "$PKG/tools/exact_verify.py" +copy_file "$ROOT/release/program/inventory_safe_v1.json" "$PKG/program/inventory_safe_v1.json" +copy_file "$ROOT/domain_packs/PACK_SCHEMA.json" "$PKG/domain_packs/PACK_SCHEMA.json" +copy_file "$ROOT/release/program/SPEC.md" "$PKG/program/SPEC.md" +copy_file "$ROOT/domain_packs/PACK_SPEC.md" "$PKG/domain_packs/PACK_SPEC.md" +copy_file "$ROOT/domain_packs/registry_v1.json" "$PKG/domain_packs/registry_v1.json" +copy_file "$ROOT/domain_packs/core/manifest.json" "$PKG/domain_packs/core/manifest.json" +copy_file "$ROOT/domain_packs/core/core_pack.anb" "$PKG/domain_packs/core/core_pack.anb" +copy_file "$ROOT/domain_packs/programming/manifest.json" "$PKG/domain_packs/programming/manifest.json" +copy_file "$ROOT/domain_packs/programming/programming_pack.anb" "$PKG/domain_packs/programming/programming_pack.anb" +copy_file "$ROOT/domain_packs/decision/manifest.json" "$PKG/domain_packs/decision/manifest.json" +copy_file "$ROOT/domain_packs/decision/decision_pack.anb" "$PKG/domain_packs/decision/decision_pack.anb" +copy_file "$ROOT/plugin/hermes/profiles/core.json" "$PKG/plugin/hermes/profiles/core.json" +copy_file "$ROOT/plugin/hermes/profiles/formal.json" "$PKG/plugin/hermes/profiles/formal.json" +copy_file "$ROOT/plugin/hermes/profiles/full.json" "$PKG/plugin/hermes/profiles/full.json" +copy_file "$ROOT/plugin/hermes/schemas/jackal_agent_profile.schema.json" "$PKG/plugin/hermes/schemas/jackal_agent_profile.schema.json" + +copy_file "$ROOT/release/claim/inference_registry_v1.json" "$PKG/inference_registry_v1.json" +copy_file "$ROOT/release/claim/unit_registry_v1.json" "$PKG/unit_registry_v1.json" +copy_file "$ROOT/release/claim/inference_registry_v1.json" "$PKG/release/claim/inference_registry_v1.json" +copy_file "$ROOT/release/claim/unit_registry_v1.json" "$PKG/release/claim/unit_registry_v1.json" +copy_file "$ROOT/plugin/hermes/server.py" "$PKG/plugin/hermes/server.py" +copy_file "$ROOT/plugin/hermes/bundle_hash.py" "$PKG/plugin/hermes/bundle_hash.py" +copy_file "$ROOT/plugin/hermes/jackal_hermes" "$PKG/plugin/hermes/jackal_hermes" +copy_file "$ROOT/plugin/hermes/tools.json" "$PKG/plugin/hermes/tools.json" + +# Current compatibility policy plus the evidence it names. The archival range +# v1 identity remains replay-only. The int-cert v1 identity is historical +# revocation evidence only and its vulnerable checker is deliberately absent. +copy_file "$ROOT/release/compat/v172_floor.linux-aarch64.json" "$PKG/evidence/compat_v172_floor.json" +copy_file "$ROOT/release/compat/v173_floor.json" "$PKG/evidence/compat_v173_floor.json" +copy_file "$ROOT/release/compat/v170_floor.json" "$PKG/evidence/compat_v170_floor.json" +copy_file "$ROOT/release/compat/v150_floor.json" "$PKG/evidence/compat_v150_floor.json" +copy_file "$ROOT/release/evidence/range_ordering_aba_v172.json" "$PKG/evidence/range_ordering_aba_v172.json" +copy_file "$ROOT/release/evidence/int_cert_premise_aba_v172.json" "$PKG/evidence/int_cert_premise_aba_v172.json" +copy_file "$ROOT/release/evidence/range_proof_identity.json" "$PKG/evidence/range_proof_identity_v1.json" +copy_file "$ROOT/release/evidence/int_cert_proof_identity.json" "$PKG/evidence/int_cert_proof_identity_v1.json" +copy_file "$ROOT/release/evidence/range_proof_identity_v172.linux-aarch64.json" "$PKG/evidence/range_proof_identity_v172.json" +copy_file "$ROOT/release/evidence/int_cert_proof_identity_v172.linux-aarch64.json" "$PKG/evidence/int_cert_proof_identity_v172.json" + +for name in $SELECTED_OPTIONAL_EVIDENCE; do + copy_file "$ROOT/release/evidence/$name" "$PKG/evidence/$name" +done + +/bin/chmod +x \ + "$PKG/jackal-native" "$PKG/jackal_cert_check" "$PKG/jackal_cert_check_v170" \ + "$PKG/jackal_gaussian_check" "$PKG/jackal_int_cert_check" \ + "$PKG/gaussian_certificate.py" "$PKG/gaussian_release.py" \ + "$PKG/int_cert_producer.py" "$PKG/int_cert_release.py" \ + "$PKG/isolated_entry.py" "$PKG/exact_verify.py" \ + "$PKG/claim_kernel.py" "$PKG/claim_router.py" \ + "$PKG/claim_bundle_verify.py" "$PKG/tools/anubis_program_verify.py" \ + "$PKG/tools/domain_pack_verify.py" "$PKG/tools/test_exists_verify.py" \ + "$PKG/tools/decision_verify.py" "$PKG/tools/exact_verify.py" \ + "$PKG/plugin/hermes/jackal_hermes" + +cat > "$PKG/jackal-cert-release" <<'WRAP' +#!/bin/sh +# JACKAL v1.7.2 packaged range release gate (self-contained). +set -eu +HERE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) +[ "$#" -eq 4 ] || { echo "usage: jackal-cert-release \"\" " >&2; exit 2; } +EE=$(awk '$1=="evaluator"{print $NF}' "$HERE/MANIFEST.sha256") +EC=$(awk '$1=="checker"{print $NF}' "$HERE/MANIFEST.sha256") +ES=$(awk '$1=="source"{print $NF}' "$HERE/MANIFEST.sha256") +EI=$(awk '$1=="coverage_inventory"{print $NF}' "$HERE/MANIFEST.sha256") +EPF=$(awk '$1=="range_proof_identity"{print $NF}' "$HERE/MANIFEST.sha256") +EPD=$(awk '$1=="range_proof_digest"{print $NF}' "$HERE/MANIFEST.sha256") +[ -n "$EE" ] && [ -n "$EC" ] && [ -n "$ES" ] && [ -n "$EI" ] && [ -n "$EPF" ] && [ -n "$EPD" ] || { echo "status=unavailable reason=manifest-incomplete" >&2; exit 3; } +exec python3 -I -S -B "$HERE/isolated_entry.py" range \ + --expr "$1" --lo "$2" --hi "$3" \ + --evaluator "$HERE/jackal-native" --checker "$HERE/jackal_cert_check" \ + --expected-evaluator "$EE" --expected-checker "$EC" --expected-source "$ES" \ + --inventory "$HERE/formal_coverage_inventory.json" --expected-inventory "$EI" \ + --proof-identity "$HERE/range_proof_identity.json" \ + --expected-proof-identity-file "$EPF" --expected-proof-identity-digest "$EPD" \ + --release-epoch v1.7.2 --formal-receipt "$4" +WRAP + +cat > "$PKG/jackal-int-cert-release" <<'WRAP' +#!/bin/sh +# JACKAL v1.7.2 packaged composed-integral release gate (self-contained). +set -eu +HERE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) +[ "$#" -eq 5 ] || { echo "usage: jackal-int-cert-release \"\" " >&2; exit 2; } +EP=$(awk '$1=="int_cert_producer"{print $NF}' "$HERE/MANIFEST.sha256") +EC=$(awk '$1=="int_cert_checker"{print $NF}' "$HERE/MANIFEST.sha256") +EI=$(awk '$1=="coverage_inventory"{print $NF}' "$HERE/MANIFEST.sha256") +EPF=$(awk '$1=="int_cert_proof_identity"{print $NF}' "$HERE/MANIFEST.sha256") +EPD=$(awk '$1=="int_cert_proof_digest"{print $NF}' "$HERE/MANIFEST.sha256") +[ -n "$EP" ] && [ -n "$EC" ] && [ -n "$EI" ] && [ -n "$EPF" ] && [ -n "$EPD" ] || { echo "status=refused reason=manifest-incomplete" >&2; exit 3; } +exec python3 -I -S -B "$HERE/isolated_entry.py" int-cert \ + --expression "$1" --lower "$2" --upper "$3" --tolerance "$4" \ + --producer "$HERE/int_cert_producer.py" --checker "$HERE/jackal_int_cert_check" \ + --expected-producer "$EP" --expected-checker "$EC" --receipt "$5" \ + --inventory "$HERE/formal_coverage_inventory.json" --expected-inventory "$EI" \ + --proof-identity "$HERE/int_cert_proof_identity.json" \ + --expected-proof-identity-file "$EPF" --expected-proof-identity-digest "$EPD" \ + --release-epoch v1.7.2 +WRAP + +cat > "$PKG/jackal-gaussian-release" <<'WRAP' +#!/bin/sh +# Preserved theorem-backed Gaussian lane; package-local and self-contained. +set -eu +HERE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) +[ "$#" -eq 5 ] || { echo "usage: jackal-gaussian-release " >&2; exit 2; } +EP=$(awk '$1=="gaussian_producer"{print $NF}' "$HERE/MANIFEST.sha256") +EC=$(awk '$1=="gaussian_checker"{print $NF}' "$HERE/MANIFEST.sha256") +EI=$(awk '$1=="coverage_inventory"{print $NF}' "$HERE/MANIFEST.sha256") +EPF=$(awk '$1=="gaussian_proof_identity"{print $NF}' "$HERE/MANIFEST.sha256") +EPD=$(awk '$1=="gaussian_proof_digest"{print $NF}' "$HERE/MANIFEST.sha256") +[ -n "$EP" ] && [ -n "$EC" ] && [ -n "$EI" ] && [ -n "$EPF" ] && [ -n "$EPD" ] || { echo "status=refused reason=manifest-incomplete" >&2; exit 3; } +exec python3 -I -S -B "$HERE/isolated_entry.py" gaussian \ + --expression "$1" --lower "$2" --upper "$3" --tolerance "$4" \ + --producer "$HERE/gaussian_certificate.py" --checker "$HERE/jackal_gaussian_check" \ + --expected-producer "$EP" --expected-checker "$EC" \ + --inventory "$HERE/formal_coverage_inventory.json" --expected-inventory "$EI" \ + --proof-identity "$HERE/gaussian_proof_identity.json" \ + --expected-proof-identity-file "$EPF" --expected-proof-identity-digest "$EPD" \ + --release-epoch v1.5.0 --receipt "$5" +WRAP + +cat > "$PKG/jackal-receipt-verify" <<'WRAP' +#!/bin/sh +set -eu +HERE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) +exec python3 -I -S -B "$HERE/isolated_entry.py" verify "$@" +WRAP + +cat > "$PKG/jackal-claim" <<'WRAP' +#!/bin/sh +set -eu +HERE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) +exec python3 -I -S -B "$HERE/claim_router.py" claim "$@" +WRAP + +cat > "$PKG/jackal-anubis-program" <<'WRAP' +#!/bin/sh +# check invokes only Anubis build --evidence; no subcommand executes artifact. +set -eu +SELF=$0 +LINK_HOPS=0 +while [ -L "$SELF" ]; do + LINK_HOPS=$((LINK_HOPS + 1)) + if [ "$LINK_HOPS" -gt 16 ]; then + echo "status=refused reason=wrapper-symlink-depth" >&2 + exit 126 + fi + LINK_TARGET=$(/usr/bin/readlink "$SELF") || { + echo "status=refused reason=wrapper-symlink-read" >&2 + exit 126 + } + case "$LINK_TARGET" in + /*) SELF=$LINK_TARGET ;; + *) SELF=$(dirname -- "$SELF")/$LINK_TARGET ;; + esac +done +HERE=$(CDPATH= cd -P -- "$(dirname -- "$SELF")" && pwd -P) +exec python3 -I -S -B "$HERE/tools/anubis_program_verify.py" "$@" +WRAP + +cat > "$PKG/jackal-claim-verify" <<'WRAP' +#!/bin/sh +set -eu +HERE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) +M="$HERE/MANIFEST.sha256" +set -- "$@" \ + --expected-inference-registry "$HERE/inference_registry_v1.json" \ + --expected-inference-registry-sha256 "$(awk '$1=="claim_inference_registry"{print $NF}' "$M")" \ + --expected-unit-registry "$HERE/unit_registry_v1.json" \ + --expected-unit-registry-sha256 "$(awk '$1=="claim_unit_registry"{print $NF}' "$M")" \ + --expected-environment-epoch "$(awk '$1=="evaluator"{print $NF}' "$M")" \ + --receipt-verifier "$HERE/receipt_verify.py" --exact-verifier "$HERE/exact_verify.py" \ + --checker "$HERE/jackal_cert_check" --expected-checker "$(awk '$1=="checker"{print $NF}' "$M")" \ + --expected-evaluator "$(awk '$1=="evaluator"{print $NF}' "$M")" \ + --inventory "$HERE/formal_coverage_inventory.json" \ + --expected-inventory "$(awk '$1=="coverage_inventory"{print $NF}' "$M")" \ + --proof-identity "$HERE/range_proof_identity.json" \ + --expected-proof-identity-file "$(awk '$1=="range_proof_identity"{print $NF}' "$M")" \ + --expected-proof-identity-digest "$(awk '$1=="range_proof_digest"{print $NF}' "$M")" \ + --gaussian-checker "$HERE/jackal_gaussian_check" \ + --expected-gaussian-checker "$(awk '$1=="gaussian_checker"{print $NF}' "$M")" \ + --gaussian-proof-identity "$HERE/gaussian_proof_identity.json" \ + --expected-gaussian-proof-identity-file "$(awk '$1=="gaussian_proof_identity"{print $NF}' "$M")" \ + --expected-gaussian-proof-identity-digest "$(awk '$1=="gaussian_proof_digest"{print $NF}' "$M")" \ + --int-cert-checker "$HERE/jackal_int_cert_check" \ + --expected-int-cert-checker "$(awk '$1=="int_cert_checker"{print $NF}' "$M")" \ + --int-cert-proof-identity "$HERE/int_cert_proof_identity.json" \ + --expected-int-cert-proof-identity-file "$(awk '$1=="int_cert_proof_identity"{print $NF}' "$M")" \ + --expected-int-cert-proof-identity-digest "$(awk '$1=="int_cert_proof_digest"{print $NF}' "$M")" \ + --archival-range-checker "$HERE/jackal_cert_check_v170" \ + --expected-archival-range-checker "$(awk '$1=="archival_range_checker"{print $NF}' "$M")" \ + --archival-range-proof-identity "$HERE/evidence/range_proof_identity_v1.json" \ + --expected-archival-range-proof-identity-file "$(awk '$1=="archival_range_proof_identity"{print $NF}' "$M")" \ + --expected-archival-range-proof-identity-digest "$(awk '$1=="archival_range_proof_digest"{print $NF}' "$M")" \ + --archival-range-inventory "$HERE/evidence/formal_coverage_inventory_v170.json" \ + --expected-archival-range-inventory "$(awk '$1=="archival_range_coverage_inventory"{print $NF}' "$M")" +for producer in sqrt_rat exp_rat ln_rat sin_rat atan_rat tanh_rat; do + pin=$(awk -v label="${producer}_producer" '$1==label{print $NF}' "$M") + [ -n "$pin" ] && set -- "$@" --trusted-producer "$pin" +done +pin=$(awk '$1=="gaussian_producer"{print $NF}' "$M") +[ -n "$pin" ] && set -- "$@" --trusted-producer "$pin" +pin=$(awk '$1=="int_cert_producer"{print $NF}' "$M") +[ -n "$pin" ] && set -- "$@" --trusted-producer "$pin" +exec python3 -I -S -B "$HERE/claim_bundle_verify.py" "$@" +WRAP + +emit_variant_wrapper() { + wrapper_name="$1" + producer_file="$2" + manifest_label="$3" + variant="$4" + producer_extra="$5" + cat > "$PKG/$wrapper_name" < [receipt.json]" >&2; exit 2; } +EXPR="\$1"; LO="\$2"; HI="\$3"; RECEIPT="\${4:-}" +[ -f "\$HERE/MANIFEST.sha256" ] && [ ! -L "\$HERE/MANIFEST.sha256" ] || { echo "status=refused reason=manifest-identity" >&2; exit 1; } +EM=\$(shasum -a 256 "\$HERE/MANIFEST.sha256" | awk '{print \$1}') +EP=\$(awk '\$1=="$manifest_label"{print \$NF}' "\$HERE/MANIFEST.sha256") +EC=\$(awk '\$1=="checker"{print \$NF}' "\$HERE/MANIFEST.sha256") +EPF=\$(awk '\$1=="range_proof_identity"{print \$NF}' "\$HERE/MANIFEST.sha256") +EPD=\$(awk '\$1=="range_proof_digest"{print \$NF}' "\$HERE/MANIFEST.sha256") +EI=\$(awk '\$1=="coverage_inventory"{print \$NF}' "\$HERE/MANIFEST.sha256") +[ -n "\$EP" ] && [ -n "\$EC" ] && [ -n "\$EPF" ] && [ -n "\$EPD" ] && [ -n "\$EI" ] || { echo "status=refused reason=manifest-incomplete" >&2; exit 1; } +verify_variant_runtime_identity() { + MP=\$(shasum -a 256 "\$HERE/MANIFEST.sha256" | awk '{print \$1}') + PP=\$(shasum -a 256 "\$HERE/$producer_file" | awk '{print \$1}') + CP=\$(shasum -a 256 "\$HERE/jackal_cert_check" | awk '{print \$1}') + PF=\$(shasum -a 256 "\$HERE/range_proof_identity.json" | awk '{print \$1}') + IF=\$(shasum -a 256 "\$HERE/formal_coverage_inventory.json" | awk '{print \$1}') + DID=\$(python3 -I -S -B -c 'import json,sys; print(json.load(open(sys.argv[1], encoding="utf-8"))["identity_digest_sha256"])' "\$HERE/range_proof_identity.json") + [ "\$MP" = "\$EM" ] && [ "\$PP" = "\$EP" ] && [ "\$CP" = "\$EC" ] && \ + [ "\$PF" = "\$EPF" ] && [ "\$IF" = "\$EI" ] && [ "\$DID" = "\$EPD" ] || { + echo "status=refused reason=identity" >&2 + exit 1 + } +} +verify_variant_runtime_identity +CERT=\$(mktemp) +trap 'rm -f "\$CERT"' EXIT +python3 -I -S -B "\$HERE/$producer_file" emit $producer_extra --expression="\$EXPR" --lower="\$LO" --upper="\$HI" >"\$CERT" 2>&1 || { echo "status=refused reason=producer-refused" >&2; exit 1; } +verify_variant_runtime_identity +OUT=\$("\$HERE/jackal_cert_check" "\$CERT" range-bound-cert "\$EXPR" "\$LO" "\$HI" 2>&1) || { echo "status=refused reason=checker-rejected detail=\"\$OUT\"" >&2; exit 1; } +verify_variant_runtime_identity +if [ -n "\$RECEIPT" ]; then + python3 -I -S -B "\$HERE/isolated_entry.py" emit-variant-receipt \ + --variant "$variant" --expression="\$EXPR" --lower="\$LO" --upper="\$HI" \ + --cert "\$CERT" --producer "\$HERE/$producer_file" \ + --checker "\$HERE/jackal_cert_check" \ + --proof-identity "\$HERE/range_proof_identity.json" \ + --inventory "\$HERE/formal_coverage_inventory.json" \ + --release-epoch v1.7.2 --output "\$RECEIPT" +fi +verify_variant_runtime_identity +[ -z "\$RECEIPT" ] || echo "receipt=\$RECEIPT" +echo "status=formal-bounded" +echo "checker.ACCEPT=\$OUT" +WRAP + /bin/chmod +x "$PKG/$wrapper_name" +} + +emit_variant_wrapper jackal-sqrt-rat-release sqrt_rat_producer.py sqrt_rat_producer sqrt_rat "" +emit_variant_wrapper jackal-exp-rat-release exp_rat_producer.py exp_rat_producer exp_rat "" +emit_variant_wrapper jackal-ln-rat-release ln_rat_producer.py ln_rat_producer ln_rat "" +emit_variant_wrapper jackal-sin-rat-release sin_rat_producer.py sin_rat_producer sin_rat "--op sin" +emit_variant_wrapper jackal-cos-rat-release sin_rat_producer.py sin_rat_producer cos_rat "--op cos" +emit_variant_wrapper jackal-atan-rat-release atan_rat_producer.py atan_rat_producer atan_rat "" +emit_variant_wrapper jackal-tanh-rat-release tanh_rat_producer.py tanh_rat_producer tanh_rat "" + +/bin/chmod +x "$PKG/jackal-cert-release" "$PKG/jackal-int-cert-release" \ + "$PKG/jackal-gaussian-release" "$PKG/jackal-receipt-verify" \ + "$PKG/jackal-claim" "$PKG/jackal-claim-verify" \ + "$PKG/jackal-anubis-program" + +EVALUATOR_ID=$(sha256 "$PKG/jackal-native") +RANGE_CHECKER_ID=$(sha256 "$PKG/jackal_cert_check") +GAUSSIAN_CHECKER_ID=$(sha256 "$PKG/jackal_gaussian_check") +INT_CHECKER_ID=$(sha256 "$PKG/jackal_int_cert_check") +ARCHIVAL_RANGE_CHECKER_ID=$(sha256 "$PKG/jackal_cert_check_v170") +ARCHIVAL_RANGE_INVENTORY_ID=$(sha256 "$PKG/evidence/formal_coverage_inventory_v170.json") +INT_PRODUCER_ID=$(sha256 "$PKG/int_cert_producer.py") +SOURCE_ID=$(sha256 "$PKG/jackal_calc.anb") +RANGE_IDENTITY_FILE_ID=$(sha256 "$PKG/range_proof_identity.json") +INT_IDENTITY_FILE_ID=$(sha256 "$PKG/int_cert_proof_identity.json") +GAUSSIAN_IDENTITY_FILE_ID=$(sha256 "$PKG/gaussian_proof_identity.json") +RANGE_IDENTITY_DIGEST=$(python3 -I -S -B -c 'import json,sys; print(json.load(open(sys.argv[1]))["identity_digest_sha256"])' "$PKG/range_proof_identity.json") +INT_IDENTITY_DIGEST=$(python3 -I -S -B -c 'import json,sys; print(json.load(open(sys.argv[1]))["identity_digest_sha256"])' "$PKG/int_cert_proof_identity.json") +GAUSSIAN_IDENTITY_DIGEST=$(python3 -I -S -B -c 'import json,sys; print(json.load(open(sys.argv[1]))["identity_digest_sha256"])' "$PKG/gaussian_proof_identity.json") +LEAN_ADMISSION_AUDIT_ID=$(sha256 "$PKG/evidence/lean_admission_audit_v173.json") +LEAN_ADMISSION_AUDIT_DIGEST=$(python3 -I -S -B -c 'import json,sys; print(json.load(open(sys.argv[1]))["audit_digest_sha256"])' "$PKG/evidence/lean_admission_audit_v173.json") +COVERAGE_ID=$(sha256 "$PKG/formal_coverage_inventory.json") +COMPAT_ID=$(sha256 "$PKG/evidence/compat_v172_floor.json") +PROGRAM_COMPAT_ID=$(sha256 "$PKG/evidence/compat_v173_floor.json") +RANGE_ABA_ID=$(sha256 "$PKG/evidence/range_ordering_aba_v172.json") +INT_ABA_ID=$(sha256 "$PKG/evidence/int_cert_premise_aba_v172.json") +# formal_receipt.py is part of the hermes runtime bundle; bake its Linux compat +# pins BEFORE the bundle digest is computed so MANIFEST and selftest agree. +python3 -I -S -B "$ROOT/release/tools/bake_linux_compat_pins.py" \ + "$PKG/formal_receipt.py" "$RANGE_IDENTITY_FILE_ID" "$INT_IDENTITY_FILE_ID" >/dev/null +PLUGIN_ID=$(python3 -I -S -B "$PKG/plugin/hermes/bundle_hash.py" print) + +cat > "$PKG/MANIFEST.sha256" < "$PKG/NON-CLAIMS.txt" <<'EOF' +JACKAL v1.7.3 — explicit boundary +- Apple Silicon macOS only; unsigned and not notarized. +- Range and composed-integral formal language applies only to the declared + checker-accepted fragments and the v2 identities shipped here. +- The archived v1 range identity is replay-only. Archival replay + requires the exact historical range checker AND the exact historical + coverage inventory that shipped with it (jackal_cert_check_v170 plus + formal_coverage_inventory_v170.json); no other checker/inventory tuple + is admitted for archival replay, and reversed range intervals remain + revoked and refuse. +- The archived v1 composed-integral identity is historical revocation + evidence only. Its request-unbound checker is not shipped or admitted; + every v1.7.0 int-certificate receipt refuses formal replay. +- Unsupported proof epochs and fragments refuse. +- Gaussian, pure-rational, exact-CAS, and claim-kernel lanes preserve their + prior assurance classes. No lane is silently upgraded. +- A programming-status pack establishes STRUCTURE, never correctness. + test-exists says only that a declaration-shaped occurrence of a named + symbol exists in bytes at a claimed content hash. It says nothing + about whether that test executes, passes, asserts anything, or covers + what a surrounding document claims it covers. +- claim-cites-test RESOLVES a citation; it does not validate one. A + document may cite a real test that checks something entirely + different, and this checker cannot see that. +- The decision pack orders options by a caller-declared numeric + criterion. Accepting that criterion is never a claim that it is the + right one to optimise. Value judgments are refused, not ranked. +- The value-judgment screen is a substring blocklist and is INCOMPLETE. + Measured on the shipped engine: criteria spelled optimal, ideal, and + leetspeak such as b3st are ACCEPTED, while best and preference_score + refuse. Closing that gap requires a declared unit or measurement + provenance on the criterion, which is a protocol change and was not + made. +- The domain-pack verifier checks metadata, identity, and policy only. + It records anubis_execution_status=NOT_EXECUTED and + assurance_status=NOT_MINTED in its own output: a declared manifest + ceiling is an upper bound on what a consumer may claim, never a grant. +- verified-program-evidence and verified-program-receipt mean exact byte/pin, + roster, producer-summary, approved-Z3 UNSAT, and independent-RUP checks + under inventory-safe-v1. They do not establish policy-construct totality, + source-to-VC proof, SMT-to-CNF proof, source-native refinement, runtime + behavior, or universal language soundness. +- Program verification never executes the compiled artifact. The check front + door invokes only the exact approved compiler's build --evidence path. +- No universal correctness, source-to-native refinement, input-truth proof, + operating-system proof, or authenticated builder claim is made. +- The repository-wide Lean admission audit binds tracked source, theorem + axioms, and observed checker bytes. It does not prove the compiler, kernel, + native code, operating system, hardware, or supply chain. +EOF + +cat > "$PKG/README.txt" <<'EOF' +JACKAL v1.7.3 — unified domain-pack and Anubis program evidence for Apple Silicon macOS. + +First run: shasum -a 256 -c SHA256SUMS +Current stable identities: + range_proof_identity.json schema jackal-range-proof-identity-v2 + int_cert_proof_identity.json schema jackal-int-cert-proof-identity-v2 +Compatibility and A->B->A evidence live under evidence/. +The repository-wide Lean admission record is +evidence/lean_admission_audit_v173.json. +The complete 41-tool catalog and core/formal/full profiles live under +plugin/hermes/. Domain packs and their checkers retain repository-relative +paths under domain_packs/ and tools/. Program verification uses +jackal-anubis-program with program/inventory_safe_v1.json. +Current range and composed-integral wrappers emit release epoch v1.7.2. +See NON-CLAIMS.txt before interpreting any result. +EOF + +cat > "$PKG/PROVENANCE-RECEIPT.txt" < SHA256SUMS) + +# Validate the staged package itself before it can become a tarball or enter +# release/dist. This rejects a self-consistent manifest built from a +# semantically mismatched checker/proof/policy tuple. +(cd "$PKG" && shasum -a 256 -c SHA256SUMS >/dev/null) +python3 -I -S -B - "$PKG" "$V170_RANGE_CHECKER_SHA256" \ + "$V170_COVERAGE_INVENTORY_SHA256" <<'PY' +import hashlib +import json +import pathlib +import sys + +package = pathlib.Path(sys.argv[1]).resolve() +expected_archival_range_checker = sys.argv[2] +expected_archival_range_inventory = sys.argv[3] + + +def refuse(reason: str) -> None: + raise SystemExit(f"PACKAGE_V173_REFUSED reason=staged-semantic-{reason}") + + +def require(condition: bool, reason: str) -> None: + if not condition: + refuse(reason) + + +def sha(path: pathlib.Path) -> str: + require(path.is_file() and not path.is_symlink(), f"regular-file:{path.name}") + digest = hashlib.sha256() + with path.open("rb") as source: + while chunk := source.read(1024 * 1024): + digest.update(chunk) + return digest.hexdigest() + + +def reject_duplicates(pairs): + result = {} + for key, value in pairs: + if key in result: + refuse(f"duplicate-json-key:{key}") + result[key] = value + return result + + +def load_json(relative: str): + path = package / relative + require(path.is_file() and not path.is_symlink(), f"json-regular:{relative}") + data = path.read_bytes() + require(len(data) <= 4 * 1024 * 1024, f"json-size:{relative}") + try: + return json.loads(data, object_pairs_hook=reject_duplicates) + except (UnicodeError, json.JSONDecodeError) as exc: + refuse(f"json-parse:{relative}:{exc}") + + +manifest_path = package / "MANIFEST.sha256" +require(manifest_path.is_file() and not manifest_path.is_symlink(), "manifest-regular") +manifest_bytes = manifest_path.read_bytes() +require(len(manifest_bytes) <= 1024 * 1024, "manifest-size") +rows = {} +for raw in manifest_bytes.decode("utf-8").splitlines(): + line = raw.strip() + if not line or line.startswith("#"): + continue + fields = line.split() + require(len(fields) >= 2, "manifest-row") + label = fields[0] + require(label not in rows, f"manifest-duplicate:{label}") + rows[label] = fields[1:] + + +def row_hash(label: str) -> str: + require(label in rows and len(rows[label]) >= 1, f"manifest-missing:{label}") + value = rows[label][-1] + require(len(value) == 64 and all(c in "0123456789abcdef" for c in value), + f"manifest-digest:{label}") + return value + + +range_current = load_json("range_proof_identity.json") +gaussian_current = load_json("gaussian_proof_identity.json") +int_current = load_json("int_cert_proof_identity.json") +lean_audit = load_json("evidence/lean_admission_audit_v173.json") +range_archival = load_json("evidence/range_proof_identity_v1.json") +int_revoked = load_json("evidence/int_cert_proof_identity_v1.json") +compat = load_json("evidence/compat_v172_floor.json") + +range_checker = sha(package / "jackal_cert_check") +gaussian_checker = sha(package / "jackal_gaussian_check") +int_checker = sha(package / "jackal_int_cert_check") +archival_range_checker = sha(package / "jackal_cert_check_v170") +require(range_checker == row_hash("checker"), "range-checker-manifest") +require(gaussian_checker == row_hash("gaussian_checker"), + "gaussian-checker-manifest") +require(int_checker == row_hash("int_cert_checker"), "int-checker-manifest") +require(archival_range_checker == expected_archival_range_checker, + "archival-range-checker-pin") +require(archival_range_checker == row_hash("archival_range_checker"), + "archival-range-checker-manifest") +require(sha(package / "evidence/formal_coverage_inventory_v170.json") == + expected_archival_range_inventory, + "archival-range-inventory-pin") +require(row_hash("archival_range_coverage_inventory") == + expected_archival_range_inventory, + "archival-range-inventory-manifest") +revoked_int_checker_path = package.joinpath("jackal_int_cert_check_v170") +require(not revoked_int_checker_path.exists(), "revoked-int-checker-present") +require("archival_int_cert_checker" not in rows, "revoked-int-checker-row") + +proofs = ( + (range_current, "jackal-range-proof-identity-v2", range_checker, + "range_proof_identity", "range_proof_digest"), + (gaussian_current, "jackal-gaussian-proof-identity-v1", gaussian_checker, + "gaussian_proof_identity", "gaussian_proof_digest"), + (int_current, "jackal-int-cert-proof-identity-v2", int_checker, + "int_cert_proof_identity", "int_cert_proof_digest"), + (range_archival, "jackal-range-proof-identity-v1", archival_range_checker, + "archival_range_proof_identity", "archival_range_proof_digest"), +) +for proof, schema, checker, file_label, digest_label in proofs: + require(proof.get("schema") == schema, f"proof-schema:{file_label}") + require(proof.get("checker", {}).get("sha256") == checker, + f"proof-checker:{file_label}") + proof_path = rows[file_label][0] + require(sha(package / proof_path) == row_hash(file_label), + f"proof-file:{file_label}") + require(proof.get("identity_digest_sha256") == row_hash(digest_label), + f"proof-digest:{file_label}") + +require(lean_audit.get("schema") == "jackal-lean-admission-audit-v1", + "lean-audit-schema") +require(sha(package / "evidence/lean_admission_audit_v173.json") == + row_hash("lean_admission_audit"), "lean-audit-file") +lean_audit_digest = lean_audit.pop("audit_digest_sha256", None) +computed_lean_audit_digest = hashlib.sha256( + json.dumps(lean_audit, sort_keys=True, separators=(",", ":"), + ensure_ascii=False).encode("utf-8") +).hexdigest() +require(lean_audit_digest == computed_lean_audit_digest, + "lean-audit-self-digest") +require(lean_audit_digest == row_hash("lean_admission_audit_digest"), + "lean-audit-manifest-digest") +audit_result = lean_audit.get("audit_result", {}) +require(audit_result.get("status") == "pass", "lean-audit-status") +require(audit_result.get("logical_admission_count") == 0, + "lean-audit-admission-count") +source_inventory = lean_audit.get("source_inventory", {}) +source_files = source_inventory.get("files", []) +require(isinstance(source_files, list) and source_files and + source_inventory.get("file_count") == len(source_files), + "lean-audit-source-count") +source_paths = [item.get("path") for item in source_files + if isinstance(item, dict)] +require(len(source_paths) == len(source_files) and + len(set(source_paths)) == len(source_paths), + "lean-audit-source-uniqueness") +construct_policy = source_inventory.get("construct_policy", {}) +require(construct_policy.get("forbidden_findings") == [], + "lean-audit-forbidden-findings") +allowed_findings = construct_policy.get("allowed_findings", []) +require(isinstance(allowed_findings, list) and + {item.get("construct") for item in allowed_findings} == + {"implemented_by"}, "lean-audit-allowed-findings") +theorem_audit = lean_audit.get("theorem_axiom_audit", {}) +theorem_rows = theorem_audit.get("theorems", []) +require(isinstance(theorem_rows, list) and theorem_rows and + theorem_audit.get("theorem_count") == len(theorem_rows), + "lean-audit-theorem-count") +theorem_names = [item.get("theorem") for item in theorem_rows + if isinstance(item, dict)] +require(len(theorem_names) == len(theorem_rows) and + len(set(theorem_names)) == len(theorem_names), + "lean-audit-theorem-uniqueness") +for item in theorem_rows: + require(item.get("axioms") == + ["propext", "Classical.choice", "Quot.sound"], + f"lean-audit-axioms:{item.get('theorem')}") +trust_surface = lean_audit.get("trust_surface", {}) +require(trust_surface.get("logical_admissions") == [], + "lean-audit-logical-admissions") +require(trust_surface.get("repository_axiom_declarations") == [], + "lean-audit-repository-axioms") +audit_bindings = lean_audit.get("release_bindings", {}).get( + "current_proof_identities", []) +require(len(audit_bindings) == 3, "lean-audit-binding-count") +expected_audit_bindings = { + "range": (range_checker, sha(package / "range_proof_identity.json")), + "gaussian": (gaussian_checker, sha(package / "gaussian_proof_identity.json")), + "int-cert": (int_checker, sha(package / "int_cert_proof_identity.json")), +} +for binding in audit_bindings: + lane = binding.get("lane") + require(lane in expected_audit_bindings, f"lean-audit-binding-lane:{lane}") + expected_checker, expected_identity = expected_audit_bindings.pop(lane) + require(binding.get("checker_sha256") == expected_checker, + f"lean-audit-binding-checker:{lane}") + require(binding.get("identity_checker_sha256") == expected_checker, + f"lean-audit-identity-checker:{lane}") + require(binding.get("identity_sha256") == expected_identity, + f"lean-audit-binding-identity:{lane}") +require(expected_audit_bindings == {}, "lean-audit-binding-coverage") + +require(int_revoked.get("schema") == "jackal-int-cert-proof-identity-v1", + "revoked-int-proof-schema") +revoked_reference = rows.get("revoked_int_cert_proof_identity_reference", []) +require(len(revoked_reference) == 2, "revoked-int-proof-reference") +require(sha(package / revoked_reference[0]) == revoked_reference[1], + "revoked-int-proof-file") + +lanes = compat.get("lanes", {}) +for lane in ("range", "rational_variants"): + current = lanes.get(lane, {}).get("current", {}) + archival = lanes.get(lane, {}).get("archival_v1", {}) + require(current.get("schema") == "jackal-range-proof-identity-v2", + f"compat-current-schema:{lane}") + require(current.get("allowed_release_epochs") == ["v1.7.2"], + f"compat-current-epoch:{lane}") + require(current.get("identity_file_sha256") == row_hash("range_proof_identity"), + f"compat-current-proof:{lane}") + require(archival.get("mode") == "replay-only", f"compat-archive-mode:{lane}") + require(archival.get("allowed_release_epochs") == ["v1.5.0"], + f"compat-archive-epoch:{lane}") + require(archival.get("checker_sha256") == archival_range_checker, + f"compat-archive-checker:{lane}") + require(archival.get("identity_file_sha256") == + row_hash("archival_range_proof_identity"), + f"compat-archive-proof:{lane}") + +int_policy = lanes.get("int_cert", {}) +int_current_policy = int_policy.get("current", {}) +int_archival_policy = int_policy.get("archival_v1", {}) +require(int_current_policy.get("schema") == "jackal-int-cert-proof-identity-v2", + "compat-int-current-schema") +require(int_current_policy.get("allowed_release_epochs") == ["v1.7.2"], + "compat-int-current-epoch") +require(int_current_policy.get("identity_file_sha256") == + row_hash("int_cert_proof_identity"), "compat-int-current-proof") +require(int_archival_policy.get("mode") == "revoked-refuse", + "compat-int-revocation-mode") +require(int_archival_policy.get("allowed_release_epochs") == [], + "compat-int-revocation-epochs") +require(int_archival_policy.get("identity_file_sha256") == revoked_reference[1], + "compat-int-revocation-proof") + +program_compat = load_json("evidence/compat_v173_floor.json") +policy = load_json("program/inventory_safe_v1.json") +catalog = load_json("plugin/hermes/tools.json") +capability_inventory = load_json("capability_inventory_v1.json") +full_profile = load_json("plugin/hermes/profiles/full.json") +tool_names = [tool.get("name") for tool in catalog.get("tools", []) + if isinstance(tool, dict)] +require(catalog.get("version") == "v1.7.3", "catalog-version") +require(len(tool_names) == 41 and len(set(tool_names)) == 41, + "catalog-tool-count") +require(capability_inventory.get("schema") == + "jackal-capability-inventory-v1", "capability-inventory-schema") +inventory_names = [tool.get("name") for tool in + capability_inventory.get("tools", []) + if isinstance(tool, dict)] +require(capability_inventory.get("tool_count") == 41 and + capability_inventory.get("unique_tool_count") == 41 and + inventory_names == tool_names, + "capability-inventory-tool-parity") +inventory_catalog = capability_inventory.get("catalog", {}) +require(inventory_catalog.get("version") == "v1.7.3" and + inventory_catalog.get("sha256") == + sha(package / "plugin/hermes/tools.json"), + "capability-inventory-catalog-binding") +inventory_release = capability_inventory.get("release", {}) +require(inventory_release.get("version") == "v1.7.3" and + inventory_release.get("state") == "v1.7.3", + "capability-inventory-release-state") +require(full_profile.get("tools") == tool_names, "full-profile-catalog-parity") +for profile_name in ("core", "formal", "full"): + profile = load_json(f"plugin/hermes/profiles/{profile_name}.json") + profile_digest = profile.pop("profile_digest_sha256", None) + computed_profile_digest = hashlib.sha256( + json.dumps(profile, sort_keys=True, separators=(",", ":"), + ensure_ascii=False).encode("utf-8") + ).hexdigest() + require(profile_digest == computed_profile_digest, + f"profile-digest:{profile_name}") +require(program_compat.get("release_epoch") == "v1.7.3", + "program-compat-epoch") +require(program_compat.get("tool_count") == 41, "program-compat-tool-count") +require(program_compat.get("program_profile") == "inventory-safe-v1", + "program-compat-profile") +require(program_compat.get("independent_policy_construct_totality") is False, + "program-compat-construct-totality") +policy_digest = policy.pop("policy_digest_sha256", None) +computed_policy_digest = hashlib.sha256( + json.dumps(policy, sort_keys=True, separators=(",", ":"), + ensure_ascii=False).encode("utf-8") +).hexdigest() +require(policy_digest == computed_policy_digest, "program-policy-digest") +require(program_compat.get("program_policy_sha256") == policy_digest, + "program-compat-policy") + +manifest_bound_files = { + "domain_pack_registry": "domain_packs/registry_v1.json", + "domain_pack_verifier": "tools/domain_pack_verify.py", + "domain_pack_test_exists_checker": "tools/test_exists_verify.py", + "domain_pack_decision_checker": "tools/decision_verify.py", + "anubis_program_verifier": "tools/anubis_program_verify.py", + "anubis_program_policy": "program/inventory_safe_v1.json", +} +for label, relative in manifest_bound_files.items(): + require(len(rows.get(label, [])) == 2, f"manifest-shape:{label}") + require(rows[label][0] == relative, f"manifest-path:{label}") + require(row_hash(label) == sha(package / relative), + f"manifest-file:{label}") +print("STAGED_IDENTITY_VALIDATION_PASS") +PY + +# The domain-pack protocol-v1 verifier host-gates to its supported platforms. +# On a host whose verifier is not yet admitted, this release-QA smoke is skipped +# for a local build (JACKAL_LOCAL_BUILD=1); the domain-pack RUNTIME tools then +# fail closed at call time exactly as the verifier dictates. Identity, proof, +# compat, lean-audit, plugin-identity and formal-lane smokes below still run. +if [ "${JACKAL_LOCAL_BUILD:-0}" = "1" ]; then + echo "STAGED_DOMAIN_PACK_SKIPPED reason=local-build host-verifier-not-admitted" +else +PACK_VALIDATION=$(python3 -I -S -B "$PKG/tools/domain_pack_verify.py" \ + --root "$PKG" 2>&1) || { + echo "PACKAGE_V173_REFUSED reason=staged-domain-pack detail=$PACK_VALIDATION" >&2 + exit 4 + } + /usr/bin/printf '%s' "$PACK_VALIDATION" | python3 -I -S -B -c ' + import json + import sys + + try: + report = json.load(sys.stdin) + except (json.JSONDecodeError, UnicodeError): + raise SystemExit(1) + raise SystemExit(0 if isinstance(report, dict) and report.get("status") == "accepted" else 1) + ' || { + echo "PACKAGE_V173_REFUSED reason=staged-domain-pack-status detail=$PACK_VALIDATION" >&2 + exit 4 + } +fi + +PLUGIN_SELFTEST=$("$PKG/plugin/hermes/jackal_hermes" selftest 2>&1) || { + echo "PACKAGE_V173_REFUSED reason=staged-plugin-selftest detail=$PLUGIN_SELFTEST" >&2 + exit 4 +} +case "$PLUGIN_SELFTEST" in + *"plugin_hermes.identity_match=true"*) ;; + *) + echo "PACKAGE_V173_REFUSED reason=staged-plugin-identity detail=$PLUGIN_SELFTEST" >&2 + exit 4 + ;; +esac + +SMOKE_DIR="$STAGE/staged-semantic-smoke" +/bin/mkdir "$SMOKE_DIR" +RANGE_SMOKE_RECEIPT="$SMOKE_DIR/staged-range-receipt.json" +INT_SMOKE_RECEIPT="$SMOKE_DIR/staged-int-receipt.json" +RANGE_SMOKE=$("$PKG/jackal-cert-release" x 0 1 "$RANGE_SMOKE_RECEIPT" 2>&1) || { + echo "PACKAGE_V173_REFUSED reason=staged-range-smoke detail=$RANGE_SMOKE" >&2 + exit 4 +} +case "$RANGE_SMOKE" in *"status=formal-bounded"*) ;; *) + echo "PACKAGE_V173_REFUSED reason=staged-range-status detail=$RANGE_SMOKE" >&2 + exit 4 +esac +INT_SMOKE=$("$PKG/jackal-int-cert-release" 0 0 1 2 "$INT_SMOKE_RECEIPT" 2>&1) || { + echo "PACKAGE_V173_REFUSED reason=staged-int-smoke detail=$INT_SMOKE" >&2 + exit 4 +} +case "$INT_SMOKE" in *"status=formal-bounded"*) ;; *) + echo "PACKAGE_V173_REFUSED reason=staged-int-status detail=$INT_SMOKE" >&2 + exit 4 +esac + +RANGE_VERIFY=$("$PKG/jackal-receipt-verify" \ + --receipt "$RANGE_SMOKE_RECEIPT" --checker "$PKG/jackal_cert_check" \ + --expected-evaluator "$EVALUATOR_ID" --expected-checker "$RANGE_CHECKER_ID" \ + --expected-source "$SOURCE_ID" --expected-release-epoch v1.7.2 \ + --expected-command range-bound-cert --expected-expression x \ + --expected-input-lo 0 --expected-input-hi 1 \ + --inventory "$PKG/formal_coverage_inventory.json" --expected-inventory "$COVERAGE_ID" \ + --proof-identity "$PKG/range_proof_identity.json" \ + --expected-proof-identity-file "$RANGE_IDENTITY_FILE_ID" \ + --expected-proof-identity-digest "$RANGE_IDENTITY_DIGEST" 2>&1) || { + echo "PACKAGE_V173_REFUSED reason=staged-range-replay detail=$RANGE_VERIFY" >&2 + exit 4 +} +INT_VERIFY=$("$PKG/jackal-receipt-verify" \ + --receipt "$INT_SMOKE_RECEIPT" --checker "$PKG/jackal_int_cert_check" \ + --expected-evaluator "$INT_PRODUCER_ID" --expected-checker "$INT_CHECKER_ID" \ + --expected-release-epoch v1.7.2 --expected-command integrate-bound-cert \ + --expected-expression 0 --expected-input-lo 0 --expected-input-hi 1 \ + --expected-tolerance 2 --inventory "$PKG/formal_coverage_inventory.json" \ + --expected-inventory "$COVERAGE_ID" \ + --proof-identity "$PKG/int_cert_proof_identity.json" \ + --expected-proof-identity-file "$INT_IDENTITY_FILE_ID" \ + --expected-proof-identity-digest "$INT_IDENTITY_DIGEST" 2>&1) || { + echo "PACKAGE_V173_REFUSED reason=staged-int-replay detail=$INT_VERIFY" >&2 + exit 4 +} +for replay in "$RANGE_VERIFY" "$INT_VERIFY"; do + /usr/bin/printf '%s\n' "$replay" | /usr/bin/grep -F "status=verified verdict=ACCEPT" >/dev/null && + /usr/bin/printf '%s\n' "$replay" | /usr/bin/grep -F "receipt_valid=true" >/dev/null && + /usr/bin/printf '%s\n' "$replay" | /usr/bin/grep -F "checker_verdict=ACCEPT" >/dev/null || { + echo "PACKAGE_V173_REFUSED reason=staged-replay-markers detail=$replay" >&2 + exit 4 + } +done + +# The semantic smokes must not mutate any packaged authority byte. +(cd "$PKG" && shasum -a 256 -c SHA256SUMS >/dev/null) +echo "STAGED_SEMANTIC_VALIDATION_PASS" + +STAGED_TARBALL="$STAGE/$TARBALL_NAME" +python3 -I -S -B - "$PKG" "$STAGED_TARBALL" <<'PY' +import gzip +import pathlib +import sys +import tarfile + +package = pathlib.Path(sys.argv[1]).resolve() +output = pathlib.Path(sys.argv[2]).resolve() +paths = [package, *sorted(package.rglob("*"), key=lambda p: p.relative_to(package).as_posix())] +with output.open("wb") as raw: + with gzip.GzipFile(filename="", mode="wb", fileobj=raw, compresslevel=9, mtime=0) as gz: + with tarfile.open(fileobj=gz, mode="w", format=tarfile.USTAR_FORMAT) as archive: + for path in paths: + relative = path.relative_to(package).as_posix() if path != package else "" + arcname = package.name if not relative else f"{package.name}/{relative}" + info = archive.gettarinfo(str(path), arcname=arcname) + info.uid = 0 + info.gid = 0 + info.uname = "" + info.gname = "" + info.mtime = 1786924800 + info.pax_headers = {} + if path.is_file(): + with path.open("rb") as source: + archive.addfile(info, source) + else: + archive.addfile(info) +PY + +# Blocker F: the preflight narrows the publication window and names an early +# collision. Each publication itself uses macOS renamex_np(RENAME_EXCL), so an +# object appearing after this check is refused atomically rather than replaced. +[ ! -e "$FINAL_PKG" ] && [ ! -L "$FINAL_PKG" ] \ + && [ ! -e "$FINAL_TARBALL" ] && [ ! -L "$FINAL_TARBALL" ] || { + echo "PACKAGE_V173_REFUSED reason=output-appeared-during-build" >&2 + exit 5 +} +publish_noreplace "$PKG" "$FINAL_PKG" || exit 5 +publish_noreplace "$STAGED_TARBALL" "$FINAL_TARBALL" || { + publish_noreplace "$FINAL_PKG" "$PKG" || { + echo "PACKAGE_V173_REFUSED reason=publication-rollback-failed path=$FINAL_PKG" >&2 + exit 5 + } + echo "PACKAGE_V173_REFUSED reason=publication-rolled-back path=$FINAL_TARBALL" >&2 + exit 5 +} + +echo "PACKAGE_V173_BUILD_PASS version=$VER platform=$PLATFORM" +echo "package=$FINAL_PKG" +echo "files=$(cd "$FINAL_PKG" && /usr/bin/find . -type f | /usr/bin/wc -l | /usr/bin/tr -d ' ')" +echo "sha256sums_root=$(sha256 "$FINAL_PKG/SHA256SUMS")" +echo "tarball=$FINAL_TARBALL" +echo "tarball_sha256=$(sha256 "$FINAL_TARBALL")" +echo "tarball_bytes=$(/usr/bin/wc -c < "$FINAL_TARBALL" | /usr/bin/tr -d ' ')" diff --git a/release/capability_inventory_v1.json b/release/capability_inventory_v1.json index 8d66f97..ed5247d 100644 --- a/release/capability_inventory_v1.json +++ b/release/capability_inventory_v1.json @@ -1 +1 @@ -{"catalog":{"path":"plugin/hermes/tools.json","sha256":"53c823f07db512b82e01a4f132ff43be426b4b227c436e8853c5144ae0504e87","version":"v1.7.3"},"inputs":[{"path":"tools/capability_inventory.py","sha256":"a966660ef94d7b788be9f92451a78e43b41e12ae2c4e942834c1703994c2ccc0"},{"path":"plugin/hermes/tools.json","sha256":"53c823f07db512b82e01a4f132ff43be426b4b227c436e8853c5144ae0504e87"},{"path":"plugin/hermes/profiles/core.json","sha256":"49f33ba23cca5ab940f1929604f61491bc914d092f291cda4fe4f06b37d042d3"},{"path":"plugin/hermes/profiles/formal.json","sha256":"9be2b3144486311d9ba7f1d41c5033eb8e2553e9d12b71d46e512401f57a084b"},{"path":"plugin/hermes/profiles/full.json","sha256":"0db937da01737bbc0341a591ecd23e55008d8ffc02368517c7d1e7da8b309dec"},{"path":"plugin/hermes/server.py","sha256":"4c42725d797ac78ed20d3e843e602b1c60c88bd13f74e06c65a6b4016b3b7daf"},{"path":"plugins/jackel/.codex-plugin/plugin.json","sha256":"49bbd046759b045add1caf1f19300431fe7d697b59bfd93b57daf1d7edb709ff"},{"path":"plugins/jackel/mcp/server.py","sha256":"d307e3534e3451e59f9955ef2aac459bfb8c2d72239aa2325641d0487064f5f5"},{"path":"release/MANIFEST.sha256","sha256":"ac52dafc0e9edbf74dde56b358c3c55ab5b705d3b66811558156c480b3530509"},{"path":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"path":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"path":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"}],"release":{"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"state":"v1.7.3","statement":"Published release identity; the annotated v1.7.3 tag and GitHub release must bind these exact bytes.","version":"v1.7.3"},"schema":"jackal-capability-inventory-v1","status_vocabulary":["bounded","checked","estimated","exact","formal-bounded","indeterminate","model-based","ok","refused","structural-exact","verified","verified-program-evidence","verified-program-receipt"],"tool_count":41,"tools":[{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_range_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"826bed7e2645735d5d333040eaa8c28425df90b6e87f8dd6aa94df1cc40ace45","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded receipt with the certificate embedded (or refuse). Inputs: expression: Anubis expression in the single variable x, restricted to the certified fragment.; input_lo: Interval lower bound as an integer or reduced ℚ (e.g. '1', '2/3').; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-gaussian","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_gaussian_integral","profiles":["formal","full"],"refusal_boundary":"Only the exact catalog-declared Gaussian form and canonical rational bounds/tolerance are admitted. Any other form, failed enclosure, checker rejection, or pin/identity mismatch refuses without downgrade.","release_state":"v1.7.3","schema_sha256":"4a43f67d68610c9e7b13f8bc8195c6c3e9ea24493494eb5aca8e768d707adb13","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a zero-libm formal-bounded Gaussian integral receipt, rerun the pinned checker, or refuse without downgrade. Inputs: expression: Exact canonical exp(-A*(x-mu)^2) expression; all other expressions refuse.; input_lo: Integration lower bound as a canonical rational.; input_hi: Integration upper bound as a canonical rational.; tolerance: Maximum enclosure width as a positive canonical rational."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-int-cert","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_bound_cert","profiles":["formal","full"],"refusal_boundary":"Only the request-bound v1.7.2 composed-integral fragment and canonical bounds/tolerance are admitted. Request-unbound v1.7.0 evidence, unsupported syntax, failed subdivision, checker rejection, or identity mismatch refuses without using the weaker float lane.","release_state":"v1.7.3","schema_sha256":"1229ede1ee518a9b19d3a201268e598fac6fd52fd2eef1bb379f920d6093b9cd","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a request-bound certified composed definite-integral formal receipt (v1.7.2): the untrusted exact-rational producer mirrors the engine's adaptive subdivision, the pinned Lean-proved jackal_int_cert_check binds the exact raw expression/bounds/tolerance and re-checks the whole subdivision-tree certificate (theorem int_cert_sound), and the receipt is independently re-verified before returning. Request-unbound v1.7.0 receipts are revoked. Certified fragment: num/var/neg/add/sub/mul/div/pow(0..4096)/sin/cos/abs in x. Everything else refuses. The weaker float lane jackal_integrate_bound stays status=bounded and is NOT this tool. Inputs: expression: Integrand in the single variable x, restricted to the certified fragment (num/var/neg/add/sub/mul/div/pow/sin/cos/abs).; input_lo: Integration lower bound as an integer or reduced canonical rational (e.g. '0', '2/3').; input_hi: Integration upper bound as a canonical rational, strictly above input_lo.; tolerance: Maximum enclosure width as a positive canonical rational (e.g. '1/100')."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-receipt-registry","identities":[{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_verify_receipt","profiles":["core","formal","full"],"refusal_boundary":"Only closed-registry range/rational, Gaussian, and current request-bound int-cert receipts matching independent caller expectations are replayed. Unknown epochs/variants, copied rather than caller-pinned expectations, revoked int-cert evidence, or checker/pin mismatch refuses.","release_state":"v1.7.3","schema_sha256":"988b83705212769a01eb2e5f5b44322b5728d5fd86eef4f64f7a4a37e378fc1f","status_classes":["verified","refused"],"supported_fragment":"Re-run the matching pinned Lean-proved checker over an embedded certificate using a closed epoch/variant registry: current v1.7.2 range/rational and request-bound int_cert, replay-only v1.5.0 range/rational, or Gaussian v1.5.0. Request-unbound v1.7.0 int_cert receipts refuse. Inputs: receipt: A jackal-formal-receipt-v1 JSON document.; expected_release_epoch: Caller-authorized release epoch, not copied from the receipt.; expected_command: Caller-authorized operation: range-bound-cert or integrate.; expected_expression: Exact raw expression supplied by the caller.; expected_input_lo: Exact raw lower-bound token supplied by the caller.; expected_input_hi: Exact raw upper-bound token supplied by the caller.; expected_tolerance: Exact raw tolerance token; required for Gaussian and int_cert receipts and forbidden for range receipts."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_sqrt_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"bc611de421d812aa6d6d8772fb986c17bcde74d7fe70ea31ff22433335d67c6d","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q sqrt(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'sqrt(x)' on a canonical rational interval; every other expression refuses without downgrade. v1.4.0 fragment extension. Inputs: expression: Must equal 'sqrt(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational (e.g. '2', '1/4'); must be >= 0.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_exp_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"9cc7bee07eebc566a9e267ad1b30c10a73cb25c18090ed2f9a3e9ec48550b928","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q exp(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'exp(x)' on a canonical rational interval [lo, hi] (general-sign since v1.5.0); every other expression refuses without downgrade. v1.4.1 fragment extension. Inputs: expression: Must equal 'exp(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational; any sign (general-sign since v1.5.0).; input_hi: Interval upper bound (canonical rational, hi >= lo); the producer picks a Taylor degree with 2*hi <= n+1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_ln_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"16dfb2b64dc9e290e1c062eba898233b04b187f1b244f6cc06433c48d1b7da45","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q ln(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'ln(x)' on a canonical rational interval with lo > 0; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'ln(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational; must be > 0.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_sin_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"d578799057048871ff13eca207bda2f9564261fce975801904d8cb34370cc7fe","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q sin(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'sin(x)' on a canonical rational interval whose midpoint m satisfies |m| <= 1; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'sin(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo); midpoint (lo+hi)/2 must satisfy |m| <= 1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_cos_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"d0f575ac0dbfe5e64aede075ae30bb1a625f05963e772febca6ac180b29f062b","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q cos(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'cos(x)' on a canonical rational interval whose midpoint m satisfies |m| <= 1; every other expression refuses without downgrade. Shares the sin_rat producer (--op cos). v1.5.0 fragment extension. Inputs: expression: Must equal 'cos(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo); midpoint (lo+hi)/2 must satisfy |m| <= 1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_atan_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"f16e48c7a37e284e124fe20766c7db2b90b4eed8fb748c2efebc9ee7c4b80767","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q atan(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'atan(x)' on a canonical rational interval; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'atan(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_tanh_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"6f9b24d732cc6fc2b0ad9ef7d51fa8cd88f2a344b3152c54f288f6a25a8fe05a","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q tanh enclosure via the untrusted composite producer + Lean-proved checker. NO libm on the proof-decision path. tanh is not an engine grammar token: admits ONLY the literal composite expression '1-2/(exp(2*x)+1)' (= tanh(x) mathematically) on a canonical rational interval with |lo|,|hi| <= 20; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal '1-2/(exp(2*x)+1)' after whitespace normalization (the frozen tanh-defining composite).; input_lo: Interval lower bound as an integer or reduced rational; |lo| <= 20.; input_hi: Interval upper bound (canonical rational, hi >= lo); |hi| <= 20."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_exact","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"42319cf6d3e3f7a8da025e880b8dfc02eb2c6e3128f8b93c11f41545d8bf1d8d","status_classes":["exact","refused"],"supported_fragment":"Exact big-rational arithmetic (status=exact). NOT formal: computationally exact, outside the Lean certificate chain. Inputs: expression: Integers, decimals, + - * / ^ (integer exponents), parentheses. Everything else refuses."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_evaluate","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"5baa3a344309d714a8b66c9fb4a14a97c8182b3cfe1326faa2e9967840eee17c","status_classes":["estimated","refused"],"supported_fragment":"IEEE f64 expression evaluation (status=estimated). A plain number, honestly labeled: no bound, no proof. Inputs: expression: Full expression grammar incl. transcendental functions and constants."},{"assurance_classes":["checked"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_diff","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"605972a25cde65779e921b8a27b7f1a0c19d540f5330791ec0fb571cccf858ad","status_classes":["checked","refused"],"supported_fragment":"Symbolic d/dx with numeric self-verification (status=checked). Sampled agreement is a check, not a proof of identity. Inputs: expression: Expression in x; non-differentiable functions fail closed."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"6d05a705ff580a831f75cbcd2079fe88c3b5d9c858bc6b0c3182ec55aa27cd27","status_classes":["estimated","refused"],"supported_fragment":"Fixed-grid Simpson + Richardson error estimate (status=estimated). Grid-limited: NOT a bound. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; panels: Panel count (e.g. '200')."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_adaptive","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"174132e83bff6d18972cf5d88b072b12d7102cad8fdf05197165c64bfac4fea1","status_classes":["estimated","refused"],"supported_fragment":"Adaptive Simpson with refusal semantics (status=estimated). Refuses when unconverged; agreement is still not a bound. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; tolerance: Local tolerance (e.g. '1e-9')."},{"assurance_classes":["bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_bound","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"9932617903499a2ed2baa4ac213f061f422bd8f2e60bca5bf05225a9f9f788a0","status_classes":["bounded","refused"],"supported_fragment":"Certified interval enclosure of an integral (status=bounded). CONDITIONAL on the stated f64/libm rounding model; implementation campaign-tested, NOT mechanized. Never labeled formal. For a Lean-checked formal-bounded composed enclosure over the certified fragment, use jackal_integrate_bound_cert instead. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; tolerance: Max enclosure width (e.g. '1e-6')."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_solve","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"caf1f55ca8ad1fef2e0fb4f5f5bb600edb147f257427de650335500979c13501","status_classes":["estimated","refused"],"supported_fragment":"Bisection root with residual + first-order conditioning diagnostics (status=estimated). Inputs: expression: f(x) whose root is sought.; input_lo: Bracket lower bound (sign change required).; input_hi: Bracket upper bound."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"ea4ca54f74334d678c3daf9c6686fca186041d27bb2f02dabca21a7747e7d416","status_classes":["exact","refused"],"supported_fragment":"Canonical s-expression + SHA-256 of any parsed expression (status=exact). NOT formal: exact computation outside the Lean certificate chain; no exact-cert emitted. Inputs: expression: Any expression the engine grammar parses."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"199fd63f51398c6e883a407d8e2435e42903e9c76f0227d815f3456b3568d9bc","status_classes":["exact","refused"],"supported_fragment":"Dense Q[x] canonical form, degree <= 64 (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Polynomial expression in x within the poly fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_eq","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"76d9390f705758c6ec2d5fe77cd6a1391908f93ef218ebfd5111c067dc32a819","status_classes":["exact","refused"],"supported_fragment":"Decidable polynomial identity over Q[x] (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: lhs: Left polynomial expression in x.; rhs: Right polynomial expression in x."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_gcd","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"dfff2a285e732d52520ea6fe5efabdab5bd6d956c224f30d163ccbbdbd406a5c","status_classes":["exact","refused"],"supported_fragment":"Monic polynomial gcd over Q[x] via Euclid (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: lhs: Left polynomial expression in x.; rhs: Right polynomial expression in x."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_ratfunc_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"3d4c7d73d13aa88606e9e005b7731c19ac63f9fe559b38e6ff777f979afd3b40","status_classes":["exact","refused"],"supported_fragment":"Rational-function canonical form P/Q, gcd-reduced, monic denominator, explicit denominator-nonzero side condition (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Rational-function expression in x within the ratfunc fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_roots_isolate","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"ea98289e6b6319b7c0b3e6e9832e07ff4a9dd06be1d7862956c50df6e1785978","status_classes":["exact","refused"],"supported_fragment":"Sturm-sequence isolation of all distinct real roots (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Polynomial expression in x within the poly fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_alg_sign","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"b4ad3c632887bc8875f8334dea3391017d73f30fa4895d988062882e89c2c1a5","status_classes":["exact","refused"],"supported_fragment":"Exact sign of a Q[x] polynomial at a rational point (status=exact). NOT formal; no exact-cert emitted. Inputs: expression: Polynomial expression in x within the poly fragment.; point: Rational evaluation point (e.g. '3/2')."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_alg_cmp","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"bfea42d3f97e6f0403d11155d667dfec7000719e2aa3af67c8897989a9e2eee4","status_classes":["exact","refused"],"supported_fragment":"Order decision between two isolated real algebraic numbers (status=exact). NOT formal; no exact-cert emitted. Inputs: p: First defining polynomial in x.; a1: First isolating interval lower bound (rational).; b1: First isolating interval upper bound (rational).; q: Second defining polynomial in x.; a2: Second isolating interval lower bound (rational).; b2: Second isolating interval upper bound (rational)."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_xgcd","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"1c7fb606e43e71eeb4ab288c08ea4a6c89efd95beb3f802e084d5d3c1a3beaf6","status_classes":["exact","refused"],"supported_fragment":"Extended gcd with Bezout certificate (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: a: First integer.; b: Second integer."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_mod_pow","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"b3edc74b3901989b9248f8b89feaed2cc396e218abf9ccfca7ab53a99a9c7bc1","status_classes":["exact","refused"],"supported_fragment":"Modular exponentiation via square-and-multiply (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: base: Base integer.; exp: Nonnegative exponent integer.; mod: Modulus integer >= 1."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_mod_inv","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"d0826f19759afacd20d4a5f0d6704a52bce158c6950bb852a5e0774886a4abd7","status_classes":["exact","refused"],"supported_fragment":"Modular inverse with product certificate (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: a: Integer to invert.; m: Modulus integer >= 2; gcd(a, m) must be 1."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_crt","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"d44aebbbcb3b00ad0d192581533c5cfdb164e26431f3ed850406c8ecfa5044b4","status_classes":["exact","refused"],"supported_fragment":"Chinese remainder reconstruction over pairwise-coprime moduli, up to 16 pairs (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: args: Space-separated residue/modulus pairs: 'r1 m1 r2 m2 [...]' (e.g. '2 3 3 5 2 7')."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_divides","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"1191b2b4ce3a9a5c3a1dafb0917fad46ca9c3375c73f4ae59ff7a389d513adb4","status_classes":["exact","refused"],"supported_fragment":"Exact divisibility decision (status=exact). NOT formal; no exact-cert emitted. Inputs: a: Candidate divisor integer.; b: Dividend integer."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_prime_cert","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"3ff03881b24f8fd94db68b210874010e66ce0e3d32666d98a21c1bc40ccc5646","status_classes":["exact","refused"],"supported_fragment":"Pratt primality certificate or composite divisor witness, budgeted and fail-closed (status=exact; n <= 10^60, Pratt tree depth <= 64, nodes <= 512). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: n: Integer >= 2, at most 61 digits."},{"assurance_classes":["estimated","model-based","checked","bounded","formal-bounded","exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"claim-router","identities":[{"label":"claim_kernel","locator":"tools/claim_kernel.py","sha256":"77b0f85ad5fb7214f88898b60ea29ea9fd7be740c38b655388444e6e5181f348"},{"label":"claim_router","locator":"tools/claim_router.py","sha256":"02328cf177a0423bdc5cbca6ec0ea946bb0679bbd3dc6c24140d32598e575afb"},{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"},{"label":"claim_inference_registry","locator":"release/claim/inference_registry_v1.json","sha256":"c70b33d5aee8071b5125e6a5f8ffe5226fc22a137d920c17d9b3463968be13f0"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_claim","profiles":["core","formal","full"],"refusal_boundary":"Only jackal-claim-request-v1 and its closed step vocabulary are compiled. Policy, identity, schema, route, or assurance failures refuse; fallback is off by default and any caller-enabled fallback remains explicit in the route trace rather than silently changing assurance.","release_state":"v1.7.3","schema_sha256":"4d2703ff772433f39ac8b6555727e856685b0e5042b9c2cc8fcaa4402d6b9153","status_classes":["ok","refused"],"supported_fragment":"Compile a structured jackal-claim-request-v1 into a canonical, content-addressed jackal-claim-bundle-v1 evidence graph through the deterministic policy router. Routes through exact, current/archival range-family, Gaussian, request-bound composed-integral, machine, and unit lanes; emits a route trace naming candidates and refusal reasons; and refuses rather than silently downgrading (allow_fallback defaults false). The bundle is independently replayable via jackal_verify_bundle. Inputs: request: jackal-claim-request-v1 object: {schema, steps:[{id, op, ...}], root, policy?, nonce?, emitted_at_unix?, max_age_seconds?, expires_at_unix?}. Step ops: input, exact, enclose, gaussian, integrate_cert, machine, interval_add/sub/mul/div, threshold, decision, convert, and, model, passthrough, attach."},{"assurance_classes":["estimated","model-based","checked","bounded","formal-bounded","exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"claim-verifier","identities":[{"label":"claim_verifier","locator":"tools/claim_bundle_verify.py","sha256":"e0fcb9540c730bd9bb492b528ed42d29d49fc775b3aa0f9b831b6264fd68fd22"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"},{"label":"claim_inference_registry","locator":"release/claim/inference_registry_v1.json","sha256":"c70b33d5aee8071b5125e6a5f8ffe5226fc22a137d920c17d9b3463968be13f0"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_verify_bundle","profiles":["core","formal","full"],"refusal_boundary":"Only canonical bundles matching separately caller-pinned epoch, policy, root proposition, time, and nonce are replayed. Semantic, graph, freshness, evidence, checker, or pin ambiguity returns refused or indeterminate exactly as declared; it is never converted to success.","release_state":"v1.7.3","schema_sha256":"9e3acec17637a352bc88e3b08e8679a34f1efae3539fe1cce05646212be4cb5f","status_classes":["verified","refused","indeterminate"],"supported_fragment":"Independently replay a jackal-claim-bundle-v1 against caller-pinned expectations. The standalone dependency-free verifier recomputes every canonical byte and hash, revalidates the DAG, selects only the closed current/archival range, Gaussian, or current request-bound int-cert checker/proof tuple, re-runs embedded evidence, recomputes machine/unit mathematics, re-evaluates every inference rule and assurance-axis propagation, enforces consequence-class floors and policy, and recomputes the deterministic rendering. Returns verified | refused | indeterminate with exact reasons — never a generic green badge. Inputs: bundle: The jackal-claim-bundle-v1 object to replay.; expected_release_epoch: Caller-pinned epoch (e.g. 'v1.6.0'); never copied from the bundle.; expected_policy_sha256: Caller-pinned SHA-256 of the canonical policy bytes.; expected_root_proposition: Caller-pinned canonical root proposition IR object.; verification_time_unix: Caller-supplied verification time (unix seconds) for freshness/expiry checks.; expected_nonce: Caller nonce; the bundle root must bind exactly this nonce."},{"assurance_classes":["structural-exact"],"consequence_ceiling":"informational","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"structural-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"1a3b2c95dcdc7c7337fbe0ecb34043b70c3697752d6dc585f45f3c7d4f1b0706"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"22984f511208af2d7a318f1a43306d95a4b0f61876d8b44f34f39a2ded6d573d"},{"label":"domain_pack_test_exists_checker","locator":"tools/test_exists_verify.py","sha256":"598cb99e1eb70c9410ca87345efee346f73e43aaf3625427dca17ea04231caea"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_test_exists","profiles":["full"],"refusal_boundary":"Only byte-exact source/citation structure described by the schema is accepted after independent file-byte recomputation. Path traversal, malformed symbols/hashes, missing text/declarations, or checker mismatch refuses; the result never asserts test execution or correctness.","release_state":"v1.7.3","schema_sha256":"9685ecf3bcf78a3a26916455cc528cdeac137420e8694447e2865b33890f9d46","status_classes":["structural-exact","refused"],"supported_fragment":"Domain pack jackal.programming.source, operation programming.source.test_exists.v1, routed through pack-route. States one byte-exact STRUCTURAL fact: a declaration-shaped occurrence of `symbol` exists at `declaration_line` in a file whose content hash is exactly `file_sha256`, and the file contains exactly `declaration_count` such occurrences. The engine validates the canonical FORM; the manifest-pinned independent checker tools/test_exists_verify.py then recomputes every claimed field from the real bytes on disk and only an ACCEPT verdict returns success, so a misstated hash, line or count refuses instead of minting a certificate. ASSURANCE ceiling exact; CONSEQUENCE ceiling informational, and the second does not rise with the first: a test-exists-cert is NEVER evidence that the code under test is correct, that the test executes, that it is collected by any runner, or that it asserts anything at all. NOT formal: no Lean checker and no theorem are involved. Do not cite this certificate in support of a correctness claim. Inputs: file_path: Repository-relative path token; absolute paths and parent traversal refuse `prog-path`.; file_sha256: Exactly 64 lowercase hex characters; the checker recomputes it from the file bytes.; symbol: Identifier of the declaration; a non-identifier refuses `prog-symbol`.; declaration_line: 1-based line of the declaration as a canonical positive integer.; declaration_count: Total declaration-shaped occurrences of `symbol` in the file; `0` refuses `prog-absent`."},{"assurance_classes":["structural-exact"],"consequence_ceiling":"informational","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"structural-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"1a3b2c95dcdc7c7337fbe0ecb34043b70c3697752d6dc585f45f3c7d4f1b0706"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"22984f511208af2d7a318f1a43306d95a4b0f61876d8b44f34f39a2ded6d573d"},{"label":"domain_pack_test_exists_checker","locator":"tools/test_exists_verify.py","sha256":"598cb99e1eb70c9410ca87345efee346f73e43aaf3625427dca17ea04231caea"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_claim_cites_test","profiles":["full"],"refusal_boundary":"Only byte-exact source/citation structure described by the schema is accepted after independent file-byte recomputation. Path traversal, malformed symbols/hashes, missing text/declarations, or checker mismatch refuses; the result never asserts test execution or correctness.","release_state":"v1.7.3","schema_sha256":"69a533155bde04bfd5dedd43e9d63acd02f3e2773757936e9e1714458e20abd4","status_classes":["structural-exact","refused"],"supported_fragment":"Domain pack jackal.programming.source, operation programming.source.claim_cites_test.v1, routed through pack-route. Resolves a citation: `claim_text` occurs verbatim in the document at `doc_path`/`doc_sha256`, and `symbol` has a declaration-shaped occurrence in the cited test file at `test_path`/`test_sha256`. Resolution is all this establishes. It does NOT establish that the cited test covers, exercises or supports the claim — the cited test may check something entirely different, which is the exact defect this operation exists to bound rather than hide. The manifest-pinned tools/test_exists_verify.py re-runs over the certificate and only ACCEPT returns success, so a claim text absent from the document or a dangling citation refuses. ASSURANCE ceiling exact; CONSEQUENCE ceiling informational, and the second does not rise with the first. NOT formal: no Lean checker and no theorem are involved. Inputs: doc_path: Repository-relative path of the document making the claim.; doc_sha256: Exactly 64 lowercase hex characters for the document bytes.; claim_text: The claim sentence, verbatim, 1..2048 bytes; it must occur in the document.; test_path: Repository-relative path of the cited test file.; test_sha256: Exactly 64 lowercase hex characters for the cited test file bytes.; symbol: Identifier the citation resolves to inside the cited test file."},{"assurance_classes":["exact"],"consequence_ceiling":"decision-boundary","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"decision-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"1a3b2c95dcdc7c7337fbe0ecb34043b70c3697752d6dc585f45f3c7d4f1b0706"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"22984f511208af2d7a318f1a43306d95a4b0f61876d8b44f34f39a2ded6d573d"},{"label":"domain_pack_decision_checker","locator":"tools/decision_verify.py","sha256":"f1ad7c9fbd4c1d899dbb4bebabbbeb97e97a56bd4b279ad7d8ec3722bf12e0f6"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_decision_rank","profiles":["full"],"refusal_boundary":"Only 2..6 schema-valid options under a caller-declared admissible numeric criterion are ranked. Invalid shape/sense/unit, value-judgment criteria, zero top margin, or checker mismatch refuses; caller values are not treated as measurements or confidence intervals.","release_state":"v1.7.3","schema_sha256":"843fe08464d40d97094eeb6424c0c29a3e2617172ba56262ca4122468a8bb92f","status_classes":["exact","refused"],"supported_fragment":"Domain pack jackal.decision.matrix, operation decision.matrix.rank.v1, routed through pack-route. Orders 2..6 labelled options by a caller-declared numeric criterion and emits a jackal-decision-cert-v1 naming the selected option, the runner-up and the exact margin; the manifest-pinned tools/decision_verify.py recomputes the whole ordering from the certificate's own option values and only ACCEPT returns success. Criterion admissibility is decided by the engine against a fixed word list, so a bare value judgment refuses `decision-value-judgment`; a top-two tie refuses `decision-margin-zero`. ASSURANCE ceiling exact; CONSEQUENCE ceiling decision-boundary. The arithmetic is exact and the choice of criterion is not: the declared criterion and the declared option values remain the caller's, this result is not a claim that the criterion is the right one, the values are not measurements, and the margin is not a confidence interval. For the closed-unit lane that additionally requires a declared unit, use jackal_decision_rank_v2. NOT formal: no Lean checker and no theorem are involved. Inputs: decision_id: Caller's identifier for this decision, bound into the certificate. Bytes are restricted to [A-Za-z0-9_]; anything else refuses `prog-symbol`.; criterion: The declared numeric criterion (e.g. 'latency_ms'); a value judgment refuses `decision-value-judgment`.; sense: Exactly 'min' or 'max'; anything else refuses `decision-sense-unknown`.; options: 2..6 whitespace-separated `label value` pairs, e.g. 'a 10 b 20 c 30'. Values are canonical integers. A label containing whitespace shifts the pairing and refuses `pack-args-shape`; it is never silently re-paired."},{"assurance_classes":["exact"],"consequence_ceiling":"decision-boundary","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"decision-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"1a3b2c95dcdc7c7337fbe0ecb34043b70c3697752d6dc585f45f3c7d4f1b0706"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"22984f511208af2d7a318f1a43306d95a4b0f61876d8b44f34f39a2ded6d573d"},{"label":"domain_pack_decision_checker","locator":"tools/decision_verify.py","sha256":"f1ad7c9fbd4c1d899dbb4bebabbbeb97e97a56bd4b279ad7d8ec3722bf12e0f6"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_decision_rank_v2","profiles":["full"],"refusal_boundary":"Only 2..6 schema-valid options under a caller-declared admissible numeric criterion are ranked. Invalid shape/sense/unit, value-judgment criteria, zero top margin, or checker mismatch refuses; caller values are not treated as measurements or confidence intervals.","release_state":"v1.7.3","schema_sha256":"cdc8abba09426977a5319b52410204f21e2e1eb7b38a9de31de751fcb862e78a","status_classes":["exact","refused"],"supported_fragment":"Domain pack jackal.decision.matrix, operation decision.matrix.rank.v2, routed through pack-route. Same deterministic ordering as jackal_decision_rank, plus a REQUIRED declared unit drawn from a closed vocabulary: the 65 canonical ids of release/claim/unit_registry_v1.json excluding the dimensionless identity `one` (66 ids in the registry, `one` is not admitted here). Matching is exact-token and case-sensitive; an alias, a spelled-out name such as 'millisecond', a different case, or the dimensionless identity all refuse `decision-unit-unknown`, and an empty unit refuses `decision-unit-missing`. Emits jackal-decision-cert-v2, re-checked by the manifest-pinned tools/decision_verify.py; only ACCEPT returns success. ASSURANCE ceiling exact; CONSEQUENCE ceiling decision-boundary. Honest residual: a declared unit is NOT a measurement. The closed vocabulary forces the caller to name a dimension, and nothing more — a value-judgment criterion that survives the engine's word list is still accepted when a real unit is declared (`most_elegant` in `ms` ranks), and the values themselves remain caller-declared. NOT formal: no Lean checker and no theorem are involved. Inputs: decision_id: Caller's identifier for this decision, bound into the certificate. Bytes are restricted to [A-Za-z0-9_]; anything else refuses `prog-symbol`.; criterion: The declared numeric criterion; a value judgment refuses `decision-value-judgment` even with an admissible unit.; unit: One canonical unit id from release/claim/unit_registry_v1.json, excluding `one`. Exact token, case-sensitive: 'ms' is admitted, 'millisecond' and 'MS' refuse `decision-unit-unknown`.; sense: Exactly 'min' or 'max'; anything else refuses `decision-sense-unknown`.; options: 2..6 whitespace-separated `label value` pairs, e.g. 'a 10 b 20 c 30'. Values are canonical integers. A label containing whitespace shifts the pairing and refuses `pack-args-shape`; it is never silently re-paired."},{"assurance_classes":["verified-program-evidence"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"4b80e29bdffc0737f05a6e215fce8cce3b6b828c24afbf55c68443399e5119dc"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_check_program","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"177cfcf9dfcd6bbc6e657eb83b88f04bfedaa0f28f81307077a776e2052df1e2","status_classes":["verified-program-evidence","refused"],"supported_fragment":"Run a caller-pinned Anubis compiler only as `build --evidence` in Safe mode, never execute the compiled artifact, then independently close and replay the resulting strict anubis.program-evidence.v3 package under inventory-safe-v1. Emits only verified-program-evidence or a named refusal. This profile checks producer-attested function/policy inventories but explicitly does not establish policy-construct totality, source-to-VC proof, SMT-to-CNF proof, source-native refinement, runtime behavior, or universal soundness. Inputs: source_path: Local regular non-symlink Anubis source path.; anubis_bin: Local regular non-symlink Anubis executable; caller-pinned and hashed before/after build.; expected_source_sha256: Caller-pinned exact source SHA-256.; expected_compiler_sha256: Caller-pinned approved Anubis executable SHA-256.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1; contracted-safe-v1 refuses.; nonce: Caller nonce bound into the receipt.; out_root: New local output root; existing paths refuse."},{"assurance_classes":["verified-program-evidence"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"4b80e29bdffc0737f05a6e215fce8cce3b6b828c24afbf55c68443399e5119dc"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_verify_program","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"45c7aae87c329925f6bd6b9100efc7d099d70fcaeaba915ee59937f019e1153d","status_classes":["verified-program-evidence","refused"],"supported_fragment":"Independently verify caller-selected Anubis Safe source and evidence bytes under inventory-safe-v1: strict v3 roster, exact manifest closure, source/compiler/artifact/policy pins, producer-summary reconciliation, one-to-one solver/proof paths and counters, approved Z3 UNSAT replay, and independent RUP replay. Never executes the artifact and never claims independent policy-construct totality or source-native refinement. Inputs: source_path: Caller-selected regular non-symlink Anubis source path.; evidence_dir: Caller-selected strict anubis.program-evidence.v3 directory.; expected_source_sha256: Caller-pinned exact source SHA-256.; expected_compiler_sha256: Caller-pinned producer executable SHA-256.; expected_artifact_sha256: Caller-pinned sealed artifact SHA-256; artifact bytes are read but never executed.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1.; nonce: Caller nonce bound into the receipt."},{"assurance_classes":["verified-program-receipt"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"4b80e29bdffc0737f05a6e215fce8cce3b6b828c24afbf55c68443399e5119dc"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_verify_program_receipt","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"6bb75d81aebf6f2b3b20900357204e9ef0858cdac412ea016868028cdd2a67d3","status_classes":["verified-program-receipt","refused"],"supported_fragment":"Recompute a jackal-anubis-program-receipt-v1 from caller-selected source/evidence bytes and independent caller pins, rejecting outer-digest-consistent semantic laundering. Success is only verified-program-receipt; it does not raise the underlying inventory-safe-v1 assurance ceiling. Inputs: receipt: Program receipt object to replay; its own pins are never trusted.; source_path: Caller-selected regular source path.; evidence_dir: Caller-selected evidence directory.; expected_source_sha256: Caller-pinned source SHA-256.; expected_compiler_sha256: Caller-pinned compiler SHA-256.; expected_artifact_sha256: Caller-pinned artifact SHA-256.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1.; nonce: Caller nonce; never copied from the receipt."}],"unique_tool_count":41} +{"catalog":{"path":"plugin/hermes/tools.json","sha256":"53c823f07db512b82e01a4f132ff43be426b4b227c436e8853c5144ae0504e87","version":"v1.7.3"},"inputs":[{"path":"tools/capability_inventory.py","sha256":"a966660ef94d7b788be9f92451a78e43b41e12ae2c4e942834c1703994c2ccc0"},{"path":"plugin/hermes/tools.json","sha256":"53c823f07db512b82e01a4f132ff43be426b4b227c436e8853c5144ae0504e87"},{"path":"plugin/hermes/profiles/core.json","sha256":"49f33ba23cca5ab940f1929604f61491bc914d092f291cda4fe4f06b37d042d3"},{"path":"plugin/hermes/profiles/formal.json","sha256":"9be2b3144486311d9ba7f1d41c5033eb8e2553e9d12b71d46e512401f57a084b"},{"path":"plugin/hermes/profiles/full.json","sha256":"0db937da01737bbc0341a591ecd23e55008d8ffc02368517c7d1e7da8b309dec"},{"path":"plugin/hermes/server.py","sha256":"4c42725d797ac78ed20d3e843e602b1c60c88bd13f74e06c65a6b4016b3b7daf"},{"path":"plugins/jackel/.codex-plugin/plugin.json","sha256":"49bbd046759b045add1caf1f19300431fe7d697b59bfd93b57daf1d7edb709ff"},{"path":"plugins/jackel/mcp/server.py","sha256":"b5916270588db1fbb68b4d520c5f5e9d0fabb84e26602f18ad0a2927a38cece9"},{"path":"release/MANIFEST.sha256","sha256":"ac52dafc0e9edbf74dde56b358c3c55ab5b705d3b66811558156c480b3530509"},{"path":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"path":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"path":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"}],"release":{"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"state":"v1.7.3","statement":"Published release identity; the annotated v1.7.3 tag and GitHub release must bind these exact bytes.","version":"v1.7.3"},"schema":"jackal-capability-inventory-v1","status_vocabulary":["bounded","checked","estimated","exact","formal-bounded","indeterminate","model-based","ok","refused","structural-exact","verified","verified-program-evidence","verified-program-receipt"],"tool_count":41,"tools":[{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_range_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"826bed7e2645735d5d333040eaa8c28425df90b6e87f8dd6aa94df1cc40ace45","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded receipt with the certificate embedded (or refuse). Inputs: expression: Anubis expression in the single variable x, restricted to the certified fragment.; input_lo: Interval lower bound as an integer or reduced ℚ (e.g. '1', '2/3').; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-gaussian","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_gaussian_integral","profiles":["formal","full"],"refusal_boundary":"Only the exact catalog-declared Gaussian form and canonical rational bounds/tolerance are admitted. Any other form, failed enclosure, checker rejection, or pin/identity mismatch refuses without downgrade.","release_state":"v1.7.3","schema_sha256":"4a43f67d68610c9e7b13f8bc8195c6c3e9ea24493494eb5aca8e768d707adb13","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a zero-libm formal-bounded Gaussian integral receipt, rerun the pinned checker, or refuse without downgrade. Inputs: expression: Exact canonical exp(-A*(x-mu)^2) expression; all other expressions refuse.; input_lo: Integration lower bound as a canonical rational.; input_hi: Integration upper bound as a canonical rational.; tolerance: Maximum enclosure width as a positive canonical rational."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-int-cert","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_bound_cert","profiles":["formal","full"],"refusal_boundary":"Only the request-bound v1.7.2 composed-integral fragment and canonical bounds/tolerance are admitted. Request-unbound v1.7.0 evidence, unsupported syntax, failed subdivision, checker rejection, or identity mismatch refuses without using the weaker float lane.","release_state":"v1.7.3","schema_sha256":"1229ede1ee518a9b19d3a201268e598fac6fd52fd2eef1bb379f920d6093b9cd","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a request-bound certified composed definite-integral formal receipt (v1.7.2): the untrusted exact-rational producer mirrors the engine's adaptive subdivision, the pinned Lean-proved jackal_int_cert_check binds the exact raw expression/bounds/tolerance and re-checks the whole subdivision-tree certificate (theorem int_cert_sound), and the receipt is independently re-verified before returning. Request-unbound v1.7.0 receipts are revoked. Certified fragment: num/var/neg/add/sub/mul/div/pow(0..4096)/sin/cos/abs in x. Everything else refuses. The weaker float lane jackal_integrate_bound stays status=bounded and is NOT this tool. Inputs: expression: Integrand in the single variable x, restricted to the certified fragment (num/var/neg/add/sub/mul/div/pow/sin/cos/abs).; input_lo: Integration lower bound as an integer or reduced canonical rational (e.g. '0', '2/3').; input_hi: Integration upper bound as a canonical rational, strictly above input_lo.; tolerance: Maximum enclosure width as a positive canonical rational (e.g. '1/100')."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-receipt-registry","identities":[{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_verify_receipt","profiles":["core","formal","full"],"refusal_boundary":"Only closed-registry range/rational, Gaussian, and current request-bound int-cert receipts matching independent caller expectations are replayed. Unknown epochs/variants, copied rather than caller-pinned expectations, revoked int-cert evidence, or checker/pin mismatch refuses.","release_state":"v1.7.3","schema_sha256":"988b83705212769a01eb2e5f5b44322b5728d5fd86eef4f64f7a4a37e378fc1f","status_classes":["verified","refused"],"supported_fragment":"Re-run the matching pinned Lean-proved checker over an embedded certificate using a closed epoch/variant registry: current v1.7.2 range/rational and request-bound int_cert, replay-only v1.5.0 range/rational, or Gaussian v1.5.0. Request-unbound v1.7.0 int_cert receipts refuse. Inputs: receipt: A jackal-formal-receipt-v1 JSON document.; expected_release_epoch: Caller-authorized release epoch, not copied from the receipt.; expected_command: Caller-authorized operation: range-bound-cert or integrate.; expected_expression: Exact raw expression supplied by the caller.; expected_input_lo: Exact raw lower-bound token supplied by the caller.; expected_input_hi: Exact raw upper-bound token supplied by the caller.; expected_tolerance: Exact raw tolerance token; required for Gaussian and int_cert receipts and forbidden for range receipts."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_sqrt_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"bc611de421d812aa6d6d8772fb986c17bcde74d7fe70ea31ff22433335d67c6d","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q sqrt(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'sqrt(x)' on a canonical rational interval; every other expression refuses without downgrade. v1.4.0 fragment extension. Inputs: expression: Must equal 'sqrt(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational (e.g. '2', '1/4'); must be >= 0.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_exp_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"9cc7bee07eebc566a9e267ad1b30c10a73cb25c18090ed2f9a3e9ec48550b928","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q exp(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'exp(x)' on a canonical rational interval [lo, hi] (general-sign since v1.5.0); every other expression refuses without downgrade. v1.4.1 fragment extension. Inputs: expression: Must equal 'exp(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational; any sign (general-sign since v1.5.0).; input_hi: Interval upper bound (canonical rational, hi >= lo); the producer picks a Taylor degree with 2*hi <= n+1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_ln_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"16dfb2b64dc9e290e1c062eba898233b04b187f1b244f6cc06433c48d1b7da45","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q ln(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'ln(x)' on a canonical rational interval with lo > 0; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'ln(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational; must be > 0.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_sin_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"d578799057048871ff13eca207bda2f9564261fce975801904d8cb34370cc7fe","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q sin(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'sin(x)' on a canonical rational interval whose midpoint m satisfies |m| <= 1; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'sin(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo); midpoint (lo+hi)/2 must satisfy |m| <= 1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_cos_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"d0f575ac0dbfe5e64aede075ae30bb1a625f05963e772febca6ac180b29f062b","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q cos(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'cos(x)' on a canonical rational interval whose midpoint m satisfies |m| <= 1; every other expression refuses without downgrade. Shares the sin_rat producer (--op cos). v1.5.0 fragment extension. Inputs: expression: Must equal 'cos(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo); midpoint (lo+hi)/2 must satisfy |m| <= 1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_atan_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"f16e48c7a37e284e124fe20766c7db2b90b4eed8fb748c2efebc9ee7c4b80767","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q atan(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'atan(x)' on a canonical rational interval; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'atan(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_tanh_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"6f9b24d732cc6fc2b0ad9ef7d51fa8cd88f2a344b3152c54f288f6a25a8fe05a","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q tanh enclosure via the untrusted composite producer + Lean-proved checker. NO libm on the proof-decision path. tanh is not an engine grammar token: admits ONLY the literal composite expression '1-2/(exp(2*x)+1)' (= tanh(x) mathematically) on a canonical rational interval with |lo|,|hi| <= 20; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal '1-2/(exp(2*x)+1)' after whitespace normalization (the frozen tanh-defining composite).; input_lo: Interval lower bound as an integer or reduced rational; |lo| <= 20.; input_hi: Interval upper bound (canonical rational, hi >= lo); |hi| <= 20."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_exact","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"42319cf6d3e3f7a8da025e880b8dfc02eb2c6e3128f8b93c11f41545d8bf1d8d","status_classes":["exact","refused"],"supported_fragment":"Exact big-rational arithmetic (status=exact). NOT formal: computationally exact, outside the Lean certificate chain. Inputs: expression: Integers, decimals, + - * / ^ (integer exponents), parentheses. Everything else refuses."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_evaluate","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"5baa3a344309d714a8b66c9fb4a14a97c8182b3cfe1326faa2e9967840eee17c","status_classes":["estimated","refused"],"supported_fragment":"IEEE f64 expression evaluation (status=estimated). A plain number, honestly labeled: no bound, no proof. Inputs: expression: Full expression grammar incl. transcendental functions and constants."},{"assurance_classes":["checked"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_diff","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"605972a25cde65779e921b8a27b7f1a0c19d540f5330791ec0fb571cccf858ad","status_classes":["checked","refused"],"supported_fragment":"Symbolic d/dx with numeric self-verification (status=checked). Sampled agreement is a check, not a proof of identity. Inputs: expression: Expression in x; non-differentiable functions fail closed."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"6d05a705ff580a831f75cbcd2079fe88c3b5d9c858bc6b0c3182ec55aa27cd27","status_classes":["estimated","refused"],"supported_fragment":"Fixed-grid Simpson + Richardson error estimate (status=estimated). Grid-limited: NOT a bound. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; panels: Panel count (e.g. '200')."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_adaptive","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"174132e83bff6d18972cf5d88b072b12d7102cad8fdf05197165c64bfac4fea1","status_classes":["estimated","refused"],"supported_fragment":"Adaptive Simpson with refusal semantics (status=estimated). Refuses when unconverged; agreement is still not a bound. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; tolerance: Local tolerance (e.g. '1e-9')."},{"assurance_classes":["bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_bound","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"9932617903499a2ed2baa4ac213f061f422bd8f2e60bca5bf05225a9f9f788a0","status_classes":["bounded","refused"],"supported_fragment":"Certified interval enclosure of an integral (status=bounded). CONDITIONAL on the stated f64/libm rounding model; implementation campaign-tested, NOT mechanized. Never labeled formal. For a Lean-checked formal-bounded composed enclosure over the certified fragment, use jackal_integrate_bound_cert instead. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; tolerance: Max enclosure width (e.g. '1e-6')."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_solve","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"caf1f55ca8ad1fef2e0fb4f5f5bb600edb147f257427de650335500979c13501","status_classes":["estimated","refused"],"supported_fragment":"Bisection root with residual + first-order conditioning diagnostics (status=estimated). Inputs: expression: f(x) whose root is sought.; input_lo: Bracket lower bound (sign change required).; input_hi: Bracket upper bound."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"ea4ca54f74334d678c3daf9c6686fca186041d27bb2f02dabca21a7747e7d416","status_classes":["exact","refused"],"supported_fragment":"Canonical s-expression + SHA-256 of any parsed expression (status=exact). NOT formal: exact computation outside the Lean certificate chain; no exact-cert emitted. Inputs: expression: Any expression the engine grammar parses."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"199fd63f51398c6e883a407d8e2435e42903e9c76f0227d815f3456b3568d9bc","status_classes":["exact","refused"],"supported_fragment":"Dense Q[x] canonical form, degree <= 64 (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Polynomial expression in x within the poly fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_eq","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"76d9390f705758c6ec2d5fe77cd6a1391908f93ef218ebfd5111c067dc32a819","status_classes":["exact","refused"],"supported_fragment":"Decidable polynomial identity over Q[x] (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: lhs: Left polynomial expression in x.; rhs: Right polynomial expression in x."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_gcd","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"dfff2a285e732d52520ea6fe5efabdab5bd6d956c224f30d163ccbbdbd406a5c","status_classes":["exact","refused"],"supported_fragment":"Monic polynomial gcd over Q[x] via Euclid (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: lhs: Left polynomial expression in x.; rhs: Right polynomial expression in x."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_ratfunc_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"3d4c7d73d13aa88606e9e005b7731c19ac63f9fe559b38e6ff777f979afd3b40","status_classes":["exact","refused"],"supported_fragment":"Rational-function canonical form P/Q, gcd-reduced, monic denominator, explicit denominator-nonzero side condition (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Rational-function expression in x within the ratfunc fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_roots_isolate","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"ea98289e6b6319b7c0b3e6e9832e07ff4a9dd06be1d7862956c50df6e1785978","status_classes":["exact","refused"],"supported_fragment":"Sturm-sequence isolation of all distinct real roots (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Polynomial expression in x within the poly fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_alg_sign","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"b4ad3c632887bc8875f8334dea3391017d73f30fa4895d988062882e89c2c1a5","status_classes":["exact","refused"],"supported_fragment":"Exact sign of a Q[x] polynomial at a rational point (status=exact). NOT formal; no exact-cert emitted. Inputs: expression: Polynomial expression in x within the poly fragment.; point: Rational evaluation point (e.g. '3/2')."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_alg_cmp","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"bfea42d3f97e6f0403d11155d667dfec7000719e2aa3af67c8897989a9e2eee4","status_classes":["exact","refused"],"supported_fragment":"Order decision between two isolated real algebraic numbers (status=exact). NOT formal; no exact-cert emitted. Inputs: p: First defining polynomial in x.; a1: First isolating interval lower bound (rational).; b1: First isolating interval upper bound (rational).; q: Second defining polynomial in x.; a2: Second isolating interval lower bound (rational).; b2: Second isolating interval upper bound (rational)."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_xgcd","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"1c7fb606e43e71eeb4ab288c08ea4a6c89efd95beb3f802e084d5d3c1a3beaf6","status_classes":["exact","refused"],"supported_fragment":"Extended gcd with Bezout certificate (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: a: First integer.; b: Second integer."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_mod_pow","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"b3edc74b3901989b9248f8b89feaed2cc396e218abf9ccfca7ab53a99a9c7bc1","status_classes":["exact","refused"],"supported_fragment":"Modular exponentiation via square-and-multiply (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: base: Base integer.; exp: Nonnegative exponent integer.; mod: Modulus integer >= 1."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_mod_inv","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"d0826f19759afacd20d4a5f0d6704a52bce158c6950bb852a5e0774886a4abd7","status_classes":["exact","refused"],"supported_fragment":"Modular inverse with product certificate (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: a: Integer to invert.; m: Modulus integer >= 2; gcd(a, m) must be 1."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_crt","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"d44aebbbcb3b00ad0d192581533c5cfdb164e26431f3ed850406c8ecfa5044b4","status_classes":["exact","refused"],"supported_fragment":"Chinese remainder reconstruction over pairwise-coprime moduli, up to 16 pairs (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: args: Space-separated residue/modulus pairs: 'r1 m1 r2 m2 [...]' (e.g. '2 3 3 5 2 7')."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_divides","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"1191b2b4ce3a9a5c3a1dafb0917fad46ca9c3375c73f4ae59ff7a389d513adb4","status_classes":["exact","refused"],"supported_fragment":"Exact divisibility decision (status=exact). NOT formal; no exact-cert emitted. Inputs: a: Candidate divisor integer.; b: Dividend integer."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_prime_cert","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"3ff03881b24f8fd94db68b210874010e66ce0e3d32666d98a21c1bc40ccc5646","status_classes":["exact","refused"],"supported_fragment":"Pratt primality certificate or composite divisor witness, budgeted and fail-closed (status=exact; n <= 10^60, Pratt tree depth <= 64, nodes <= 512). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: n: Integer >= 2, at most 61 digits."},{"assurance_classes":["estimated","model-based","checked","bounded","formal-bounded","exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"claim-router","identities":[{"label":"claim_kernel","locator":"tools/claim_kernel.py","sha256":"77b0f85ad5fb7214f88898b60ea29ea9fd7be740c38b655388444e6e5181f348"},{"label":"claim_router","locator":"tools/claim_router.py","sha256":"02328cf177a0423bdc5cbca6ec0ea946bb0679bbd3dc6c24140d32598e575afb"},{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"},{"label":"claim_inference_registry","locator":"release/claim/inference_registry_v1.json","sha256":"c70b33d5aee8071b5125e6a5f8ffe5226fc22a137d920c17d9b3463968be13f0"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_claim","profiles":["core","formal","full"],"refusal_boundary":"Only jackal-claim-request-v1 and its closed step vocabulary are compiled. Policy, identity, schema, route, or assurance failures refuse; fallback is off by default and any caller-enabled fallback remains explicit in the route trace rather than silently changing assurance.","release_state":"v1.7.3","schema_sha256":"4d2703ff772433f39ac8b6555727e856685b0e5042b9c2cc8fcaa4402d6b9153","status_classes":["ok","refused"],"supported_fragment":"Compile a structured jackal-claim-request-v1 into a canonical, content-addressed jackal-claim-bundle-v1 evidence graph through the deterministic policy router. Routes through exact, current/archival range-family, Gaussian, request-bound composed-integral, machine, and unit lanes; emits a route trace naming candidates and refusal reasons; and refuses rather than silently downgrading (allow_fallback defaults false). The bundle is independently replayable via jackal_verify_bundle. Inputs: request: jackal-claim-request-v1 object: {schema, steps:[{id, op, ...}], root, policy?, nonce?, emitted_at_unix?, max_age_seconds?, expires_at_unix?}. Step ops: input, exact, enclose, gaussian, integrate_cert, machine, interval_add/sub/mul/div, threshold, decision, convert, and, model, passthrough, attach."},{"assurance_classes":["estimated","model-based","checked","bounded","formal-bounded","exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"claim-verifier","identities":[{"label":"claim_verifier","locator":"tools/claim_bundle_verify.py","sha256":"e0fcb9540c730bd9bb492b528ed42d29d49fc775b3aa0f9b831b6264fd68fd22"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"},{"label":"claim_inference_registry","locator":"release/claim/inference_registry_v1.json","sha256":"c70b33d5aee8071b5125e6a5f8ffe5226fc22a137d920c17d9b3463968be13f0"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_verify_bundle","profiles":["core","formal","full"],"refusal_boundary":"Only canonical bundles matching separately caller-pinned epoch, policy, root proposition, time, and nonce are replayed. Semantic, graph, freshness, evidence, checker, or pin ambiguity returns refused or indeterminate exactly as declared; it is never converted to success.","release_state":"v1.7.3","schema_sha256":"9e3acec17637a352bc88e3b08e8679a34f1efae3539fe1cce05646212be4cb5f","status_classes":["verified","refused","indeterminate"],"supported_fragment":"Independently replay a jackal-claim-bundle-v1 against caller-pinned expectations. The standalone dependency-free verifier recomputes every canonical byte and hash, revalidates the DAG, selects only the closed current/archival range, Gaussian, or current request-bound int-cert checker/proof tuple, re-runs embedded evidence, recomputes machine/unit mathematics, re-evaluates every inference rule and assurance-axis propagation, enforces consequence-class floors and policy, and recomputes the deterministic rendering. Returns verified | refused | indeterminate with exact reasons — never a generic green badge. Inputs: bundle: The jackal-claim-bundle-v1 object to replay.; expected_release_epoch: Caller-pinned epoch (e.g. 'v1.6.0'); never copied from the bundle.; expected_policy_sha256: Caller-pinned SHA-256 of the canonical policy bytes.; expected_root_proposition: Caller-pinned canonical root proposition IR object.; verification_time_unix: Caller-supplied verification time (unix seconds) for freshness/expiry checks.; expected_nonce: Caller nonce; the bundle root must bind exactly this nonce."},{"assurance_classes":["structural-exact"],"consequence_ceiling":"informational","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"structural-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"1a3b2c95dcdc7c7337fbe0ecb34043b70c3697752d6dc585f45f3c7d4f1b0706"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"22984f511208af2d7a318f1a43306d95a4b0f61876d8b44f34f39a2ded6d573d"},{"label":"domain_pack_test_exists_checker","locator":"tools/test_exists_verify.py","sha256":"598cb99e1eb70c9410ca87345efee346f73e43aaf3625427dca17ea04231caea"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_test_exists","profiles":["full"],"refusal_boundary":"Only byte-exact source/citation structure described by the schema is accepted after independent file-byte recomputation. Path traversal, malformed symbols/hashes, missing text/declarations, or checker mismatch refuses; the result never asserts test execution or correctness.","release_state":"v1.7.3","schema_sha256":"9685ecf3bcf78a3a26916455cc528cdeac137420e8694447e2865b33890f9d46","status_classes":["structural-exact","refused"],"supported_fragment":"Domain pack jackal.programming.source, operation programming.source.test_exists.v1, routed through pack-route. States one byte-exact STRUCTURAL fact: a declaration-shaped occurrence of `symbol` exists at `declaration_line` in a file whose content hash is exactly `file_sha256`, and the file contains exactly `declaration_count` such occurrences. The engine validates the canonical FORM; the manifest-pinned independent checker tools/test_exists_verify.py then recomputes every claimed field from the real bytes on disk and only an ACCEPT verdict returns success, so a misstated hash, line or count refuses instead of minting a certificate. ASSURANCE ceiling exact; CONSEQUENCE ceiling informational, and the second does not rise with the first: a test-exists-cert is NEVER evidence that the code under test is correct, that the test executes, that it is collected by any runner, or that it asserts anything at all. NOT formal: no Lean checker and no theorem are involved. Do not cite this certificate in support of a correctness claim. Inputs: file_path: Repository-relative path token; absolute paths and parent traversal refuse `prog-path`.; file_sha256: Exactly 64 lowercase hex characters; the checker recomputes it from the file bytes.; symbol: Identifier of the declaration; a non-identifier refuses `prog-symbol`.; declaration_line: 1-based line of the declaration as a canonical positive integer.; declaration_count: Total declaration-shaped occurrences of `symbol` in the file; `0` refuses `prog-absent`."},{"assurance_classes":["structural-exact"],"consequence_ceiling":"informational","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"structural-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"1a3b2c95dcdc7c7337fbe0ecb34043b70c3697752d6dc585f45f3c7d4f1b0706"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"22984f511208af2d7a318f1a43306d95a4b0f61876d8b44f34f39a2ded6d573d"},{"label":"domain_pack_test_exists_checker","locator":"tools/test_exists_verify.py","sha256":"598cb99e1eb70c9410ca87345efee346f73e43aaf3625427dca17ea04231caea"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_claim_cites_test","profiles":["full"],"refusal_boundary":"Only byte-exact source/citation structure described by the schema is accepted after independent file-byte recomputation. Path traversal, malformed symbols/hashes, missing text/declarations, or checker mismatch refuses; the result never asserts test execution or correctness.","release_state":"v1.7.3","schema_sha256":"69a533155bde04bfd5dedd43e9d63acd02f3e2773757936e9e1714458e20abd4","status_classes":["structural-exact","refused"],"supported_fragment":"Domain pack jackal.programming.source, operation programming.source.claim_cites_test.v1, routed through pack-route. Resolves a citation: `claim_text` occurs verbatim in the document at `doc_path`/`doc_sha256`, and `symbol` has a declaration-shaped occurrence in the cited test file at `test_path`/`test_sha256`. Resolution is all this establishes. It does NOT establish that the cited test covers, exercises or supports the claim — the cited test may check something entirely different, which is the exact defect this operation exists to bound rather than hide. The manifest-pinned tools/test_exists_verify.py re-runs over the certificate and only ACCEPT returns success, so a claim text absent from the document or a dangling citation refuses. ASSURANCE ceiling exact; CONSEQUENCE ceiling informational, and the second does not rise with the first. NOT formal: no Lean checker and no theorem are involved. Inputs: doc_path: Repository-relative path of the document making the claim.; doc_sha256: Exactly 64 lowercase hex characters for the document bytes.; claim_text: The claim sentence, verbatim, 1..2048 bytes; it must occur in the document.; test_path: Repository-relative path of the cited test file.; test_sha256: Exactly 64 lowercase hex characters for the cited test file bytes.; symbol: Identifier the citation resolves to inside the cited test file."},{"assurance_classes":["exact"],"consequence_ceiling":"decision-boundary","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"decision-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"1a3b2c95dcdc7c7337fbe0ecb34043b70c3697752d6dc585f45f3c7d4f1b0706"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"22984f511208af2d7a318f1a43306d95a4b0f61876d8b44f34f39a2ded6d573d"},{"label":"domain_pack_decision_checker","locator":"tools/decision_verify.py","sha256":"f1ad7c9fbd4c1d899dbb4bebabbbeb97e97a56bd4b279ad7d8ec3722bf12e0f6"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_decision_rank","profiles":["full"],"refusal_boundary":"Only 2..6 schema-valid options under a caller-declared admissible numeric criterion are ranked. Invalid shape/sense/unit, value-judgment criteria, zero top margin, or checker mismatch refuses; caller values are not treated as measurements or confidence intervals.","release_state":"v1.7.3","schema_sha256":"843fe08464d40d97094eeb6424c0c29a3e2617172ba56262ca4122468a8bb92f","status_classes":["exact","refused"],"supported_fragment":"Domain pack jackal.decision.matrix, operation decision.matrix.rank.v1, routed through pack-route. Orders 2..6 labelled options by a caller-declared numeric criterion and emits a jackal-decision-cert-v1 naming the selected option, the runner-up and the exact margin; the manifest-pinned tools/decision_verify.py recomputes the whole ordering from the certificate's own option values and only ACCEPT returns success. Criterion admissibility is decided by the engine against a fixed word list, so a bare value judgment refuses `decision-value-judgment`; a top-two tie refuses `decision-margin-zero`. ASSURANCE ceiling exact; CONSEQUENCE ceiling decision-boundary. The arithmetic is exact and the choice of criterion is not: the declared criterion and the declared option values remain the caller's, this result is not a claim that the criterion is the right one, the values are not measurements, and the margin is not a confidence interval. For the closed-unit lane that additionally requires a declared unit, use jackal_decision_rank_v2. NOT formal: no Lean checker and no theorem are involved. Inputs: decision_id: Caller's identifier for this decision, bound into the certificate. Bytes are restricted to [A-Za-z0-9_]; anything else refuses `prog-symbol`.; criterion: The declared numeric criterion (e.g. 'latency_ms'); a value judgment refuses `decision-value-judgment`.; sense: Exactly 'min' or 'max'; anything else refuses `decision-sense-unknown`.; options: 2..6 whitespace-separated `label value` pairs, e.g. 'a 10 b 20 c 30'. Values are canonical integers. A label containing whitespace shifts the pairing and refuses `pack-args-shape`; it is never silently re-paired."},{"assurance_classes":["exact"],"consequence_ceiling":"decision-boundary","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"decision-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"1a3b2c95dcdc7c7337fbe0ecb34043b70c3697752d6dc585f45f3c7d4f1b0706"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"22984f511208af2d7a318f1a43306d95a4b0f61876d8b44f34f39a2ded6d573d"},{"label":"domain_pack_decision_checker","locator":"tools/decision_verify.py","sha256":"f1ad7c9fbd4c1d899dbb4bebabbbeb97e97a56bd4b279ad7d8ec3722bf12e0f6"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_decision_rank_v2","profiles":["full"],"refusal_boundary":"Only 2..6 schema-valid options under a caller-declared admissible numeric criterion are ranked. Invalid shape/sense/unit, value-judgment criteria, zero top margin, or checker mismatch refuses; caller values are not treated as measurements or confidence intervals.","release_state":"v1.7.3","schema_sha256":"cdc8abba09426977a5319b52410204f21e2e1eb7b38a9de31de751fcb862e78a","status_classes":["exact","refused"],"supported_fragment":"Domain pack jackal.decision.matrix, operation decision.matrix.rank.v2, routed through pack-route. Same deterministic ordering as jackal_decision_rank, plus a REQUIRED declared unit drawn from a closed vocabulary: the 65 canonical ids of release/claim/unit_registry_v1.json excluding the dimensionless identity `one` (66 ids in the registry, `one` is not admitted here). Matching is exact-token and case-sensitive; an alias, a spelled-out name such as 'millisecond', a different case, or the dimensionless identity all refuse `decision-unit-unknown`, and an empty unit refuses `decision-unit-missing`. Emits jackal-decision-cert-v2, re-checked by the manifest-pinned tools/decision_verify.py; only ACCEPT returns success. ASSURANCE ceiling exact; CONSEQUENCE ceiling decision-boundary. Honest residual: a declared unit is NOT a measurement. The closed vocabulary forces the caller to name a dimension, and nothing more — a value-judgment criterion that survives the engine's word list is still accepted when a real unit is declared (`most_elegant` in `ms` ranks), and the values themselves remain caller-declared. NOT formal: no Lean checker and no theorem are involved. Inputs: decision_id: Caller's identifier for this decision, bound into the certificate. Bytes are restricted to [A-Za-z0-9_]; anything else refuses `prog-symbol`.; criterion: The declared numeric criterion; a value judgment refuses `decision-value-judgment` even with an admissible unit.; unit: One canonical unit id from release/claim/unit_registry_v1.json, excluding `one`. Exact token, case-sensitive: 'ms' is admitted, 'millisecond' and 'MS' refuse `decision-unit-unknown`.; sense: Exactly 'min' or 'max'; anything else refuses `decision-sense-unknown`.; options: 2..6 whitespace-separated `label value` pairs, e.g. 'a 10 b 20 c 30'. Values are canonical integers. A label containing whitespace shifts the pairing and refuses `pack-args-shape`; it is never silently re-paired."},{"assurance_classes":["verified-program-evidence"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"4b80e29bdffc0737f05a6e215fce8cce3b6b828c24afbf55c68443399e5119dc"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_check_program","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"177cfcf9dfcd6bbc6e657eb83b88f04bfedaa0f28f81307077a776e2052df1e2","status_classes":["verified-program-evidence","refused"],"supported_fragment":"Run a caller-pinned Anubis compiler only as `build --evidence` in Safe mode, never execute the compiled artifact, then independently close and replay the resulting strict anubis.program-evidence.v3 package under inventory-safe-v1. Emits only verified-program-evidence or a named refusal. This profile checks producer-attested function/policy inventories but explicitly does not establish policy-construct totality, source-to-VC proof, SMT-to-CNF proof, source-native refinement, runtime behavior, or universal soundness. Inputs: source_path: Local regular non-symlink Anubis source path.; anubis_bin: Local regular non-symlink Anubis executable; caller-pinned and hashed before/after build.; expected_source_sha256: Caller-pinned exact source SHA-256.; expected_compiler_sha256: Caller-pinned approved Anubis executable SHA-256.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1; contracted-safe-v1 refuses.; nonce: Caller nonce bound into the receipt.; out_root: New local output root; existing paths refuse."},{"assurance_classes":["verified-program-evidence"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"4b80e29bdffc0737f05a6e215fce8cce3b6b828c24afbf55c68443399e5119dc"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_verify_program","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"45c7aae87c329925f6bd6b9100efc7d099d70fcaeaba915ee59937f019e1153d","status_classes":["verified-program-evidence","refused"],"supported_fragment":"Independently verify caller-selected Anubis Safe source and evidence bytes under inventory-safe-v1: strict v3 roster, exact manifest closure, source/compiler/artifact/policy pins, producer-summary reconciliation, one-to-one solver/proof paths and counters, approved Z3 UNSAT replay, and independent RUP replay. Never executes the artifact and never claims independent policy-construct totality or source-native refinement. Inputs: source_path: Caller-selected regular non-symlink Anubis source path.; evidence_dir: Caller-selected strict anubis.program-evidence.v3 directory.; expected_source_sha256: Caller-pinned exact source SHA-256.; expected_compiler_sha256: Caller-pinned producer executable SHA-256.; expected_artifact_sha256: Caller-pinned sealed artifact SHA-256; artifact bytes are read but never executed.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1.; nonce: Caller nonce bound into the receipt."},{"assurance_classes":["verified-program-receipt"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"4b80e29bdffc0737f05a6e215fce8cce3b6b828c24afbf55c68443399e5119dc"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_verify_program_receipt","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"6bb75d81aebf6f2b3b20900357204e9ef0858cdac412ea016868028cdd2a67d3","status_classes":["verified-program-receipt","refused"],"supported_fragment":"Recompute a jackal-anubis-program-receipt-v1 from caller-selected source/evidence bytes and independent caller pins, rejecting outer-digest-consistent semantic laundering. Success is only verified-program-receipt; it does not raise the underlying inventory-safe-v1 assurance ceiling. Inputs: receipt: Program receipt object to replay; its own pins are never trusted.; source_path: Caller-selected regular source path.; evidence_dir: Caller-selected evidence directory.; expected_source_sha256: Caller-pinned source SHA-256.; expected_compiler_sha256: Caller-pinned compiler SHA-256.; expected_artifact_sha256: Caller-pinned artifact SHA-256.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1.; nonce: Caller nonce; never copied from the receipt."}],"unique_tool_count":41} diff --git a/release/compat/v172_floor.linux-aarch64.json b/release/compat/v172_floor.linux-aarch64.json new file mode 100644 index 0000000..38d45d0 --- /dev/null +++ b/release/compat/v172_floor.linux-aarch64.json @@ -0,0 +1,79 @@ +{ + "current_release_epoch": "v1.7.2", + "lanes": { + "int_cert": { + "archival_v1": { + "allowed_release_epochs": [], + "checker_file": "jackal_int_cert_check_v170", + "checker_sha256": "c858e3bfc0ff2809a808170caabbf090077cb54996e76f065dbcd26ffb067d49", + "identity_file": "release/evidence/int_cert_proof_identity.json", + "identity_file_sha256": "f0323e312d8b0e05a7200546fd819fc191d5f146d359bb14efec5b1575f16844", + "inventory_file": "release/coverage/formal_coverage_inventory_v170.json", + "inventory_file_sha256": "18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6", + "mode": "revoked-refuse", + "reason": "v1 artifact-only checker does not bind the raw request expression to the proved QExpr", + "schema": "jackal-int-cert-proof-identity-v1" + }, + "current": { + "allowed_release_epochs": [ + "v1.7.2" + ], + "identity_file": "release/evidence/int_cert_proof_identity_v172.json", + "identity_file_sha256": "533c5cc4718331e2739ec92513487842aa48471b4b7d1be57db08999a9d90f95", + "minimum_schema_version": 2, + "schema": "jackal-int-cert-proof-identity-v2" + } + }, + "range": { + "archival_v1": { + "allowed_release_epochs": [ + "v1.5.0" + ], + "checker_file": "jackal_cert_check_v170", + "checker_sha256": "05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a", + "identity_file": "release/evidence/range_proof_identity.json", + "identity_file_sha256": "1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67", + "inventory_file": "release/coverage/formal_coverage_inventory_v170.json", + "inventory_file_sha256": "18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6", + "mode": "replay-only", + "schema": "jackal-range-proof-identity-v1" + }, + "current": { + "allowed_release_epochs": [ + "v1.7.2" + ], + "identity_file": "release/evidence/range_proof_identity_v172.json", + "identity_file_sha256": "c6caed2434cbd77cba19bb0279936bfa322a696301e6d20c932a9b412f2fa0ca", + "minimum_schema_version": 2, + "schema": "jackal-range-proof-identity-v2" + } + }, + "rational_variants": { + "archival_v1": { + "allowed_release_epochs": [ + "v1.5.0" + ], + "checker_file": "jackal_cert_check_v170", + "checker_sha256": "05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a", + "identity_file": "release/evidence/range_proof_identity.json", + "identity_file_sha256": "1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67", + "inventory_file": "release/coverage/formal_coverage_inventory_v170.json", + "inventory_file_sha256": "18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6", + "mode": "replay-only", + "schema": "jackal-range-proof-identity-v1" + }, + "current": { + "allowed_release_epochs": [ + "v1.7.2" + ], + "identity_file": "release/evidence/range_proof_identity_v172.json", + "identity_file_sha256": "c6caed2434cbd77cba19bb0279936bfa322a696301e6d20c932a9b412f2fa0ca", + "minimum_schema_version": 2, + "schema": "jackal-range-proof-identity-v2" + } + } + }, + "reversed_interval_policy": "revoked-refuse", + "schema": "jackal-proof-compatibility-floor-v1", + "unsupported_policy": "refuse" +} diff --git a/release/evidence/gaussian_proof_identity.linux-aarch64.json b/release/evidence/gaussian_proof_identity.linux-aarch64.json new file mode 100644 index 0000000..dd0d965 --- /dev/null +++ b/release/evidence/gaussian_proof_identity.linux-aarch64.json @@ -0,0 +1,486 @@ +{ + "build_attestation": { + "attestation_digest_sha256": "40945160648f044955934d44795c6b9f53cdee21e6d2ae3dcd3d86c13a1b434a", + "authentication": { + "authenticated": false, + "scheme": "none", + "statement": "This deterministic record binds observed checker bytes to named inputs. It is not a signature and does not authenticate the builder or artifact." + }, + "build_command": [ + "lake", + "build", + "jackal_gaussian_check" + ], + "checker": { + "bytes": 181303904, + "path": "proofs/lean/.lake/build/bin/jackal_gaussian_check", + "sha256": "1f21c6b2e41c171414405c0aa6fee089851716d1add707727ace45395f4ed379", + "target": "jackal_gaussian_check" + }, + "claim_boundary": "This is reproducibility/build-provenance evidence, not a proof of compiler, linker, operating-system, hardware, or supply-chain correctness.", + "compiler_observed_for_build_platform": { + "build": "Release", + "commit": "8c9756b28d64dab099da31a4c09229a9e6a2ef35", + "executable_bytes": 13824, + "executable_sha256": "79fb1d26fa5a39385d59fdc48a711a14b0710ca6480271acce99b4d177cea085", + "target": "aarch64-unknown-linux-gnu", + "version": "4.32.0" + }, + "inputs": { + "lean_commit": "8c9756b28d64dab099da31a4c09229a9e6a2ef35", + "mathlib_commit": "81a5d257c8e410db227a6665ed08f64fea08e997", + "source_closure_sha256": "c7bfd35c843884ab541028eb3021a3503e88d86aa2391378f2d34f56554fa497", + "toolchain_configuration": [ + { + "path": "proofs/lean/lakefile.toml", + "sha256": "21eef36ea0d9a665622b171dcf1f96460aa250ef214314d766112e01dadf1eaf" + }, + { + "path": "proofs/lean/lake-manifest.json", + "sha256": "f521808691ba1ab175c5cdeec098a76586d345fea93370a38c2d2b73645f69d4" + }, + { + "path": "proofs/lean/lean-toolchain", + "sha256": "2773c517aa90b66ea8a2c52bddddf84393157797f8341be0df45294fff7fd32e" + } + ] + }, + "kind": "unsigned-local-build-binding-v1", + "working_directory": "proofs/lean" + }, + "checker": { + "bytes": 181303904, + "path": "proofs/lean/.lake/build/bin/jackal_gaussian_check", + "sha256": "1f21c6b2e41c171414405c0aa6fee089851716d1add707727ace45395f4ed379", + "target": "jackal_gaussian_check" + }, + "fragment": { + "assurance": "formal-bounded", + "certificate_magic": "jackal-gaussian-integral-cert v1", + "checker_boolean_definition": "JackalIv.GaussianCert.checkCert", + "checker_entrypoint_definition": "runGaussianCert", + "checker_executable": "jackal_gaussian_check", + "family": "gaussian-exp-square-v1", + "lane": "gaussian", + "parser_definition": "JackalIv.GaussianCert.parseCert", + "premises_not_discharged_by_checker": [], + "runtime_alternate_implementation_boundary": "none in local source closure", + "soundness_theorem": "JackalIv.GaussianCert.gaussian_integral_check_sound", + "theorem_premises": [ + "checkCert c = true (runtime checked)" + ] + }, + "generator": { + "path": "release/tools/gaussian_proof_identity.py", + "sha256": "05bfa1709b0968da37b95c3d80c619de003ee4ba6987f6cea2844293fa8e4ccd" + }, + "identity_digest_sha256": "489780aab2b7b5f16bc529b141c5c7967a9307cbc539c3fff8eab9f0789263fe", + "proof": { + "axiom_audit_command": "lake env lean /dev/stdin with checked-in #print axioms set", + "axiom_policy": { + "allowed_exactly": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "forbidden": [ + "sorryAx", + "any additional axiom" + ] + }, + "theorems": [ + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "theorem": "JackalIv.GaussianCert.gaussian_integral_check_sound" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "theorem": "JackalIv.Gaussian.scaled_gaussian_enclosed" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "theorem": "JackalIv.Gaussian.checker_core_enclosed" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "theorem": "JackalIv.Gaussian.expNegQ_encloses" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "theorem": "JackalIv.Gaussian.sqrtPi_enclosed" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "theorem": "JackalIv.GaussianCert.checkCert_iff" + } + ] + }, + "schema": "jackal-gaussian-proof-identity-v1", + "source_closure": { + "aggregate_sha256": "c7bfd35c843884ab541028eb3021a3503e88d86aa2391378f2d34f56554fa497", + "definition": "Every repository-local transitive Lean import reachable from root_modules; external imports are bound through lake-manifest.json and named here.", + "external_imports": [ + "Mathlib", + "Mathlib.Analysis.Complex.Exponential", + "Mathlib.Analysis.Real.Pi.Bounds", + "Mathlib.Analysis.SpecialFunctions.Gaussian.GaussianIntegral", + "Mathlib.Analysis.SpecialFunctions.Trigonometric.Arctan", + "Mathlib.Analysis.SpecialFunctions.Trigonometric.Bounds" + ], + "files": [ + { + "bytes": 11165, + "imports": [ + "JackalIv.Model", + "JackalIv.Pad" + ], + "module": "JackalIv.Arith", + "path": "proofs/lean/JackalIv/Arith.lean", + "sha256": "2bc091be9dd47acae8d4b8af7b272827a3cea7b5ec08773566ad8fe40a12bf83" + }, + { + "bytes": 27102, + "imports": [ + "JackalIv.CertTypes", + "JackalIv.Gaussian", + "JackalIv.Transcend" + ], + "module": "JackalIv.CertCheck", + "path": "proofs/lean/JackalIv/CertCheck.lean", + "sha256": "02cec1630ed5f822f226155e0d4b7c1b62acf056826b03e5e8b191544789b6de" + }, + { + "bytes": 54454, + "imports": [ + "JackalIv.CertCheck" + ], + "module": "JackalIv.CertCodec", + "path": "proofs/lean/JackalIv/CertCodec.lean", + "sha256": "66ac121b53dd12ec395dbd88ddf16f726bf3afdb4946f1f4deabee8af001cd9d" + }, + { + "bytes": 16791, + "imports": [ + "JackalIv.Syntax" + ], + "module": "JackalIv.CertTypes", + "path": "proofs/lean/JackalIv/CertTypes.lean", + "sha256": "0f241bce34f817a1f415d9722d0c34652cb4f312b7261d842b4000b23d7b4139" + }, + { + "bytes": 17004, + "imports": [ + "JackalIv.Model", + "JackalIv.Pad", + "JackalIv.Arith", + "JackalIv.Monotone", + "JackalIv.Pow" + ], + "module": "JackalIv.Exact", + "path": "proofs/lean/JackalIv/Exact.lean", + "sha256": "a4c0f493b0d69b1a9756205d7b61f5852bde225a5fe532140ec178b97576ce28" + }, + { + "bytes": 7290, + "imports": [ + "JackalIv.Taylor", + "Mathlib.Analysis.Complex.Exponential" + ], + "module": "JackalIv.Gaussian", + "path": "proofs/lean/JackalIv/Gaussian.lean", + "sha256": "2aaaaa895141dab699f6cd936639948976e9560c07d015708e02545b02a045fe" + }, + { + "bytes": 7647, + "imports": [ + "JackalIv.CertCodec", + "JackalIv.GaussianIntegral" + ], + "module": "JackalIv.GaussianCert", + "path": "proofs/lean/JackalIv/GaussianCert.lean", + "sha256": "a86f48a1dcf7a6eaa5170b984cd97815644e25cd19ab13bcd2e87020786b9b7e" + }, + { + "bytes": 1001, + "imports": [ + "JackalIv.GaussianCert" + ], + "module": "JackalIv.GaussianCertMain", + "path": "proofs/lean/JackalIv/GaussianCertMain.lean", + "sha256": "1690e3412ec811567da9801dbeda7d57b30735f461e22711a97ebe99f5017aa3" + }, + { + "bytes": 9715, + "imports": [ + "JackalIv.Gaussian", + "Mathlib.Analysis.Real.Pi.Bounds", + "Mathlib.Analysis.SpecialFunctions.Gaussian.GaussianIntegral" + ], + "module": "JackalIv.GaussianIntegral", + "path": "proofs/lean/JackalIv/GaussianIntegral.lean", + "sha256": "7c3b53502d4d64a4d17ffa59929565e37d9f5a1c45cd8aec93bbfe9d9a6ee16b" + }, + { + "bytes": 3704, + "imports": [ + "Mathlib" + ], + "module": "JackalIv.Model", + "path": "proofs/lean/JackalIv/Model.lean", + "sha256": "81b13207259c86ccd816cf3d93dd70f11cc042722f2b42320b61ec7a301cb306" + }, + { + "bytes": 6837, + "imports": [ + "JackalIv.Model", + "JackalIv.Pad" + ], + "module": "JackalIv.Monotone", + "path": "proofs/lean/JackalIv/Monotone.lean", + "sha256": "87f262d6f0fb7d60b7ea1fdc716c95625c6131830aee0e2d5a45d62397533a8e" + }, + { + "bytes": 4695, + "imports": [ + "JackalIv.Model" + ], + "module": "JackalIv.Pad", + "path": "proofs/lean/JackalIv/Pad.lean", + "sha256": "82cce18646e2522695fec7c68796f9a60a85abc20b6bfe1c45dac8070578c5d1" + }, + { + "bytes": 11388, + "imports": [ + "JackalIv.Model", + "JackalIv.Pad", + "JackalIv.Arith" + ], + "module": "JackalIv.Pow", + "path": "proofs/lean/JackalIv/Pow.lean", + "sha256": "0d80581069c3934274ca4992c6c07867e10821c8fedc43ec6c6fedd6e0971332" + }, + { + "bytes": 17044, + "imports": [ + "JackalIv.Model", + "JackalIv.Pad", + "JackalIv.Arith", + "JackalIv.Monotone", + "JackalIv.Exact", + "JackalIv.Pow", + "JackalIv.Trig" + ], + "module": "JackalIv.Syntax", + "path": "proofs/lean/JackalIv/Syntax.lean", + "sha256": "552bf222b26a615b779a5f0c8abf44beb258609551b158ee3141729dedcf7651" + }, + { + "bytes": 25406, + "imports": [ + "JackalIv.Model", + "JackalIv.Pad" + ], + "module": "JackalIv.Taylor", + "path": "proofs/lean/JackalIv/Taylor.lean", + "sha256": "b3a5c2bbb8374b845624f13fc66b7cb8ad0bf0ca987c6b923631f3ea275febd2" + }, + { + "bytes": 20215, + "imports": [ + "JackalIv.Gaussian", + "Mathlib.Analysis.SpecialFunctions.Trigonometric.Bounds", + "Mathlib.Analysis.SpecialFunctions.Trigonometric.Arctan", + "Mathlib.Analysis.Real.Pi.Bounds" + ], + "module": "JackalIv.Transcend", + "path": "proofs/lean/JackalIv/Transcend.lean", + "sha256": "2fce308fdf161d6fc1edb3d41cb0148e6d8544ab0954a17a7c29ae915a7f1569" + }, + { + "bytes": 24529, + "imports": [ + "JackalIv.Model", + "JackalIv.Pad" + ], + "module": "JackalIv.Trig", + "path": "proofs/lean/JackalIv/Trig.lean", + "sha256": "c65e6db19679c0081d833d4a15cf9d46b4f73e395ed7564505fc0c2e586078d4" + } + ], + "local_construct_policy": { + "allowed_exact_source_lines": [], + "forbidden_by_default": [ + "admit", + "axiom_declaration", + "extern", + "implemented_by", + "native_decide", + "partial", + "sorry", + "unsafe" + ] + }, + "root_modules": [ + "JackalIv.GaussianCertMain" + ] + }, + "toolchain": { + "configuration_files": [ + { + "path": "proofs/lean/lakefile.toml", + "sha256": "21eef36ea0d9a665622b171dcf1f96460aa250ef214314d766112e01dadf1eaf" + }, + { + "path": "proofs/lean/lake-manifest.json", + "sha256": "f521808691ba1ab175c5cdeec098a76586d345fea93370a38c2d2b73645f69d4" + }, + { + "path": "proofs/lean/lean-toolchain", + "sha256": "2773c517aa90b66ea8a2c52bddddf84393157797f8341be0df45294fff7fd32e" + } + ], + "lake_version": "Lake version 5.0.0-src+8c9756b (Lean version 4.32.0)", + "lean": { + "build": "Release", + "commit": "8c9756b28d64dab099da31a4c09229a9e6a2ef35", + "version": "4.32.0" + }, + "lean_toolchain": "leanprover/lean4:v4.32.0", + "manifest_packages": [ + { + "config_file": "lakefile.toml", + "inherited": true, + "input_revision": "v4.32.0", + "manifest_file": "lake-manifest.json", + "name": "Cli", + "revision": "88679d088c9720c27ebdf2ba4dafe17341747f94", + "scope": "leanprover", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover/lean4-cli" + }, + { + "config_file": "lakefile.toml", + "inherited": true, + "input_revision": "main", + "manifest_file": "lake-manifest.json", + "name": "LeanSearchClient", + "revision": "c5d5b8fe6e5158def25cd28eb94e4141ad97c843", + "scope": "leanprover-community", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover-community/LeanSearchClient" + }, + { + "config_file": "lakefile.toml", + "inherited": true, + "input_revision": "master", + "manifest_file": "lake-manifest.json", + "name": "Qq", + "revision": "38d591e778f100aec9762bb582f9c7f55f50e9dc", + "scope": "leanprover-community", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover-community/quote4" + }, + { + "config_file": "lakefile.toml", + "inherited": true, + "input_revision": "master", + "manifest_file": "lake-manifest.json", + "name": "aesop", + "revision": "a7dbf0c63b694e47f425f3dcddbc0e178bb432d3", + "scope": "leanprover-community", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover-community/aesop" + }, + { + "config_file": "lakefile.toml", + "inherited": true, + "input_revision": "main", + "manifest_file": "lake-manifest.json", + "name": "batteries", + "revision": "023ce7d62a0531e22a5331e20b587817a80d49ff", + "scope": "leanprover-community", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover-community/batteries" + }, + { + "config_file": "lakefile.toml", + "inherited": true, + "input_revision": "main", + "manifest_file": "lake-manifest.json", + "name": "importGraph", + "revision": "7e9612bf0b9ee66db3cb5b9988a35afc706f5a12", + "scope": "leanprover-community", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover-community/import-graph" + }, + { + "config_file": "lakefile.lean", + "inherited": false, + "input_revision": "v4.32.0", + "manifest_file": "lake-manifest.json", + "name": "mathlib", + "revision": "81a5d257c8e410db227a6665ed08f64fea08e997", + "scope": "", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover-community/mathlib4" + }, + { + "config_file": "lakefile.toml", + "inherited": true, + "input_revision": "main", + "manifest_file": "lake-manifest.json", + "name": "plausible", + "revision": "e12c1910fe855cbfc38803cd4e55543906d5fa62", + "scope": "leanprover-community", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover-community/plausible" + }, + { + "config_file": "lakefile.lean", + "inherited": true, + "input_revision": "main", + "manifest_file": "lake-manifest.json", + "name": "proofwidgets", + "revision": "6e311e2a844da9b2cc3971187df2fe0066947b93", + "scope": "leanprover-community", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover-community/ProofWidgets4" + } + ], + "mathlib_commit": "81a5d257c8e410db227a6665ed08f64fea08e997", + "package_checkout_policy": "Every git package checkout is clean and its HEAD equals its full lake-manifest revision during generation and verification." + } +} diff --git a/release/evidence/int_cert_proof_identity_v172.linux-aarch64.json b/release/evidence/int_cert_proof_identity_v172.linux-aarch64.json new file mode 100644 index 0000000..c32b8b9 --- /dev/null +++ b/release/evidence/int_cert_proof_identity_v172.linux-aarch64.json @@ -0,0 +1,687 @@ +{ + "build_attestation": { + "attestation_digest_sha256": "fd43f85942b8a8253093c772dcbebd0f76490075406e99f08e2488cb676df046", + "authentication": { + "authenticated": false, + "scheme": "none", + "statement": "This deterministic record binds observed checker bytes to named inputs. It is not a signature and does not authenticate the builder or artifact." + }, + "build_command": [ + "lake", + "build", + "jackal_int_cert_check" + ], + "checker": { + "bytes": 181725072, + "path": "proofs/lean/.lake/build/bin/jackal_int_cert_check", + "sha256": "f2e26f506f921b577fd8609a095b69789b3b76cce65d8c293d1a11f3007a8078", + "target": "jackal_int_cert_check" + }, + "claim_boundary": "This is reproducibility/build-provenance evidence, not a proof of compiler, linker, operating-system, hardware, or supply-chain correctness.", + "compiler_observed_for_build_platform": { + "build": "Release", + "commit": "8c9756b28d64dab099da31a4c09229a9e6a2ef35", + "executable_bytes": 13824, + "executable_sha256": "79fb1d26fa5a39385d59fdc48a711a14b0710ca6480271acce99b4d177cea085", + "target": "aarch64-unknown-linux-gnu", + "version": "4.32.0" + }, + "inputs": { + "lean_commit": "8c9756b28d64dab099da31a4c09229a9e6a2ef35", + "mathlib_commit": "81a5d257c8e410db227a6665ed08f64fea08e997", + "source_closure_sha256": "d577d086ee89fc0a4bcc39d9400538a39e86c6b1ab75d9d7502568c7ac874455", + "toolchain_configuration": [ + { + "path": "proofs/lean/lakefile.toml", + "sha256": "21eef36ea0d9a665622b171dcf1f96460aa250ef214314d766112e01dadf1eaf" + }, + { + "path": "proofs/lean/lake-manifest.json", + "sha256": "f521808691ba1ab175c5cdeec098a76586d345fea93370a38c2d2b73645f69d4" + }, + { + "path": "proofs/lean/lean-toolchain", + "sha256": "2773c517aa90b66ea8a2c52bddddf84393157797f8341be0df45294fff7fd32e" + } + ] + }, + "kind": "unsigned-local-build-binding-v1", + "working_directory": "proofs/lean" + }, + "checker": { + "bytes": 181725072, + "path": "proofs/lean/.lake/build/bin/jackal_int_cert_check", + "sha256": "f2e26f506f921b577fd8609a095b69789b3b76cce65d8c293d1a11f3007a8078", + "target": "jackal_int_cert_check" + }, + "fragment": { + "assurance": "formal-bounded", + "certificate_magic": "jackal-int-cert v1", + "checker_boolean_definition": "JackalIv.IntCert.checkIntCertRequest", + "checker_entrypoint_definition": "main (IntCertMain)", + "checker_executable": "jackal_int_cert_check", + "family": "integrate-bound-composed-request-bound-v1", + "lane": "int-cert", + "parser_definition": "JackalIv.IntCert.parseIntCert", + "premise_closure": "every embedded certificate is releaseNodesOk; ModelTCB and the former TreeTCB are derived inside int_cert_core_sound; the raw caller expression, bounds, and tolerance are matched inside checkIntCertRequest and exposed by int_cert_sound", + "premises_not_discharged_by_checker": [], + "runtime_alternate_implementation_boundary": "checker acceptance uses no implemented_by definition; two exact dump-only implemented_by attributes elsewhere in the imported closure are pinned", + "soundness_theorem": "JackalIv.IntCert.int_cert_sound", + "theorem_premises": [ + "checkIntCertRequest rawExpr rawLo rawHi rawTol hdr tree = .ok () (runtime checked)" + ] + }, + "generator": { + "path": "release/tools/range_proof_identity.py", + "sha256": "4efc0133107f8abe55619dc8b057318203953a7e0580573933f0dd2e47aba826" + }, + "identity_digest_sha256": "a024ab9cb1010721297703bab38a0e43a7a48ac65b0c1d71292599e813e3dad9", + "proof": { + "axiom_audit_command": "lake env lean /dev/stdin with checked-in #print axioms set", + "axiom_policy": { + "allowed_exactly": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "forbidden": [ + "sorryAx", + "any additional axiom" + ] + }, + "theorems": [ + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "theorem": "JackalIv.IntCert.int_cert_sound" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "theorem": "JackalIv.IntCert.int_cert_core_sound" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "theorem": "JackalIv.IntCert.intRequestMatches_true" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "theorem": "JackalIv.IntCert.checkIntCertRequest_ok" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "theorem": "JackalIv.IntCert.checkIntCert_rootQExpr_exists" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "theorem": "JackalIv.IntCert.rootRawExpr_rootQExpr_embed" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "theorem": "JackalIv.IntCert.range_leaf_sound" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "theorem": "JackalIv.IntCert.taylor2_leaf_sound" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "theorem": "JackalIv.IntCert.taylor4_leaf_sound" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "theorem": "JackalIv.IntCert.split_sound" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "theorem": "JackalIv.IntCert.sem_measurable" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "theorem": "JackalIv.IntCert.embedQ_DQ" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "theorem": "JackalIv.IntCert.qexprOf_embed" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "theorem": "JackalIv.Cert.releaseNodesOk_modelTCB" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "theorem": "JackalIv.Cert.cert_check_sound" + } + ] + }, + "schema": "jackal-int-cert-proof-identity-v2", + "source_closure": { + "aggregate_sha256": "d577d086ee89fc0a4bcc39d9400538a39e86c6b1ab75d9d7502568c7ac874455", + "definition": "Every repository-local transitive Lean import reachable from root_modules; external imports are bound through lake-manifest.json and named here.", + "external_imports": [ + "Mathlib", + "Mathlib.Analysis.Complex.Exponential", + "Mathlib.Analysis.Real.Pi.Bounds", + "Mathlib.Analysis.SpecialFunctions.Trigonometric.Arctan", + "Mathlib.Analysis.SpecialFunctions.Trigonometric.Bounds" + ], + "files": [ + { + "bytes": 11165, + "imports": [ + "JackalIv.Model", + "JackalIv.Pad" + ], + "module": "JackalIv.Arith", + "path": "proofs/lean/JackalIv/Arith.lean", + "sha256": "2bc091be9dd47acae8d4b8af7b272827a3cea7b5ec08773566ad8fe40a12bf83" + }, + { + "bytes": 27102, + "imports": [ + "JackalIv.CertTypes", + "JackalIv.Gaussian", + "JackalIv.Transcend" + ], + "module": "JackalIv.CertCheck", + "path": "proofs/lean/JackalIv/CertCheck.lean", + "sha256": "02cec1630ed5f822f226155e0d4b7c1b62acf056826b03e5e8b191544789b6de" + }, + { + "bytes": 54454, + "imports": [ + "JackalIv.CertCheck" + ], + "module": "JackalIv.CertCodec", + "path": "proofs/lean/JackalIv/CertCodec.lean", + "sha256": "66ac121b53dd12ec395dbd88ddf16f726bf3afdb4946f1f4deabee8af001cd9d" + }, + { + "bytes": 31404, + "imports": [ + "JackalIv.CertCodec", + "JackalIv.CertSound", + "JackalIv.Correspondence" + ], + "module": "JackalIv.CertRequest", + "path": "proofs/lean/JackalIv/CertRequest.lean", + "sha256": "fb57f1c3dfac97362629045f9b6342978150630836a4c3b2f76e6e8f2351073a" + }, + { + "bytes": 52899, + "imports": [ + "JackalIv.CertCheck", + "JackalIv.Embed" + ], + "module": "JackalIv.CertSound", + "path": "proofs/lean/JackalIv/CertSound.lean", + "sha256": "bc602fc99d0652fb78de65488065337000ac5fa78038273d22abc702215a0ec9" + }, + { + "bytes": 16791, + "imports": [ + "JackalIv.Syntax" + ], + "module": "JackalIv.CertTypes", + "path": "proofs/lean/JackalIv/CertTypes.lean", + "sha256": "0f241bce34f817a1f415d9722d0c34652cb4f312b7261d842b4000b23d7b4139" + }, + { + "bytes": 6139, + "imports": [ + "JackalIv.Parser", + "JackalIv.Lower", + "JackalIv.Dump", + "JackalIv.Embed" + ], + "module": "JackalIv.Correspondence", + "path": "proofs/lean/JackalIv/Correspondence.lean", + "sha256": "2b4acd4c904c8069f65a230eabf5bd1cacc0c73d077df650bbf12a24c12b18f3" + }, + { + "bytes": 30555, + "imports": [ + "JackalIv.Syntax", + "JackalIv.Taylor" + ], + "module": "JackalIv.Deriv", + "path": "proofs/lean/JackalIv/Deriv.lean", + "sha256": "618bce22f169ce7ff4b0f2b53d0148451b0bb3dafb64d2a01b4082560adca77e" + }, + { + "bytes": 12026, + "imports": [ + "JackalIv.Parser" + ], + "module": "JackalIv.Dump", + "path": "proofs/lean/JackalIv/Dump.lean", + "sha256": "3baba94104288e5783c763723f9582a25db40131849a41e743669cfac8445495" + }, + { + "bytes": 33040, + "imports": [ + "JackalIv.Syntax", + "JackalIv.Gaussian" + ], + "module": "JackalIv.Embed", + "path": "proofs/lean/JackalIv/Embed.lean", + "sha256": "0a1ff6ddbcea4ca9d36ad3ae099ac361bd2e863250f42e4b3fecac6d79b4947c" + }, + { + "bytes": 17004, + "imports": [ + "JackalIv.Model", + "JackalIv.Pad", + "JackalIv.Arith", + "JackalIv.Monotone", + "JackalIv.Pow" + ], + "module": "JackalIv.Exact", + "path": "proofs/lean/JackalIv/Exact.lean", + "sha256": "a4c0f493b0d69b1a9756205d7b61f5852bde225a5fe532140ec178b97576ce28" + }, + { + "bytes": 7290, + "imports": [ + "JackalIv.Taylor", + "Mathlib.Analysis.Complex.Exponential" + ], + "module": "JackalIv.Gaussian", + "path": "proofs/lean/JackalIv/Gaussian.lean", + "sha256": "2aaaaa895141dab699f6cd936639948976e9560c07d015708e02545b02a045fe" + }, + { + "bytes": 18448, + "imports": [ + "JackalIv.IntCertTypes", + "JackalIv.CertRequest" + ], + "module": "JackalIv.IntCertCheck", + "path": "proofs/lean/JackalIv/IntCertCheck.lean", + "sha256": "a225b06b8ef09906eb4b54954616578b74bdf9151a9101d53828b306d86be0b8" + }, + { + "bytes": 10176, + "imports": [ + "JackalIv.CertCodec", + "JackalIv.IntCertTypes" + ], + "module": "JackalIv.IntCertCodec", + "path": "proofs/lean/JackalIv/IntCertCodec.lean", + "sha256": "82c59bec607d97e3e72a0d251d5efebfd1b4b5641c34ba2fd3798e5d12c23072" + }, + { + "bytes": 2086, + "imports": [ + "JackalIv.IntCertCodec", + "JackalIv.IntCertCheck", + "JackalIv.IntCertSound" + ], + "module": "JackalIv.IntCertMain", + "path": "proofs/lean/JackalIv/IntCertMain.lean", + "sha256": "de900f9b4699be843784b596efcf6dbcdb32b0177819a58bef4c462fde20cbac" + }, + { + "bytes": 12823, + "imports": [ + "JackalIv.Syntax" + ], + "module": "JackalIv.IntCertMeasure", + "path": "proofs/lean/JackalIv/IntCertMeasure.lean", + "sha256": "5ccae2f48055e00503657dfff16af24d813cd721fc7a789bdb93e39b29331c3f" + }, + { + "bytes": 14280, + "imports": [ + "JackalIv.CertTypes", + "JackalIv.Deriv" + ], + "module": "JackalIv.IntCertQExpr", + "path": "proofs/lean/JackalIv/IntCertQExpr.lean", + "sha256": "91fec5cb08fd9a9cc4bcc2a2486526785a464d469aaee3b7828b599cbc07d87b" + }, + { + "bytes": 33862, + "imports": [ + "JackalIv.IntCertCheck", + "JackalIv.IntCertMeasure" + ], + "module": "JackalIv.IntCertSound", + "path": "proofs/lean/JackalIv/IntCertSound.lean", + "sha256": "5c4b8d92f6f3b03cc47716d78b5ed7dd85b3b6a552849fc95a4a085fc5c6c541" + }, + { + "bytes": 6746, + "imports": [ + "JackalIv.CertRequest", + "JackalIv.IntCertQExpr" + ], + "module": "JackalIv.IntCertTypes", + "path": "proofs/lean/JackalIv/IntCertTypes.lean", + "sha256": "b1a3b9f7fe81cce66180f032a0d91e385d901be4714e65a5c43f3ea991ad0877" + }, + { + "bytes": 17818, + "imports": [ + "JackalIv.Syntax" + ], + "module": "JackalIv.Lower", + "path": "proofs/lean/JackalIv/Lower.lean", + "sha256": "32d7f453bee0ddc1999b2693f8bb9bdb9706976172e29a120e23aa118409d9f2" + }, + { + "bytes": 3704, + "imports": [ + "Mathlib" + ], + "module": "JackalIv.Model", + "path": "proofs/lean/JackalIv/Model.lean", + "sha256": "81b13207259c86ccd816cf3d93dd70f11cc042722f2b42320b61ec7a301cb306" + }, + { + "bytes": 6837, + "imports": [ + "JackalIv.Model", + "JackalIv.Pad" + ], + "module": "JackalIv.Monotone", + "path": "proofs/lean/JackalIv/Monotone.lean", + "sha256": "87f262d6f0fb7d60b7ea1fdc716c95625c6131830aee0e2d5a45d62397533a8e" + }, + { + "bytes": 4695, + "imports": [ + "JackalIv.Model" + ], + "module": "JackalIv.Pad", + "path": "proofs/lean/JackalIv/Pad.lean", + "sha256": "82cce18646e2522695fec7c68796f9a60a85abc20b6bfe1c45dac8070578c5d1" + }, + { + "bytes": 23310, + "imports": [ + "JackalIv.Syntax" + ], + "module": "JackalIv.Parser", + "path": "proofs/lean/JackalIv/Parser.lean", + "sha256": "fe5d803c7af09e36d1543517921af618351390f49ebbb46f0ecc1f79b2a86cc3" + }, + { + "bytes": 11388, + "imports": [ + "JackalIv.Model", + "JackalIv.Pad", + "JackalIv.Arith" + ], + "module": "JackalIv.Pow", + "path": "proofs/lean/JackalIv/Pow.lean", + "sha256": "0d80581069c3934274ca4992c6c07867e10821c8fedc43ec6c6fedd6e0971332" + }, + { + "bytes": 17044, + "imports": [ + "JackalIv.Model", + "JackalIv.Pad", + "JackalIv.Arith", + "JackalIv.Monotone", + "JackalIv.Exact", + "JackalIv.Pow", + "JackalIv.Trig" + ], + "module": "JackalIv.Syntax", + "path": "proofs/lean/JackalIv/Syntax.lean", + "sha256": "552bf222b26a615b779a5f0c8abf44beb258609551b158ee3141729dedcf7651" + }, + { + "bytes": 25406, + "imports": [ + "JackalIv.Model", + "JackalIv.Pad" + ], + "module": "JackalIv.Taylor", + "path": "proofs/lean/JackalIv/Taylor.lean", + "sha256": "b3a5c2bbb8374b845624f13fc66b7cb8ad0bf0ca987c6b923631f3ea275febd2" + }, + { + "bytes": 20215, + "imports": [ + "JackalIv.Gaussian", + "Mathlib.Analysis.SpecialFunctions.Trigonometric.Bounds", + "Mathlib.Analysis.SpecialFunctions.Trigonometric.Arctan", + "Mathlib.Analysis.Real.Pi.Bounds" + ], + "module": "JackalIv.Transcend", + "path": "proofs/lean/JackalIv/Transcend.lean", + "sha256": "2fce308fdf161d6fc1edb3d41cb0148e6d8544ab0954a17a7c29ae915a7f1569" + }, + { + "bytes": 24529, + "imports": [ + "JackalIv.Model", + "JackalIv.Pad" + ], + "module": "JackalIv.Trig", + "path": "proofs/lean/JackalIv/Trig.lean", + "sha256": "c65e6db19679c0081d833d4a15cf9d46b4f73e395ed7564505fc0c2e586078d4" + } + ], + "local_construct_policy": { + "allowed_exact_source_lines": [ + { + "construct": "implemented_by", + "path": "proofs/lean/JackalIv/Correspondence.lean", + "source_lines": [ + "@[implemented_by Dump.parseSexpImpl]", + "@[implemented_by Dump.lowerSexpImpl]" + ] + } + ], + "forbidden_by_default": [ + "admit", + "axiom_declaration", + "extern", + "implemented_by", + "native_decide", + "partial", + "sorry", + "unsafe" + ] + }, + "root_modules": [ + "JackalIv.IntCertMain" + ] + }, + "toolchain": { + "configuration_files": [ + { + "path": "proofs/lean/lakefile.toml", + "sha256": "21eef36ea0d9a665622b171dcf1f96460aa250ef214314d766112e01dadf1eaf" + }, + { + "path": "proofs/lean/lake-manifest.json", + "sha256": "f521808691ba1ab175c5cdeec098a76586d345fea93370a38c2d2b73645f69d4" + }, + { + "path": "proofs/lean/lean-toolchain", + "sha256": "2773c517aa90b66ea8a2c52bddddf84393157797f8341be0df45294fff7fd32e" + } + ], + "lake_version": "Lake version 5.0.0-src+8c9756b (Lean version 4.32.0)", + "lean": { + "build": "Release", + "commit": "8c9756b28d64dab099da31a4c09229a9e6a2ef35", + "version": "4.32.0" + }, + "lean_toolchain": "leanprover/lean4:v4.32.0", + "manifest_packages": [ + { + "config_file": "lakefile.toml", + "inherited": true, + "input_revision": "v4.32.0", + "manifest_file": "lake-manifest.json", + "name": "Cli", + "revision": "88679d088c9720c27ebdf2ba4dafe17341747f94", + "scope": "leanprover", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover/lean4-cli" + }, + { + "config_file": "lakefile.toml", + "inherited": true, + "input_revision": "main", + "manifest_file": "lake-manifest.json", + "name": "LeanSearchClient", + "revision": "c5d5b8fe6e5158def25cd28eb94e4141ad97c843", + "scope": "leanprover-community", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover-community/LeanSearchClient" + }, + { + "config_file": "lakefile.toml", + "inherited": true, + "input_revision": "master", + "manifest_file": "lake-manifest.json", + "name": "Qq", + "revision": "38d591e778f100aec9762bb582f9c7f55f50e9dc", + "scope": "leanprover-community", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover-community/quote4" + }, + { + "config_file": "lakefile.toml", + "inherited": true, + "input_revision": "master", + "manifest_file": "lake-manifest.json", + "name": "aesop", + "revision": "a7dbf0c63b694e47f425f3dcddbc0e178bb432d3", + "scope": "leanprover-community", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover-community/aesop" + }, + { + "config_file": "lakefile.toml", + "inherited": true, + "input_revision": "main", + "manifest_file": "lake-manifest.json", + "name": "batteries", + "revision": "023ce7d62a0531e22a5331e20b587817a80d49ff", + "scope": "leanprover-community", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover-community/batteries" + }, + { + "config_file": "lakefile.toml", + "inherited": true, + "input_revision": "main", + "manifest_file": "lake-manifest.json", + "name": "importGraph", + "revision": "7e9612bf0b9ee66db3cb5b9988a35afc706f5a12", + "scope": "leanprover-community", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover-community/import-graph" + }, + { + "config_file": "lakefile.lean", + "inherited": false, + "input_revision": "v4.32.0", + "manifest_file": "lake-manifest.json", + "name": "mathlib", + "revision": "81a5d257c8e410db227a6665ed08f64fea08e997", + "scope": "", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover-community/mathlib4" + }, + { + "config_file": "lakefile.toml", + "inherited": true, + "input_revision": "main", + "manifest_file": "lake-manifest.json", + "name": "plausible", + "revision": "e12c1910fe855cbfc38803cd4e55543906d5fa62", + "scope": "leanprover-community", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover-community/plausible" + }, + { + "config_file": "lakefile.lean", + "inherited": true, + "input_revision": "main", + "manifest_file": "lake-manifest.json", + "name": "proofwidgets", + "revision": "6e311e2a844da9b2cc3971187df2fe0066947b93", + "scope": "leanprover-community", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover-community/ProofWidgets4" + } + ], + "mathlib_commit": "81a5d257c8e410db227a6665ed08f64fea08e997", + "package_checkout_policy": "Every git package checkout is clean and its HEAD equals its full lake-manifest revision during generation and verification." + } +} diff --git a/release/evidence/lean_admission_audit_v173.linux-aarch64.json b/release/evidence/lean_admission_audit_v173.linux-aarch64.json new file mode 100644 index 0000000..fe52e61 --- /dev/null +++ b/release/evidence/lean_admission_audit_v173.linux-aarch64.json @@ -0,0 +1,803 @@ +{ + "audit_digest_sha256": "1cf4ad275356b38eda697d18ffb782f50b041a46a3fef373e0594f6c92375447", + "audit_result": { + "logical_admission_count": 0, + "repository_axiom_declaration_count": 0, + "status": "pass", + "unexpected_construct_count": 0 + }, + "generator": { + "bytes": 36483, + "path": "tools/lean_admission_audit.py", + "sha256": "d72856931ddd1ede4e62d2312b660d71010df833d00eb3eded7ae381d9a2c768" + }, + "release_bindings": { + "compatibility_snapshot_inputs": { + "classification": "Compatibility snapshots constrain replay or refusal policy; they are evidence inputs, not Lean logical admissions.", + "current_release_epoch": "v1.7.2", + "floor_bytes": 3474, + "floor_path": "release/compat/v172_floor.json", + "floor_sha256": "1a7baa000a86a07189df2cec73258db431cd5ab66e80465c5770b980e0ee4f61", + "reversed_interval_policy": "revoked-refuse", + "snapshots": [ + { + "allowed_release_epochs": [], + "epoch_class": "archival_v1", + "identity_path": "release/evidence/int_cert_proof_identity.json", + "identity_schema": "jackal-int-cert-proof-identity-v1", + "identity_sha256": "f0323e312d8b0e05a7200546fd819fc191d5f146d359bb14efec5b1575f16844", + "lane": "int_cert", + "mode": "revoked-refuse", + "reason": "v1 artifact-only checker does not bind the raw request expression to the proved QExpr" + }, + { + "allowed_release_epochs": [ + "v1.7.2" + ], + "epoch_class": "current", + "identity_path": "release/evidence/int_cert_proof_identity_v172.json", + "identity_schema": "jackal-int-cert-proof-identity-v2", + "identity_sha256": "a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf", + "lane": "int_cert", + "mode": "current", + "reason": null + }, + { + "allowed_release_epochs": [ + "v1.5.0" + ], + "epoch_class": "archival_v1", + "identity_path": "release/evidence/range_proof_identity.json", + "identity_schema": "jackal-range-proof-identity-v1", + "identity_sha256": "1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67", + "lane": "range", + "mode": "replay-only", + "reason": null + }, + { + "allowed_release_epochs": [ + "v1.7.2" + ], + "epoch_class": "current", + "identity_path": "release/evidence/range_proof_identity_v172.json", + "identity_schema": "jackal-range-proof-identity-v2", + "identity_sha256": "84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c", + "lane": "range", + "mode": "current", + "reason": null + }, + { + "allowed_release_epochs": [ + "v1.5.0" + ], + "epoch_class": "archival_v1", + "identity_path": "release/evidence/range_proof_identity.json", + "identity_schema": "jackal-range-proof-identity-v1", + "identity_sha256": "1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67", + "lane": "rational_variants", + "mode": "replay-only", + "reason": null + }, + { + "allowed_release_epochs": [ + "v1.7.2" + ], + "epoch_class": "current", + "identity_path": "release/evidence/range_proof_identity_v172.json", + "identity_schema": "jackal-range-proof-identity-v2", + "identity_sha256": "84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c", + "lane": "rational_variants", + "mode": "current", + "reason": null + } + ], + "unsupported_policy": "refuse" + }, + "current_proof_identities": [ + { + "checker_bytes": 181566968, + "checker_path": "proofs/lean/.lake/build/bin/jackal_cert_check", + "checker_sha256": "89e4e42d8daa57d4a9a19f9b95b29bd5e96fae5ad7060ac3adf355f1dfeb870c", + "identity_bytes": 18388, + "identity_checker_bytes": 181566968, + "identity_checker_sha256": "89e4e42d8daa57d4a9a19f9b95b29bd5e96fae5ad7060ac3adf355f1dfeb870c", + "identity_digest_sha256": "e373a459c1ddbd87be1b8bb881440338872a527cf1805d13340833e2e7d098d1", + "identity_path": "release/evidence/range_proof_identity_v172.linux-aarch64.json", + "identity_schema": "jackal-range-proof-identity-v2", + "identity_sha256": "c6caed2434cbd77cba19bb0279936bfa322a696301e6d20c932a9b412f2fa0ca", + "lane": "range", + "root_modules": [ + "JackalIv.CertCheckMain" + ], + "theorems": [ + "JackalIv.Cert.request_bound_certified_release", + "JackalIv.Cert.requestMatches_true", + "JackalIv.Cert.requestMatches_interval_order", + "JackalIv.Cert.releaseNodesOk_modelTCB", + "JackalIv.Cert.lowerRaw_toExpr", + "JackalIv.Cert.rawExprOf_toExpr", + "JackalIv.Cert.cert_check_sound", + "JackalIv.parse_lower_encloses" + ] + }, + { + "checker_bytes": 181303904, + "checker_path": "proofs/lean/.lake/build/bin/jackal_gaussian_check", + "checker_sha256": "1f21c6b2e41c171414405c0aa6fee089851716d1add707727ace45395f4ed379", + "identity_bytes": 16114, + "identity_checker_bytes": 181303904, + "identity_checker_sha256": "1f21c6b2e41c171414405c0aa6fee089851716d1add707727ace45395f4ed379", + "identity_digest_sha256": "489780aab2b7b5f16bc529b141c5c7967a9307cbc539c3fff8eab9f0789263fe", + "identity_path": "release/evidence/gaussian_proof_identity.linux-aarch64.json", + "identity_schema": "jackal-gaussian-proof-identity-v1", + "identity_sha256": "610624b48f48dcd089e0ad14ddac7ebbc25071e7d70cc8516ad6c3c09c747404", + "lane": "gaussian", + "root_modules": [ + "JackalIv.GaussianCertMain" + ], + "theorems": [ + "JackalIv.GaussianCert.gaussian_integral_check_sound", + "JackalIv.Gaussian.scaled_gaussian_enclosed", + "JackalIv.Gaussian.checker_core_enclosed", + "JackalIv.Gaussian.expNegQ_encloses", + "JackalIv.Gaussian.sqrtPi_enclosed", + "JackalIv.GaussianCert.checkCert_iff" + ] + }, + { + "checker_bytes": 181725072, + "checker_path": "proofs/lean/.lake/build/bin/jackal_int_cert_check", + "checker_sha256": "f2e26f506f921b577fd8609a095b69789b3b76cce65d8c293d1a11f3007a8078", + "identity_bytes": 22009, + "identity_checker_bytes": 181725072, + "identity_checker_sha256": "f2e26f506f921b577fd8609a095b69789b3b76cce65d8c293d1a11f3007a8078", + "identity_digest_sha256": "a024ab9cb1010721297703bab38a0e43a7a48ac65b0c1d71292599e813e3dad9", + "identity_path": "release/evidence/int_cert_proof_identity_v172.linux-aarch64.json", + "identity_schema": "jackal-int-cert-proof-identity-v2", + "identity_sha256": "533c5cc4718331e2739ec92513487842aa48471b4b7d1be57db08999a9d90f95", + "lane": "int-cert", + "root_modules": [ + "JackalIv.IntCertMain" + ], + "theorems": [ + "JackalIv.IntCert.int_cert_sound", + "JackalIv.IntCert.int_cert_core_sound", + "JackalIv.IntCert.intRequestMatches_true", + "JackalIv.IntCert.checkIntCertRequest_ok", + "JackalIv.IntCert.checkIntCert_rootQExpr_exists", + "JackalIv.IntCert.rootRawExpr_rootQExpr_embed", + "JackalIv.IntCert.range_leaf_sound", + "JackalIv.IntCert.taylor2_leaf_sound", + "JackalIv.IntCert.taylor4_leaf_sound", + "JackalIv.IntCert.split_sound", + "JackalIv.IntCert.sem_measurable", + "JackalIv.IntCert.embedQ_DQ", + "JackalIv.IntCert.qexprOf_embed", + "JackalIv.Cert.releaseNodesOk_modelTCB", + "JackalIv.Cert.cert_check_sound" + ] + } + ], + "lane_identifier_mapping": { + "classification": "Compatibility-floor lane keys and proof-checker lane ids are separate namespaces; this map is their explicit relationship.", + "compatibility_floor_to_proof_checker": { + "int_cert": "int-cert", + "range": "range", + "rational_variants": "range" + }, + "proof_checker_without_compatibility_floor": [ + "gaussian" + ] + }, + "release_state": "v1.7.3" + }, + "residual_nonclaims": [ + "This audit is not a cryptographic signature or builder authentication.", + "Lean kernel, compiler, mathlib, operating system, hardware, and supply chain remain trusted dependencies.", + "The audit does not prove Lean source-to-native checker refinement.", + "Runtime request parsing, provenance validation, and release-policy enforcement remain outside the named theorem statements except where a checker premise explicitly binds them.", + "Compatibility snapshots state replay/refusal policy and do not turn historical artifacts into current proofs." + ], + "schema": "jackal-lean-admission-audit-v1", + "source_inventory": { + "aggregate_sha256": "8cacb3fe30d3cf9ae10e9c939d7d7a56efb90f41ddfbdab578dbacd6253aa32c", + "construct_policy": { + "allowed_exact_source_lines": [ + { + "construct": "implemented_by", + "path": "proofs/lean/JackalIv/Correspondence.lean", + "source_line": "@[implemented_by Dump.parseSexpImpl]" + }, + { + "construct": "implemented_by", + "path": "proofs/lean/JackalIv/Correspondence.lean", + "source_line": "@[implemented_by Dump.lowerSexpImpl]" + } + ], + "allowed_findings": [ + { + "classification": "dump-only trusted runtime mirror", + "construct": "implemented_by", + "line": 102, + "path": "proofs/lean/JackalIv/Correspondence.lean", + "source_line": "@[implemented_by Dump.parseSexpImpl]" + }, + { + "classification": "dump-only trusted runtime mirror", + "construct": "implemented_by", + "line": 108, + "path": "proofs/lean/JackalIv/Correspondence.lean", + "source_line": "@[implemented_by Dump.lowerSexpImpl]" + } + ], + "forbidden_by_default": [ + "admit", + "axiom_declaration", + "extern", + "implemented_by", + "native_decide", + "partial", + "sorry", + "unsafe" + ], + "forbidden_findings": [], + "noncomputable_classification": "Lean noncomputable declarations are counted but are not logical admissions or executable-code substitutions.", + "noncomputable_occurrences": 37, + "scan_scope": "comments and string bodies removed; executable Lean tokens scanned" + }, + "file_count": 42, + "files": [ + { + "bytes": 1035, + "path": "proofs/lean/JackalIv.lean", + "sha256": "fffba0936e102b0cb6dfc5d7521e242f818d3c8bc0530ea8073dba79b5229c8b" + }, + { + "bytes": 11165, + "path": "proofs/lean/JackalIv/Arith.lean", + "sha256": "2bc091be9dd47acae8d4b8af7b272827a3cea7b5ec08773566ad8fe40a12bf83" + }, + { + "bytes": 27102, + "path": "proofs/lean/JackalIv/CertCheck.lean", + "sha256": "02cec1630ed5f822f226155e0d4b7c1b62acf056826b03e5e8b191544789b6de" + }, + { + "bytes": 3768, + "path": "proofs/lean/JackalIv/CertCheckMain.lean", + "sha256": "81ad8de226c15e7c3398e9aaa76abe85981ec0d1f94b958ed455e163361e698c" + }, + { + "bytes": 54454, + "path": "proofs/lean/JackalIv/CertCodec.lean", + "sha256": "66ac121b53dd12ec395dbd88ddf16f726bf3afdb4946f1f4deabee8af001cd9d" + }, + { + "bytes": 31404, + "path": "proofs/lean/JackalIv/CertRequest.lean", + "sha256": "fb57f1c3dfac97362629045f9b6342978150630836a4c3b2f76e6e8f2351073a" + }, + { + "bytes": 3791, + "path": "proofs/lean/JackalIv/CertRequestOrderingContract.lean", + "sha256": "1795649d74abf8f9bc88ca48db461e768e3bdfdd27beb3d314ffeefba6ffb950" + }, + { + "bytes": 52899, + "path": "proofs/lean/JackalIv/CertSound.lean", + "sha256": "bc602fc99d0652fb78de65488065337000ac5fa78038273d22abc702215a0ec9" + }, + { + "bytes": 16791, + "path": "proofs/lean/JackalIv/CertTypes.lean", + "sha256": "0f241bce34f817a1f415d9722d0c34652cb4f312b7261d842b4000b23d7b4139" + }, + { + "bytes": 6139, + "path": "proofs/lean/JackalIv/Correspondence.lean", + "sha256": "2b4acd4c904c8069f65a230eabf5bd1cacc0c73d077df650bbf12a24c12b18f3" + }, + { + "bytes": 21715, + "path": "proofs/lean/JackalIv/CritIn.lean", + "sha256": "e1cd562087083e985162654f416f423f8bfbf8b9457b781ada32f0f6a533a27a" + }, + { + "bytes": 30555, + "path": "proofs/lean/JackalIv/Deriv.lean", + "sha256": "618bce22f169ce7ff4b0f2b53d0148451b0bb3dafb64d2a01b4082560adca77e" + }, + { + "bytes": 12026, + "path": "proofs/lean/JackalIv/Dump.lean", + "sha256": "3baba94104288e5783c763723f9582a25db40131849a41e743669cfac8445495" + }, + { + "bytes": 33040, + "path": "proofs/lean/JackalIv/Embed.lean", + "sha256": "0a1ff6ddbcea4ca9d36ad3ae099ac361bd2e863250f42e4b3fecac6d79b4947c" + }, + { + "bytes": 17004, + "path": "proofs/lean/JackalIv/Exact.lean", + "sha256": "a4c0f493b0d69b1a9756205d7b61f5852bde225a5fe532140ec178b97576ce28" + }, + { + "bytes": 7290, + "path": "proofs/lean/JackalIv/Gaussian.lean", + "sha256": "2aaaaa895141dab699f6cd936639948976e9560c07d015708e02545b02a045fe" + }, + { + "bytes": 7647, + "path": "proofs/lean/JackalIv/GaussianCert.lean", + "sha256": "a86f48a1dcf7a6eaa5170b984cd97815644e25cd19ab13bcd2e87020786b9b7e" + }, + { + "bytes": 1001, + "path": "proofs/lean/JackalIv/GaussianCertMain.lean", + "sha256": "1690e3412ec811567da9801dbeda7d57b30735f461e22711a97ebe99f5017aa3" + }, + { + "bytes": 9715, + "path": "proofs/lean/JackalIv/GaussianIntegral.lean", + "sha256": "7c3b53502d4d64a4d17ffa59929565e37d9f5a1c45cd8aec93bbfe9d9a6ee16b" + }, + { + "bytes": 18448, + "path": "proofs/lean/JackalIv/IntCertCheck.lean", + "sha256": "a225b06b8ef09906eb4b54954616578b74bdf9151a9101d53828b306d86be0b8" + }, + { + "bytes": 10176, + "path": "proofs/lean/JackalIv/IntCertCodec.lean", + "sha256": "82c59bec607d97e3e72a0d251d5efebfd1b4b5641c34ba2fd3798e5d12c23072" + }, + { + "bytes": 3973, + "path": "proofs/lean/JackalIv/IntCertFixtures.lean", + "sha256": "da82459425ec8d04bf35b5ad60341987429511594341f34a4dc1fb9fba8067cc" + }, + { + "bytes": 2086, + "path": "proofs/lean/JackalIv/IntCertMain.lean", + "sha256": "de900f9b4699be843784b596efcf6dbcdb32b0177819a58bef4c462fde20cbac" + }, + { + "bytes": 12823, + "path": "proofs/lean/JackalIv/IntCertMeasure.lean", + "sha256": "5ccae2f48055e00503657dfff16af24d813cd721fc7a789bdb93e39b29331c3f" + }, + { + "bytes": 1975, + "path": "proofs/lean/JackalIv/IntCertPremiseContract.lean", + "sha256": "3a5c493ddf1badfa1ac44b04af5154f7e81417e7b11b387ac3783403e1c180c2" + }, + { + "bytes": 14280, + "path": "proofs/lean/JackalIv/IntCertQExpr.lean", + "sha256": "91fec5cb08fd9a9cc4bcc2a2486526785a464d469aaee3b7828b599cbc07d87b" + }, + { + "bytes": 33862, + "path": "proofs/lean/JackalIv/IntCertSound.lean", + "sha256": "5c4b8d92f6f3b03cc47716d78b5ed7dd85b3b6a552849fc95a4a085fc5c6c541" + }, + { + "bytes": 6746, + "path": "proofs/lean/JackalIv/IntCertTypes.lean", + "sha256": "b1a3b9f7fe81cce66180f032a0d91e385d901be4714e65a5c43f3ea991ad0877" + }, + { + "bytes": 21540, + "path": "proofs/lean/JackalIv/Ledger.lean", + "sha256": "dd2c1a3328c8759431b1deed3b38d9efc2fde4f6ac3626eb1e4303811304a753" + }, + { + "bytes": 17818, + "path": "proofs/lean/JackalIv/Lower.lean", + "sha256": "32d7f453bee0ddc1999b2693f8bb9bdb9706976172e29a120e23aa118409d9f2" + }, + { + "bytes": 7137, + "path": "proofs/lean/JackalIv/Midpoint.lean", + "sha256": "54cdda7dd3473a7dd6f2661449ad9b99925e79f3e557bdea2dff9b61810c0419" + }, + { + "bytes": 3704, + "path": "proofs/lean/JackalIv/Model.lean", + "sha256": "81b13207259c86ccd816cf3d93dd70f11cc042722f2b42320b61ec7a301cb306" + }, + { + "bytes": 6837, + "path": "proofs/lean/JackalIv/Monotone.lean", + "sha256": "87f262d6f0fb7d60b7ea1fdc716c95625c6131830aee0e2d5a45d62397533a8e" + }, + { + "bytes": 4695, + "path": "proofs/lean/JackalIv/Pad.lean", + "sha256": "82cce18646e2522695fec7c68796f9a60a85abc20b6bfe1c45dac8070578c5d1" + }, + { + "bytes": 1542, + "path": "proofs/lean/JackalIv/ParseDumpMain.lean", + "sha256": "9de4d4e15f816718594082b7a58bb19226794dda1ec3203f24ea7c5ecc273cec" + }, + { + "bytes": 23310, + "path": "proofs/lean/JackalIv/Parser.lean", + "sha256": "fe5d803c7af09e36d1543517921af618351390f49ebbb46f0ecc1f79b2a86cc3" + }, + { + "bytes": 11388, + "path": "proofs/lean/JackalIv/Pow.lean", + "sha256": "0d80581069c3934274ca4992c6c07867e10821c8fedc43ec6c6fedd6e0971332" + }, + { + "bytes": 8639, + "path": "proofs/lean/JackalIv/Solve.lean", + "sha256": "c6421cb46b54571ffec8c5177fa915dfe57a746be47f20d80e990a44a6166d90" + }, + { + "bytes": 17044, + "path": "proofs/lean/JackalIv/Syntax.lean", + "sha256": "552bf222b26a615b779a5f0c8abf44beb258609551b158ee3141729dedcf7651" + }, + { + "bytes": 25406, + "path": "proofs/lean/JackalIv/Taylor.lean", + "sha256": "b3a5c2bbb8374b845624f13fc66b7cb8ad0bf0ca987c6b923631f3ea275febd2" + }, + { + "bytes": 20215, + "path": "proofs/lean/JackalIv/Transcend.lean", + "sha256": "2fce308fdf161d6fc1edb3d41cb0148e6d8544ab0954a17a7c29ae915a7f1569" + }, + { + "bytes": 24529, + "path": "proofs/lean/JackalIv/Trig.lean", + "sha256": "c65e6db19679c0081d833d4a15cf9d46b4f73e395ed7564505fc0c2e586078d4" + } + ], + "inventory_source": "git-ls-files" + }, + "theorem_axiom_audit": { + "allowed_exactly": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "command": "lake env lean /dev/stdin", + "invocations": [ + { + "input_program_sha256": "c386a99e206c4c3704a4a9300314b8675a239068a12a71aa718fcd1c08829528", + "lane": "range", + "output_sha256": "e381ce9d94cefcd81f860227e08fb2b16b98a77a97d25f25692fadf389dd0377", + "root_modules": [ + "JackalIv.CertCheckMain" + ], + "theorem_count": 8 + }, + { + "input_program_sha256": "4e56fc1f2ee6f108361a9dc852e185a263485d8e290f281ec9c82474f0e76b18", + "lane": "gaussian", + "output_sha256": "fb230d97d8103500631853f0adfca0c958a3d0a607b26cc8a37dcaea4c7c0f99", + "root_modules": [ + "JackalIv.GaussianCertMain" + ], + "theorem_count": 6 + }, + { + "input_program_sha256": "3b61e5ce72278a7615dd1a44c85ff49d2ec389403d17a6f8840f78462fa91000", + "lane": "int-cert", + "output_sha256": "d5ad3993f550eef9f96092e412d6c1088675b809dee86c444c87b4659b857b9d", + "root_modules": [ + "JackalIv.IntCertMain" + ], + "theorem_count": 15 + } + ], + "root_modules": [ + "JackalIv.CertCheckMain", + "JackalIv.GaussianCertMain", + "JackalIv.IntCertMain" + ], + "theorem_count": 27, + "theorems": [ + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "raw_output": "'JackalIv.Cert.cert_check_sound' depends on axioms: [propext, Classical.choice, Quot.sound]", + "theorem": "JackalIv.Cert.cert_check_sound" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "raw_output": "'JackalIv.Cert.lowerRaw_toExpr' depends on axioms: [propext, Classical.choice, Quot.sound]", + "theorem": "JackalIv.Cert.lowerRaw_toExpr" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "raw_output": "'JackalIv.Cert.rawExprOf_toExpr' depends on axioms: [propext, Classical.choice, Quot.sound]", + "theorem": "JackalIv.Cert.rawExprOf_toExpr" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "raw_output": "'JackalIv.Cert.releaseNodesOk_modelTCB' depends on axioms: [propext, Classical.choice, Quot.sound]", + "theorem": "JackalIv.Cert.releaseNodesOk_modelTCB" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "raw_output": "'JackalIv.Cert.requestMatches_interval_order' depends on axioms: [propext, Classical.choice, Quot.sound]", + "theorem": "JackalIv.Cert.requestMatches_interval_order" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "raw_output": "'JackalIv.Cert.requestMatches_true' depends on axioms: [propext, Classical.choice, Quot.sound]", + "theorem": "JackalIv.Cert.requestMatches_true" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "raw_output": "'JackalIv.Cert.request_bound_certified_release' depends on axioms: [propext, Classical.choice, Quot.sound]", + "theorem": "JackalIv.Cert.request_bound_certified_release" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "raw_output": "'JackalIv.Gaussian.checker_core_enclosed' depends on axioms: [propext, Classical.choice, Quot.sound]", + "theorem": "JackalIv.Gaussian.checker_core_enclosed" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "raw_output": "'JackalIv.Gaussian.expNegQ_encloses' depends on axioms: [propext, Classical.choice, Quot.sound]", + "theorem": "JackalIv.Gaussian.expNegQ_encloses" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "raw_output": "'JackalIv.Gaussian.scaled_gaussian_enclosed' depends on axioms: [propext, Classical.choice, Quot.sound]", + "theorem": "JackalIv.Gaussian.scaled_gaussian_enclosed" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "raw_output": "'JackalIv.Gaussian.sqrtPi_enclosed' depends on axioms: [propext, Classical.choice, Quot.sound]", + "theorem": "JackalIv.Gaussian.sqrtPi_enclosed" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "raw_output": "'JackalIv.GaussianCert.checkCert_iff' depends on axioms: [propext, Classical.choice, Quot.sound]", + "theorem": "JackalIv.GaussianCert.checkCert_iff" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "raw_output": "'JackalIv.GaussianCert.gaussian_integral_check_sound' depends on axioms: [propext, Classical.choice, Quot.sound]", + "theorem": "JackalIv.GaussianCert.gaussian_integral_check_sound" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "raw_output": "'JackalIv.IntCert.checkIntCertRequest_ok' depends on axioms: [propext, Classical.choice, Quot.sound]", + "theorem": "JackalIv.IntCert.checkIntCertRequest_ok" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "raw_output": "'JackalIv.IntCert.checkIntCert_rootQExpr_exists' depends on axioms: [propext, Classical.choice, Quot.sound]", + "theorem": "JackalIv.IntCert.checkIntCert_rootQExpr_exists" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "raw_output": "'JackalIv.IntCert.embedQ_DQ' depends on axioms: [propext, Classical.choice, Quot.sound]", + "theorem": "JackalIv.IntCert.embedQ_DQ" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "raw_output": "'JackalIv.IntCert.intRequestMatches_true' depends on axioms: [propext, Classical.choice, Quot.sound]", + "theorem": "JackalIv.IntCert.intRequestMatches_true" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "raw_output": "'JackalIv.IntCert.int_cert_core_sound' depends on axioms: [propext, Classical.choice, Quot.sound]", + "theorem": "JackalIv.IntCert.int_cert_core_sound" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "raw_output": "'JackalIv.IntCert.int_cert_sound' depends on axioms: [propext, Classical.choice, Quot.sound]", + "theorem": "JackalIv.IntCert.int_cert_sound" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "raw_output": "'JackalIv.IntCert.qexprOf_embed' depends on axioms: [propext, Classical.choice, Quot.sound]", + "theorem": "JackalIv.IntCert.qexprOf_embed" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "raw_output": "'JackalIv.IntCert.range_leaf_sound' depends on axioms: [propext, Classical.choice, Quot.sound]", + "theorem": "JackalIv.IntCert.range_leaf_sound" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "raw_output": "'JackalIv.IntCert.rootRawExpr_rootQExpr_embed' depends on axioms: [propext, Classical.choice, Quot.sound]", + "theorem": "JackalIv.IntCert.rootRawExpr_rootQExpr_embed" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "raw_output": "'JackalIv.IntCert.sem_measurable' depends on axioms: [propext, Classical.choice, Quot.sound]", + "theorem": "JackalIv.IntCert.sem_measurable" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "raw_output": "'JackalIv.IntCert.split_sound' depends on axioms: [propext, Classical.choice, Quot.sound]", + "theorem": "JackalIv.IntCert.split_sound" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "raw_output": "'JackalIv.IntCert.taylor2_leaf_sound' depends on axioms: [propext, Classical.choice, Quot.sound]", + "theorem": "JackalIv.IntCert.taylor2_leaf_sound" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "raw_output": "'JackalIv.IntCert.taylor4_leaf_sound' depends on axioms: [propext, Classical.choice, Quot.sound]", + "theorem": "JackalIv.IntCert.taylor4_leaf_sound" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "raw_output": "'JackalIv.parse_lower_encloses' depends on axioms: [propext, Classical.choice, Quot.sound]", + "theorem": "JackalIv.parse_lower_encloses" + } + ] + }, + "toolchain": { + "configuration_files": [ + { + "bytes": 901, + "path": "proofs/lean/lakefile.toml", + "sha256": "21eef36ea0d9a665622b171dcf1f96460aa250ef214314d766112e01dadf1eaf" + }, + { + "bytes": 3127, + "path": "proofs/lean/lake-manifest.json", + "sha256": "f521808691ba1ab175c5cdeec098a76586d345fea93370a38c2d2b73645f69d4" + }, + { + "bytes": 25, + "path": "proofs/lean/lean-toolchain", + "sha256": "2773c517aa90b66ea8a2c52bddddf84393157797f8341be0df45294fff7fd32e" + } + ], + "lean": { + "build_profile": "Release", + "commit": "8c9756b28d64dab099da31a4c09229a9e6a2ef35", + "version": "4.32.0" + }, + "lean_toolchain": "leanprover/lean4:v4.32.0", + "mathlib_revision": "81a5d257c8e410db227a6665ed08f64fea08e997" + }, + "trust_surface": { + "allowed_local_runtime_substitutions": [ + { + "classification": "dump-only trusted runtime mirror", + "construct": "implemented_by", + "line": 102, + "path": "proofs/lean/JackalIv/Correspondence.lean", + "source_line": "@[implemented_by Dump.parseSexpImpl]" + }, + { + "classification": "dump-only trusted runtime mirror", + "construct": "implemented_by", + "line": 108, + "path": "proofs/lean/JackalIv/Correspondence.lean", + "source_line": "@[implemented_by Dump.lowerSexpImpl]" + } + ], + "lean_standard_axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "logical_admissions": [], + "repository_axiom_declarations": [], + "runtime_substitution_boundary": "The two implemented_by attributes are confined to dump-only parser/lowering mirrors; current checker acceptance uses neither definition." + } +} diff --git a/release/evidence/range_proof_identity_v172.linux-aarch64.json b/release/evidence/range_proof_identity_v172.linux-aarch64.json new file mode 100644 index 0000000..db64190 --- /dev/null +++ b/release/evidence/range_proof_identity_v172.linux-aarch64.json @@ -0,0 +1,562 @@ +{ + "build_attestation": { + "attestation_digest_sha256": "beef90d7145277dd0b1fb13464595875a148ac9260b17753ea3f49a56b6275f6", + "authentication": { + "authenticated": false, + "scheme": "none", + "statement": "This deterministic record binds observed checker bytes to named inputs. It is not a signature and does not authenticate the builder or artifact." + }, + "build_command": [ + "lake", + "build", + "jackal_cert_check" + ], + "checker": { + "bytes": 181566968, + "path": "proofs/lean/.lake/build/bin/jackal_cert_check", + "sha256": "89e4e42d8daa57d4a9a19f9b95b29bd5e96fae5ad7060ac3adf355f1dfeb870c", + "target": "jackal_cert_check" + }, + "claim_boundary": "This is reproducibility/build-provenance evidence, not a proof of compiler, linker, operating-system, hardware, or supply-chain correctness.", + "compiler_observed_for_build_platform": { + "build": "Release", + "commit": "8c9756b28d64dab099da31a4c09229a9e6a2ef35", + "executable_bytes": 13824, + "executable_sha256": "79fb1d26fa5a39385d59fdc48a711a14b0710ca6480271acce99b4d177cea085", + "target": "aarch64-unknown-linux-gnu", + "version": "4.32.0" + }, + "inputs": { + "lean_commit": "8c9756b28d64dab099da31a4c09229a9e6a2ef35", + "mathlib_commit": "81a5d257c8e410db227a6665ed08f64fea08e997", + "source_closure_sha256": "3994b85ae959554579fd57cb866a2f700f84e4721fa85d16c6fe4dc929825218", + "toolchain_configuration": [ + { + "path": "proofs/lean/lakefile.toml", + "sha256": "21eef36ea0d9a665622b171dcf1f96460aa250ef214314d766112e01dadf1eaf" + }, + { + "path": "proofs/lean/lake-manifest.json", + "sha256": "f521808691ba1ab175c5cdeec098a76586d345fea93370a38c2d2b73645f69d4" + }, + { + "path": "proofs/lean/lean-toolchain", + "sha256": "2773c517aa90b66ea8a2c52bddddf84393157797f8341be0df45294fff7fd32e" + } + ] + }, + "kind": "unsigned-local-build-binding-v1", + "working_directory": "proofs/lean" + }, + "checker": { + "bytes": 181566968, + "path": "proofs/lean/.lake/build/bin/jackal_cert_check", + "sha256": "89e4e42d8daa57d4a9a19f9b95b29bd5e96fae5ad7060ac3adf355f1dfeb870c", + "target": "jackal_cert_check" + }, + "fragment": { + "assurance": "formal-bounded", + "certificate_magic": "jackal-eval-cert v2", + "checker_boolean_definition": "JackalIv.Cert.checkCert", + "checker_entrypoint_definition": "runRequestBound", + "checker_executable": "jackal_cert_check", + "family": "range-request-bound-v1", + "lane": "range", + "parser_definition": "JackalIv.Cert.parseCert", + "premise_closure": "interval order and ModelTCB are derived from requestMatches and the exact release allowlist", + "premises_not_discharged_by_checker": [], + "request_matcher_definition": "JackalIv.Cert.requestMatches", + "runtime_alternate_implementation_boundary": "request acceptance uses no implemented_by definition; two exact dump-only implemented_by attributes elsewhere in the imported closure are pinned", + "soundness_theorem": "JackalIv.Cert.request_bound_certified_release", + "theorem_premises": [ + "requestMatches command rawExpr rawLo rawHi hdr nodes = true (runtime checked)", + "checkCert hdr nodes = true (runtime checked)" + ] + }, + "generator": { + "path": "release/tools/range_proof_identity.py", + "sha256": "4efc0133107f8abe55619dc8b057318203953a7e0580573933f0dd2e47aba826" + }, + "identity_digest_sha256": "e373a459c1ddbd87be1b8bb881440338872a527cf1805d13340833e2e7d098d1", + "proof": { + "axiom_audit_command": "lake env lean /dev/stdin with checked-in #print axioms set", + "axiom_policy": { + "allowed_exactly": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "forbidden": [ + "sorryAx", + "any additional axiom" + ] + }, + "theorems": [ + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "theorem": "JackalIv.Cert.request_bound_certified_release" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "theorem": "JackalIv.Cert.requestMatches_true" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "theorem": "JackalIv.Cert.requestMatches_interval_order" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "theorem": "JackalIv.Cert.releaseNodesOk_modelTCB" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "theorem": "JackalIv.Cert.lowerRaw_toExpr" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "theorem": "JackalIv.Cert.rawExprOf_toExpr" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "theorem": "JackalIv.Cert.cert_check_sound" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "theorem": "JackalIv.parse_lower_encloses" + } + ] + }, + "schema": "jackal-range-proof-identity-v2", + "source_closure": { + "aggregate_sha256": "3994b85ae959554579fd57cb866a2f700f84e4721fa85d16c6fe4dc929825218", + "definition": "Every repository-local transitive Lean import reachable from root_modules; external imports are bound through lake-manifest.json and named here.", + "external_imports": [ + "Mathlib", + "Mathlib.Analysis.Complex.Exponential", + "Mathlib.Analysis.Real.Pi.Bounds", + "Mathlib.Analysis.SpecialFunctions.Trigonometric.Arctan", + "Mathlib.Analysis.SpecialFunctions.Trigonometric.Bounds" + ], + "files": [ + { + "bytes": 11165, + "imports": [ + "JackalIv.Model", + "JackalIv.Pad" + ], + "module": "JackalIv.Arith", + "path": "proofs/lean/JackalIv/Arith.lean", + "sha256": "2bc091be9dd47acae8d4b8af7b272827a3cea7b5ec08773566ad8fe40a12bf83" + }, + { + "bytes": 27102, + "imports": [ + "JackalIv.CertTypes", + "JackalIv.Gaussian", + "JackalIv.Transcend" + ], + "module": "JackalIv.CertCheck", + "path": "proofs/lean/JackalIv/CertCheck.lean", + "sha256": "02cec1630ed5f822f226155e0d4b7c1b62acf056826b03e5e8b191544789b6de" + }, + { + "bytes": 3768, + "imports": [ + "JackalIv.CertRequest" + ], + "module": "JackalIv.CertCheckMain", + "path": "proofs/lean/JackalIv/CertCheckMain.lean", + "sha256": "81ad8de226c15e7c3398e9aaa76abe85981ec0d1f94b958ed455e163361e698c" + }, + { + "bytes": 54454, + "imports": [ + "JackalIv.CertCheck" + ], + "module": "JackalIv.CertCodec", + "path": "proofs/lean/JackalIv/CertCodec.lean", + "sha256": "66ac121b53dd12ec395dbd88ddf16f726bf3afdb4946f1f4deabee8af001cd9d" + }, + { + "bytes": 31404, + "imports": [ + "JackalIv.CertCodec", + "JackalIv.CertSound", + "JackalIv.Correspondence" + ], + "module": "JackalIv.CertRequest", + "path": "proofs/lean/JackalIv/CertRequest.lean", + "sha256": "fb57f1c3dfac97362629045f9b6342978150630836a4c3b2f76e6e8f2351073a" + }, + { + "bytes": 52899, + "imports": [ + "JackalIv.CertCheck", + "JackalIv.Embed" + ], + "module": "JackalIv.CertSound", + "path": "proofs/lean/JackalIv/CertSound.lean", + "sha256": "bc602fc99d0652fb78de65488065337000ac5fa78038273d22abc702215a0ec9" + }, + { + "bytes": 16791, + "imports": [ + "JackalIv.Syntax" + ], + "module": "JackalIv.CertTypes", + "path": "proofs/lean/JackalIv/CertTypes.lean", + "sha256": "0f241bce34f817a1f415d9722d0c34652cb4f312b7261d842b4000b23d7b4139" + }, + { + "bytes": 6139, + "imports": [ + "JackalIv.Parser", + "JackalIv.Lower", + "JackalIv.Dump", + "JackalIv.Embed" + ], + "module": "JackalIv.Correspondence", + "path": "proofs/lean/JackalIv/Correspondence.lean", + "sha256": "2b4acd4c904c8069f65a230eabf5bd1cacc0c73d077df650bbf12a24c12b18f3" + }, + { + "bytes": 12026, + "imports": [ + "JackalIv.Parser" + ], + "module": "JackalIv.Dump", + "path": "proofs/lean/JackalIv/Dump.lean", + "sha256": "3baba94104288e5783c763723f9582a25db40131849a41e743669cfac8445495" + }, + { + "bytes": 33040, + "imports": [ + "JackalIv.Syntax", + "JackalIv.Gaussian" + ], + "module": "JackalIv.Embed", + "path": "proofs/lean/JackalIv/Embed.lean", + "sha256": "0a1ff6ddbcea4ca9d36ad3ae099ac361bd2e863250f42e4b3fecac6d79b4947c" + }, + { + "bytes": 17004, + "imports": [ + "JackalIv.Model", + "JackalIv.Pad", + "JackalIv.Arith", + "JackalIv.Monotone", + "JackalIv.Pow" + ], + "module": "JackalIv.Exact", + "path": "proofs/lean/JackalIv/Exact.lean", + "sha256": "a4c0f493b0d69b1a9756205d7b61f5852bde225a5fe532140ec178b97576ce28" + }, + { + "bytes": 7290, + "imports": [ + "JackalIv.Taylor", + "Mathlib.Analysis.Complex.Exponential" + ], + "module": "JackalIv.Gaussian", + "path": "proofs/lean/JackalIv/Gaussian.lean", + "sha256": "2aaaaa895141dab699f6cd936639948976e9560c07d015708e02545b02a045fe" + }, + { + "bytes": 17818, + "imports": [ + "JackalIv.Syntax" + ], + "module": "JackalIv.Lower", + "path": "proofs/lean/JackalIv/Lower.lean", + "sha256": "32d7f453bee0ddc1999b2693f8bb9bdb9706976172e29a120e23aa118409d9f2" + }, + { + "bytes": 3704, + "imports": [ + "Mathlib" + ], + "module": "JackalIv.Model", + "path": "proofs/lean/JackalIv/Model.lean", + "sha256": "81b13207259c86ccd816cf3d93dd70f11cc042722f2b42320b61ec7a301cb306" + }, + { + "bytes": 6837, + "imports": [ + "JackalIv.Model", + "JackalIv.Pad" + ], + "module": "JackalIv.Monotone", + "path": "proofs/lean/JackalIv/Monotone.lean", + "sha256": "87f262d6f0fb7d60b7ea1fdc716c95625c6131830aee0e2d5a45d62397533a8e" + }, + { + "bytes": 4695, + "imports": [ + "JackalIv.Model" + ], + "module": "JackalIv.Pad", + "path": "proofs/lean/JackalIv/Pad.lean", + "sha256": "82cce18646e2522695fec7c68796f9a60a85abc20b6bfe1c45dac8070578c5d1" + }, + { + "bytes": 23310, + "imports": [ + "JackalIv.Syntax" + ], + "module": "JackalIv.Parser", + "path": "proofs/lean/JackalIv/Parser.lean", + "sha256": "fe5d803c7af09e36d1543517921af618351390f49ebbb46f0ecc1f79b2a86cc3" + }, + { + "bytes": 11388, + "imports": [ + "JackalIv.Model", + "JackalIv.Pad", + "JackalIv.Arith" + ], + "module": "JackalIv.Pow", + "path": "proofs/lean/JackalIv/Pow.lean", + "sha256": "0d80581069c3934274ca4992c6c07867e10821c8fedc43ec6c6fedd6e0971332" + }, + { + "bytes": 17044, + "imports": [ + "JackalIv.Model", + "JackalIv.Pad", + "JackalIv.Arith", + "JackalIv.Monotone", + "JackalIv.Exact", + "JackalIv.Pow", + "JackalIv.Trig" + ], + "module": "JackalIv.Syntax", + "path": "proofs/lean/JackalIv/Syntax.lean", + "sha256": "552bf222b26a615b779a5f0c8abf44beb258609551b158ee3141729dedcf7651" + }, + { + "bytes": 25406, + "imports": [ + "JackalIv.Model", + "JackalIv.Pad" + ], + "module": "JackalIv.Taylor", + "path": "proofs/lean/JackalIv/Taylor.lean", + "sha256": "b3a5c2bbb8374b845624f13fc66b7cb8ad0bf0ca987c6b923631f3ea275febd2" + }, + { + "bytes": 20215, + "imports": [ + "JackalIv.Gaussian", + "Mathlib.Analysis.SpecialFunctions.Trigonometric.Bounds", + "Mathlib.Analysis.SpecialFunctions.Trigonometric.Arctan", + "Mathlib.Analysis.Real.Pi.Bounds" + ], + "module": "JackalIv.Transcend", + "path": "proofs/lean/JackalIv/Transcend.lean", + "sha256": "2fce308fdf161d6fc1edb3d41cb0148e6d8544ab0954a17a7c29ae915a7f1569" + }, + { + "bytes": 24529, + "imports": [ + "JackalIv.Model", + "JackalIv.Pad" + ], + "module": "JackalIv.Trig", + "path": "proofs/lean/JackalIv/Trig.lean", + "sha256": "c65e6db19679c0081d833d4a15cf9d46b4f73e395ed7564505fc0c2e586078d4" + } + ], + "local_construct_policy": { + "allowed_exact_source_lines": [ + { + "construct": "implemented_by", + "path": "proofs/lean/JackalIv/Correspondence.lean", + "source_lines": [ + "@[implemented_by Dump.parseSexpImpl]", + "@[implemented_by Dump.lowerSexpImpl]" + ] + } + ], + "forbidden_by_default": [ + "admit", + "axiom_declaration", + "extern", + "implemented_by", + "native_decide", + "partial", + "sorry", + "unsafe" + ] + }, + "root_modules": [ + "JackalIv.CertCheckMain" + ] + }, + "toolchain": { + "configuration_files": [ + { + "path": "proofs/lean/lakefile.toml", + "sha256": "21eef36ea0d9a665622b171dcf1f96460aa250ef214314d766112e01dadf1eaf" + }, + { + "path": "proofs/lean/lake-manifest.json", + "sha256": "f521808691ba1ab175c5cdeec098a76586d345fea93370a38c2d2b73645f69d4" + }, + { + "path": "proofs/lean/lean-toolchain", + "sha256": "2773c517aa90b66ea8a2c52bddddf84393157797f8341be0df45294fff7fd32e" + } + ], + "lake_version": "Lake version 5.0.0-src+8c9756b (Lean version 4.32.0)", + "lean": { + "build": "Release", + "commit": "8c9756b28d64dab099da31a4c09229a9e6a2ef35", + "version": "4.32.0" + }, + "lean_toolchain": "leanprover/lean4:v4.32.0", + "manifest_packages": [ + { + "config_file": "lakefile.toml", + "inherited": true, + "input_revision": "v4.32.0", + "manifest_file": "lake-manifest.json", + "name": "Cli", + "revision": "88679d088c9720c27ebdf2ba4dafe17341747f94", + "scope": "leanprover", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover/lean4-cli" + }, + { + "config_file": "lakefile.toml", + "inherited": true, + "input_revision": "main", + "manifest_file": "lake-manifest.json", + "name": "LeanSearchClient", + "revision": "c5d5b8fe6e5158def25cd28eb94e4141ad97c843", + "scope": "leanprover-community", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover-community/LeanSearchClient" + }, + { + "config_file": "lakefile.toml", + "inherited": true, + "input_revision": "master", + "manifest_file": "lake-manifest.json", + "name": "Qq", + "revision": "38d591e778f100aec9762bb582f9c7f55f50e9dc", + "scope": "leanprover-community", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover-community/quote4" + }, + { + "config_file": "lakefile.toml", + "inherited": true, + "input_revision": "master", + "manifest_file": "lake-manifest.json", + "name": "aesop", + "revision": "a7dbf0c63b694e47f425f3dcddbc0e178bb432d3", + "scope": "leanprover-community", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover-community/aesop" + }, + { + "config_file": "lakefile.toml", + "inherited": true, + "input_revision": "main", + "manifest_file": "lake-manifest.json", + "name": "batteries", + "revision": "023ce7d62a0531e22a5331e20b587817a80d49ff", + "scope": "leanprover-community", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover-community/batteries" + }, + { + "config_file": "lakefile.toml", + "inherited": true, + "input_revision": "main", + "manifest_file": "lake-manifest.json", + "name": "importGraph", + "revision": "7e9612bf0b9ee66db3cb5b9988a35afc706f5a12", + "scope": "leanprover-community", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover-community/import-graph" + }, + { + "config_file": "lakefile.lean", + "inherited": false, + "input_revision": "v4.32.0", + "manifest_file": "lake-manifest.json", + "name": "mathlib", + "revision": "81a5d257c8e410db227a6665ed08f64fea08e997", + "scope": "", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover-community/mathlib4" + }, + { + "config_file": "lakefile.toml", + "inherited": true, + "input_revision": "main", + "manifest_file": "lake-manifest.json", + "name": "plausible", + "revision": "e12c1910fe855cbfc38803cd4e55543906d5fa62", + "scope": "leanprover-community", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover-community/plausible" + }, + { + "config_file": "lakefile.lean", + "inherited": true, + "input_revision": "main", + "manifest_file": "lake-manifest.json", + "name": "proofwidgets", + "revision": "6e311e2a844da9b2cc3971187df2fe0066947b93", + "scope": "leanprover-community", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover-community/ProofWidgets4" + } + ], + "mathlib_commit": "81a5d257c8e410db227a6665ed08f64fea08e997", + "package_checkout_policy": "Every git package checkout is clean and its HEAD equals its full lake-manifest revision during generation and verification." + } +} diff --git a/release/tools/bake_linux_compat_pins.py b/release/tools/bake_linux_compat_pins.py new file mode 100644 index 0000000..13b4ae7 --- /dev/null +++ b/release/tools/bake_linux_compat_pins.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +"""Bind a packaged formal_receipt.py's current-epoch compat pins to the flat +Linux proof-identity bytes the package ships (range + int-cert).""" +import sys, pathlib + +fr = pathlib.Path(sys.argv[1]); range_sha, int_sha = sys.argv[2], sys.argv[3] +s = fr.read_text() +range_call = ( + ' "file_sha256": _host_current_identity_sha(\n' + ' "range_proof_identity_v172.json",\n' + ' "84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c",\n' + ' ),' +) +int_call = ( + ' "file_sha256": _host_current_identity_sha(\n' + ' "int_cert_proof_identity_v172.json",\n' + ' "a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf",\n' + ' ),' +) +if range_call not in s or int_call not in s: + sys.exit("BAKE_REFUSED detail=host-aware compat pin calls not found in packaged formal_receipt.py") +s = s.replace(range_call, f' "file_sha256": "{range_sha}",', 1) +s = s.replace(int_call, f' "file_sha256": "{int_sha}",', 1) +fr.write_text(s) +print(f"BAKED range={range_sha[:12]} int={int_sha[:12]}") diff --git a/release/tools/repin_linux.py b/release/tools/repin_linux.py new file mode 100755 index 0000000..23b15db --- /dev/null +++ b/release/tools/repin_linux.py @@ -0,0 +1,162 @@ +#!/usr/bin/env python3 +"""Derive a per-host JACKAL release manifest for a locally built runtime. + +The committed ``release/MANIFEST.sha256`` pins the official macOS arm64 release +bytes. A source build on another host produces byte-different *compiled* +artifacts — the Anubis-built ``jackal-native`` and the three Lean-proved checker +binaries — while every producer (``.py``), identity (``.json``) and the Anubis +source (``.anb``) stay byte-identical across hosts. + +This tool writes ``release/MANIFEST..sha256`` as the committed manifest +with exactly those compiled-binary rows re-hashed from live bytes and the +``compiler_pin`` row rebound to the local Anubis compiler. Every other row is +copied verbatim, so the host manifest asserts the same release identity except +for the platform-specific compiled bytes. It never mutates the macOS manifest. + +Usage: + JACKAL_ANUBIS_COMPILER_PATH=/path/to/anubis python3 release/tools/repin_linux.py --plan + ... python3 release/tools/repin_linux.py --write +""" +from __future__ import annotations + +import argparse +import hashlib +import os +import platform +import sys +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[2] +MACOS_MANIFEST = ROOT / "release/MANIFEST.sha256" + +# row-label -> repo-relative path of the compiled binary it pins +BINARY_ROWS = { + "evaluator": "jackal-native", + "checker": "proofs/lean/.lake/build/bin/jackal_cert_check", + "gaussian-checker": "proofs/lean/.lake/build/bin/jackal_gaussian_check", + "int-cert-checker": "proofs/lean/.lake/build/bin/jackal_int_cert_check", +} + +# identity-row-label -> (base evidence filename without extension, digest-row-label) +# When a host-suffixed evidence file exists, the identity row's path+sha and the +# paired digest row are rebound to it. The macOS evidence files stay in place. +PROOF_IDENTITY_ROWS = { + "range-proof-identity": ("range_proof_identity_v172", "range-proof-digest"), + "gaussian-proof-identity": ("gaussian_proof_identity", "gaussian-proof-digest"), + "int-cert-proof-identity": ("int_cert_proof_identity_v172", "int-cert-proof-digest"), +} +EVIDENCE_DIR = "release/evidence" + + +def sha256(path: Path) -> str: + digest = hashlib.sha256() + with path.open("rb") as handle: + for chunk in iter(lambda: handle.read(1 << 20), b""): + digest.update(chunk) + return digest.hexdigest() + + +def host_tag() -> str: + system = platform.system().lower() + machine = platform.machine().lower() + return f"{system}-{machine}" + + +def compiler_path() -> Path: + configured = os.environ.get("JACKAL_ANUBIS_COMPILER_PATH") + if not configured: + sys.exit("REPIN_LINUX_REFUSED detail=set JACKAL_ANUBIS_COMPILER_PATH to the anubis compiler") + path = Path(configured) + if path.is_symlink(): + sys.exit(f"REPIN_LINUX_REFUSED detail=compiler authority must not be a symlink: {path}") + if not path.is_file(): + sys.exit(f"REPIN_LINUX_REFUSED detail=compiler not found: {path}") + return path + + +def build_manifest() -> str: + macos_rows = MACOS_MANIFEST.read_text(encoding="utf-8").splitlines() + comp = compiler_path() + comp_sha = sha256(comp) + tag = host_tag() + + def host_evidence(base: str) -> Path | None: + candidate = ROOT / EVIDENCE_DIR / f"{base}.{tag}.json" + return candidate if candidate.is_file() else None + + # Pre-scan which digest rows a host evidence file will override, so the + # paired digest row is rewritten in place from the same file. + digest_overrides: dict[str, str] = {} + for id_label, (base, digest_label) in PROOF_IDENTITY_ROWS.items(): + ev = host_evidence(base) + if ev is None: + continue + import json as _json + internal = _json.loads(ev.read_text(encoding="utf-8")).get("identity_digest_sha256") + if not isinstance(internal, str) or len(internal) != 64: + sys.exit(f"REPIN_LINUX_REFUSED detail=host evidence lacks identity_digest_sha256: {ev}") + digest_overrides[digest_label] = internal + + out: list[str] = [] + seen_binary: set[str] = set() + for line in macos_rows: + if not line or line.startswith("#"): + out.append(line) + continue + label = line.split()[0] + if label in BINARY_ROWS: + target = ROOT / BINARY_ROWS[label] + if not target.is_file(): + sys.exit(f"REPIN_LINUX_REFUSED detail=missing built artifact: {target}") + name = line.split()[1] + out.append(f"{label} {name} {sha256(target)}") + seen_binary.add(label) + elif label == "compiler_pin": + out.append(f"compiler_pin anubis-{comp_sha[:12]} {comp_sha}") + elif label in PROOF_IDENTITY_ROWS: + base, _ = PROOF_IDENTITY_ROWS[label] + ev = host_evidence(base) + if ev is None: + out.append(line) # keep macOS evidence row verbatim + else: + rel = ev.relative_to(ROOT) + out.append(f"{label} {rel} {sha256(ev)}") + elif label in digest_overrides: + out.append(f"{label} {digest_overrides[label]}") + else: + out.append(line) + missing = set(BINARY_ROWS) - seen_binary + if missing: + sys.exit(f"REPIN_LINUX_REFUSED detail=manifest lacked binary rows: {sorted(missing)}") + return "\n".join(out) + "\n" + + +def main(argv: list[str] | None = None) -> int: + parser = argparse.ArgumentParser(description="Derive a per-host JACKAL release manifest") + modes = parser.add_mutually_exclusive_group() + modes.add_argument("--plan", action="store_true", help="print without writing (default)") + modes.add_argument("--check", action="store_true", help="compare with the on-disk host manifest") + modes.add_argument("--write", action="store_true", help="write release/MANIFEST..sha256") + args = parser.parse_args(argv) + + text = build_manifest() + target = ROOT / f"release/MANIFEST.{host_tag()}.sha256" + + if args.write: + tmp = target.with_suffix(target.suffix + ".tmp") + tmp.write_text(text, encoding="utf-8") + os.replace(tmp, target) + print(f"REPIN_LINUX_WROTE path={target.relative_to(ROOT)} sha256={hashlib.sha256(text.encode()).hexdigest()}") + elif args.check: + if not target.is_file(): + sys.exit(f"REPIN_LINUX_REFUSED detail=host manifest absent: {target}") + if target.read_text(encoding="utf-8") != text: + sys.exit(f"REPIN_LINUX_MISMATCH path={target.relative_to(ROOT)}") + print(f"REPIN_LINUX_MATCH path={target.relative_to(ROOT)}") + else: + sys.stdout.write(text) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tests/codex_plugin/live_acceptance.py b/tests/codex_plugin/live_acceptance.py index 23dd763..b071f0a 100644 --- a/tests/codex_plugin/live_acceptance.py +++ b/tests/codex_plugin/live_acceptance.py @@ -21,6 +21,7 @@ import selectors import secrets import signal +import platform import stat import subprocess import sys @@ -1921,7 +1922,7 @@ def verify_runtime(runtime_root: Path | str) -> None: def dry_run_document( *, codex_binary: Path | str, repository_root: Path | str, ) -> dict[str, Any]: - placeholder = Path("/private/tmp/jackel-codex-isolated-CODEX_HOME") + placeholder = _fixed_temp_root() / "jackel-codex-isolated-CODEX_HOME" plan = build_codex_install_plan( codex_home=placeholder, repository_root=repository_root, codex_binary=codex_binary, @@ -1946,8 +1947,18 @@ def dry_run_document( } +def _fixed_temp_root() -> Path: + """The physical system temp directory for this host. + + macOS exposes it as /private/tmp with /tmp as a symlink; on Linux /tmp is + already the physical directory. The path stays fixed per platform rather + than being read from the environment. + """ + return Path("/private/tmp") if platform.system() == "Darwin" else Path("/tmp") + + def _isolated_codex_temp_parent() -> Path: - parent = Path("/private/tmp") + parent = _fixed_temp_root() try: info = parent.lstat() resolved = parent.resolve(strict=True) diff --git a/tests/codex_plugin/test_live_acceptance.py b/tests/codex_plugin/test_live_acceptance.py index 809d587..4ac043b 100644 --- a/tests/codex_plugin/test_live_acceptance.py +++ b/tests/codex_plugin/test_live_acceptance.py @@ -582,8 +582,8 @@ def test_installed_mcp_config_rejects_relative_command_or_escaping_cwd(self): base = { "mcpServers": { "jackel": { - "command": "/bin/zsh", - "args": ["./scripts/launch_mcp.zsh"], + "command": "/bin/sh", + "args": ["./scripts/launch_mcp.sh"], "cwd": ".", "env_vars": ["JACKAL_HOME"], "tool_timeout_sec": 3700, @@ -826,8 +826,8 @@ def registry_bytes(self, installed): "disabled_reason": None, "transport": { "type": "stdio", - "command": "/bin/zsh", - "args": ["./scripts/launch_mcp.zsh"], + "command": "/bin/sh", + "args": ["./scripts/launch_mcp.sh"], "env": None, "env_vars": ["JACKAL_HOME"], "cwd": str(installed / "."), @@ -1837,7 +1837,7 @@ def test_live_mcp_and_direct_comparator_share_one_sanitized_environment(self): direct = mock.Mock(return_value={"status": "exact"}) temporary = mock.Mock() temporary.__enter__ = mock.Mock( - return_value="/private/tmp/jackel-codex-live-fixture" + return_value=str(live._fixed_temp_root() / "jackel-codex-live-fixture") ) temporary.__exit__ = mock.Mock(return_value=False) @@ -1869,7 +1869,7 @@ def acceptance(*, client, runtime_document, direct_call): sanitizer.assert_called_once() temporary_directory.assert_called_once_with( - prefix="jackel-codex-live-", dir=Path("/private/tmp") + prefix="jackel-codex-live-", dir=live._fixed_temp_root() ) self.assertEqual(sanitizer.call_args.args[0], runtime) mcp_client.assert_called_once_with(installed, environment) diff --git a/tests/codex_plugin/test_mcp_adapter.py b/tests/codex_plugin/test_mcp_adapter.py index 25d443a..abdbfc5 100644 --- a/tests/codex_plugin/test_mcp_adapter.py +++ b/tests/codex_plugin/test_mcp_adapter.py @@ -1885,6 +1885,14 @@ def setUp(self): SHA256SUMS_SHA256="f1f794ccd2ba331e6188840cfc089180cdcd744f23c1880f8364a81b230c1a28", SELFTEST_TIMEOUT=30.0, SELFTEST_OUTPUT_LIMIT=65536, + effective_release_pins=lambda *a, **k: { + "epoch": "v1.7.0", + "asset": "jackal-v1.7.0-macos-arm64.tar.gz", + "package_size": 118862060, + "package_sha256": + "21c7ede586f30a58772f321f7dbb36ab66213e199785489f99133710ac56096e", + "package_directory": "jackal-v1.7.0-macos-arm64", + }, default_locator_path=lambda: self.root / "locator.json", validate_host=mock.Mock(return_value=None), runtime_subprocess_environment=mock.Mock( @@ -2165,6 +2173,11 @@ def test_calls_remain_bound_to_snapshot_after_original_launcher_backend_and_aba_ EPOCH="v1.7.0", ASSET="fixture.tar.gz", PACKAGE_SIZE=123, PACKAGE_SHA256="c" * 64, SHA256SUMS_SHA256=hashlib.sha256(checksums).hexdigest(), + effective_release_pins=lambda *a, **k: { + "epoch": "v1.7.0", "asset": "fixture.tar.gz", + "package_size": 123, "package_sha256": "c" * 64, + "package_directory": "fixture", + }, SELFTEST_TIMEOUT=2.0, SELFTEST_OUTPUT_LIMIT=65536, validate_host=mock.Mock(return_value=None), validate_runtime=real_provisioner.validate_runtime, diff --git a/tests/codex_plugin/test_plugin_metadata.py b/tests/codex_plugin/test_plugin_metadata.py index 5a316bd..569ef2a 100644 --- a/tests/codex_plugin/test_plugin_metadata.py +++ b/tests/codex_plugin/test_plugin_metadata.py @@ -16,7 +16,8 @@ SKILL_PATH = PLUGIN_ROOT / "skills" / "jackel" / "SKILL.md" IDENTITY_PATH = PLUGIN_ROOT / "PLUGIN_IDENTITY.sha256" README_PATH = PLUGIN_ROOT / "README.md" -LAUNCHER_PATH = PLUGIN_ROOT / "scripts" / "launch_mcp.zsh" +LAUNCHER_PATH = PLUGIN_ROOT / "scripts" / "launch_mcp.sh" +ZSH_LAUNCHER_PATH = PLUGIN_ROOT / "scripts" / "launch_mcp.zsh" SERVER_PATH = PLUGIN_ROOT / "mcp" / "server.py" WORKFLOW_PATH = REPOSITORY_ROOT / ".github" / "workflows" / "jackal-codex-plugin.yml" DESIGN_PATH = ( @@ -281,8 +282,8 @@ def test_jackel_plugin_metadata_contract(self): { "mcpServers": { "jackel": { - "command": "/bin/zsh", - "args": ["./scripts/launch_mcp.zsh"], + "command": "/bin/sh", + "args": ["./scripts/launch_mcp.sh"], "cwd": ".", "env_vars": ["JACKAL_HOME"], "tool_timeout_sec": 3700, @@ -317,9 +318,10 @@ def test_jackel_plugin_metadata_contract(self): "error estimate is not a bound", "Source-to-native refinement remains open and unclaimed", "Run a weaker lane only when the caller explicitly requests one", - "Apple Silicon macOS only", - "Do not bypass the Darwin/arm64 host guard", - "Python >=3.10 at `/opt/homebrew/bin/python3`", + "Darwin/arm64 and Linux/aarch64", + "Do not bypass the host guard", + "no published release asset for host linux-aarch64", + "Python >=3.10", "brew install python", ): self.assertIn(phrase, skill) @@ -339,6 +341,7 @@ def test_every_shipped_plugin_path_exists_and_is_identity_governed(self): manifest["mcpServers"].removeprefix("./"), "mcp/server.py", "scripts/provision_runtime.py", + "scripts/launch_mcp.sh", "scripts/launch_mcp.zsh", "scripts/verify_plugin.py", "skills/jackel/SKILL.md", @@ -350,7 +353,7 @@ def test_every_shipped_plugin_path_exists_and_is_identity_governed(self): self.assertEqual(identity_paths, referenced) for relative in referenced: self.assertTrue((PLUGIN_ROOT / relative).is_file(), relative) - self.assertEqual(mcp["args"], ["./scripts/launch_mcp.zsh"]) + self.assertEqual(mcp["args"], ["./scripts/launch_mcp.sh"]) self.assertFalse( any( path.name.endswith(".tar.gz") or path.name.startswith("jackal-v") @@ -364,7 +367,7 @@ def test_readme_documents_release_install_discovery_and_boundaries(self): "41-tool", "v1.7.3 release", "release/capability_inventory_v1.json", - "/bin/zsh scripts/launch_mcp.zsh provision", + "/bin/sh scripts/launch_mcp.sh provision", "codex mcp list", "jackal_claim", "jackal_verify_receipt", @@ -378,7 +381,7 @@ def test_readme_documents_release_install_discovery_and_boundaries(self): def test_launcher_uses_only_explicit_absolute_python_candidates_and_exact_flags(self): mcp = self.load_json(MCP_PATH)["mcpServers"]["jackel"] - self.assertEqual(mcp["command"], "/bin/zsh") + self.assertEqual(mcp["command"], "/bin/sh") source = LAUNCHER_PATH.read_text(encoding="utf-8") self.assertIn("/opt/homebrew/bin/python3", source) self.assertIn("/usr/local/bin/python3", source) @@ -392,7 +395,7 @@ def test_launcher_uses_only_explicit_absolute_python_candidates_and_exact_flags( '"WEXITED"', '"WNOHANG"', '"WNOWAIT"', '"CLD_EXITED"', '"CLD_KILLED"', '"CLD_DUMPED"', '"killpg"', '"set_blocking"', '"socketpair"', "ctypes.CDLL", - '"renameatx_np"', "selectors.DefaultSelector", + '"renameatx_np"', '"renameat2"', "selectors.DefaultSelector", "signal.setitimer", "signal.getitimer", "signal.ITIMER_REAL", "signal.SIGALRM", "tarfile.open", "urllib.request.urlopen", "is_absolute", @@ -400,15 +403,45 @@ def test_launcher_uses_only_explicit_absolute_python_candidates_and_exact_flags( self.assertIn(required_probe, source) self.assertIn('exec "$python" -I -S -B', source) - def _run_rewritten_launcher(self, candidate_sources, *launcher_arguments): - source = LAUNCHER_PATH.read_text(encoding="utf-8") - marker = textwrap.dedent("""\ - PYTHON_CANDIDATES=( - /opt/homebrew/bin/python3 - /usr/local/bin/python3 - /usr/bin/python3 - ) - """) + REFUSING_CANDIDATE = ( + 'printf \'%s\\n\' "refused:$1:$2:$3:$4" >> "$LAUNCHER_FIXTURE_LOG"\nexit 17\n' + ) + ACCEPTING_CANDIDATE = textwrap.dedent("""\ + if [ "$4" = "-c" ]; then + printf '%s\\n' "accepted:$1:$2:$3:$4" >> "$LAUNCHER_FIXTURE_LOG" + exit 0 + fi + printf '%s\\n' "accepted:$*" >> "$LAUNCHER_FIXTURE_LOG" + exit 23 + """) + + SH_CANDIDATE_MARKER = ( + 'PYTHON_CANDIDATES="/opt/homebrew/bin/python3\n' + '/usr/local/bin/python3\n' + '/usr/bin/python3"\n' + ) + ZSH_CANDIDATE_MARKER = textwrap.dedent("""\ + PYTHON_CANDIDATES=( + /opt/homebrew/bin/python3 + /usr/local/bin/python3 + /usr/bin/python3 + ) + """) + + def _run_rewritten_launcher( + self, candidate_sources, *launcher_arguments, shell="/bin/sh", + ): + """Run a launcher whose interpreter candidates are swapped for fixtures.""" + if shell.endswith("zsh"): + source = ZSH_LAUNCHER_PATH.read_text(encoding="utf-8") + marker = self.ZSH_CANDIDATE_MARKER + launcher_name = "launch_mcp.zsh" + shebang = "#!/bin/zsh\n" + else: + source = LAUNCHER_PATH.read_text(encoding="utf-8") + marker = self.SH_CANDIDATE_MARKER + launcher_name = "launch_mcp.sh" + shebang = "#!/bin/sh\n" with tempfile.TemporaryDirectory() as directory: root = Path(directory) / "plugin" scripts = root / "scripts" @@ -420,18 +453,23 @@ def _run_rewritten_launcher(self, candidate_sources, *launcher_arguments): for index, body in enumerate(candidate_sources): candidate = root / f"candidate-{index}" candidate.write_text( - "#!/bin/zsh\n" - f"export LAUNCHER_FIXTURE_LOG={str(log)!r}\n" + shebang + + f"export LAUNCHER_FIXTURE_LOG={str(log)!r}\n" + body, encoding="utf-8", ) candidate.chmod(0o755) candidates.append(candidate) - replacement = "PYTHON_CANDIDATES=(\n" + "".join( - f" {candidate}\n" for candidate in candidates - ) + ")\n" + if marker is self.ZSH_CANDIDATE_MARKER: + replacement = "PYTHON_CANDIDATES=(\n" + "".join( + f" {candidate}\n" for candidate in candidates + ) + ")\n" + else: + replacement = 'PYTHON_CANDIDATES="' + "\n".join( + str(candidate) for candidate in candidates + ) + '"\n' self.assertIn(marker, source) - (scripts / "launch_mcp.zsh").write_text( + (scripts / launcher_name).write_text( source.replace(marker, replacement), encoding="utf-8", ) (mcp / "server.py").write_text("raise SystemExit(99)\n", encoding="utf-8") @@ -439,23 +477,16 @@ def _run_rewritten_launcher(self, candidate_sources, *launcher_arguments): "raise SystemExit(98)\n", encoding="utf-8", ) completed = subprocess.run( - ["/bin/zsh", str(scripts / "launch_mcp.zsh"), *launcher_arguments], + [shell, str(scripts / launcher_name), *launcher_arguments], cwd=root, capture_output=True, text=True, check=False, - env={"PATH": "/definitely/not/a/python/path"}, timeout=2, + env={"PATH": "/definitely/not/a/python/path"}, timeout=5, ) calls = log.read_text(encoding="utf-8").splitlines() if log.exists() else [] return completed, calls, root def test_launcher_simulates_capability_fallback_and_provision_mode(self): - refusing = 'print -r -- "refused:$1:$2:$3:$4" >> "$LAUNCHER_FIXTURE_LOG"\nexit 17\n' - accepting = textwrap.dedent("""\ - if [[ "$4" == "-c" ]]; then - print -r -- "accepted:$1:$2:$3:$4" >> "$LAUNCHER_FIXTURE_LOG" - exit 0 - fi - print -r -- "accepted:$*" >> "$LAUNCHER_FIXTURE_LOG" - exit 23 - """) + refusing = self.REFUSING_CANDIDATE + accepting = self.ACCEPTING_CANDIDATE completed, calls, root = self._run_rewritten_launcher( [refusing, accepting], "provision", "--check", ) @@ -469,19 +500,61 @@ def test_launcher_simulates_capability_fallback_and_provision_mode(self): ) self.assertFalse(any(root.rglob("*.pyc"))) + LAUNCHER_REFUSAL = ( + "jackal_mcp=refused reason=no-compatible-python requirement='Python >=3.10 " + "with an atomic no-replace rename (Darwin renameatx_np / Linux renameat2) " + "at one of the fixed candidate paths' recovery='macOS: brew install python " + "| Linux: install a distribution python3 >=3.10 at /usr/bin/python3'\n" + ) + def test_launcher_refuses_once_with_126_when_no_candidate_passes(self): - refusing = 'print -r -- "refused:$1:$2:$3:$4" >> "$LAUNCHER_FIXTURE_LOG"\nexit 17\n' completed, calls, unused_root = self._run_rewritten_launcher( - [refusing, refusing], + [self.REFUSING_CANDIDATE, self.REFUSING_CANDIDATE], ) self.assertEqual(completed.returncode, 126) self.assertEqual(completed.stdout, "") - self.assertEqual( - completed.stderr, - "jackal_mcp=refused reason=no-compatible-python requirement='Python >=3.10 at /opt/homebrew/bin/python3' recovery='brew install python'\n", + self.assertEqual(completed.stderr, self.LAUNCHER_REFUSAL) + self.assertEqual(len(calls), 2) + + def test_launcher_resolves_its_root_without_any_external_command(self): + """The caller PATH is untrusted, so no PATH-resolved binary may be used.""" + completed, calls, unused_root = self._run_rewritten_launcher( + [self.REFUSING_CANDIDATE], + ) + self.assertEqual(completed.returncode, 126) + self.assertEqual(completed.stderr, self.LAUNCHER_REFUSAL) + for external in ("dirname", "basename", "readlink", "realpath", "not found"): + self.assertNotIn(external, completed.stderr) + self.assertEqual(len(calls), 1) + + @unittest.skipUnless(Path("/bin/zsh").exists(), "zsh launcher requires /bin/zsh") + def test_zsh_launcher_matches_the_portable_launcher_behaviour(self): + completed, calls, unused_root = self._run_rewritten_launcher( + [self.REFUSING_CANDIDATE, self.REFUSING_CANDIDATE], shell="/bin/zsh", ) + self.assertEqual(completed.returncode, 126) + self.assertEqual(completed.stderr, self.LAUNCHER_REFUSAL) self.assertEqual(len(calls), 2) + def test_both_launchers_carry_a_byte_identical_capability_probe(self): + def probe_of(path): + source = path.read_text(encoding="utf-8") + start = source.index("probe='") + len("probe='") + return source[start:source.index("'", start + 1)] + + self.assertEqual(probe_of(LAUNCHER_PATH), probe_of(ZSH_LAUNCHER_PATH)) + + def test_probe_requires_the_atomic_rename_symbol_for_this_host_only(self): + """Neither symbol may be demanded unconditionally on the wrong host.""" + source = LAUNCHER_PATH.read_text(encoding="utf-8") + self.assertIn( + '{"Darwin": "renameatx_np", "Linux": "renameat2"}.get(platform.system())', + source, + ) + self.assertIn("assert atomic_rename is not None", source) + self.assertIn("assert callable(getattr(libc, atomic_rename, None))", source) + self.assertNotIn('getattr(libc, "renameatx_np", None)', source) + def test_hosted_macos_workflow_mechanically_runs_all_repo_local_plugin_gates(self): self.assertTrue(WORKFLOW_PATH.is_file(), "hosted JACKAL plugin workflow is missing") source = WORKFLOW_PATH.read_text(encoding="utf-8") diff --git a/tests/codex_plugin/test_runtime_provisioner.py b/tests/codex_plugin/test_runtime_provisioner.py index c40150d..4523c97 100644 --- a/tests/codex_plugin/test_runtime_provisioner.py +++ b/tests/codex_plugin/test_runtime_provisioner.py @@ -1555,9 +1555,24 @@ def test_pinned_constants_and_default_paths(self): "a78fc05e2ebd56f31263d54ccdbf7fcc2ff92d270758720c3e235d5a3121568a", ) self.assertEqual( - provisioner.default_runtime_target(Path("/Users/tester")), + provisioner.default_runtime_target(Path("/Users/tester"), "Darwin"), Path("/Users/tester/Library/Application Support/JACKAL/runtimes/v1.7.3"), ) + self.assertEqual( + provisioner.default_locator_path(Path("/Users/tester"), "Darwin"), + Path( + "/Users/tester/Library/Application Support/JACKAL" + "/codex-plugin/runtime.json" + ), + ) + self.assertEqual( + provisioner.default_runtime_target(Path("/home/tester"), "Linux"), + Path("/home/tester/.local/share/JACKAL/runtimes/v1.7.3"), + ) + self.assertEqual( + provisioner.default_locator_path(Path("/home/tester"), "Linux"), + Path("/home/tester/.local/share/JACKAL/codex-plugin/runtime.json"), + ) def test_cli_rejects_relative_tarball_with_one_bounded_line_and_no_traceback(self): stderr = io.StringIO() @@ -1580,5 +1595,154 @@ def test_cli_parse_failure_is_one_bounded_line_without_system_exit(self): self.assertNotIn("Traceback", lines[0]) +class HostPortabilityTests(unittest.TestCase): + """The host guard admits exactly the hosts whose primitives are implemented.""" + + def test_resolve_host_admits_both_supported_hosts(self): + self.assertEqual(provisioner.resolve_host("Darwin", "arm64"), "macos-arm64") + self.assertEqual(provisioner.resolve_host("Linux", "aarch64"), "linux-aarch64") + + def test_resolve_host_refuses_near_misses_without_guessing(self): + for system, machine in ( + ("Linux", "x86_64"), + ("Darwin", "x86_64"), + ("Linux", "arm64"), + ("Darwin", "aarch64"), + ("Windows", "AMD64"), + ("FreeBSD", "aarch64"), + ): + with self.subTest(system=system, machine=machine): + with self.assertRaises(provisioner.ProvisionError) as caught: + provisioner.resolve_host(system, machine) + detail = str(caught.exception) + self.assertIn(f"{system}/{machine}", detail) + self.assertIn("unsupported host", detail) + + def test_release_pin_resolves_for_hosts_with_a_pin(self): + self.assertEqual( + provisioner.release_pin("macos-arm64")["asset"], provisioner.ASSET + ) + # linux-aarch64 carries a locally built runtime pin + self.assertEqual( + provisioner.release_pin("linux-aarch64")["package_directory"], + "jackal-v1.7.3-linux-aarch64", + ) + + def test_release_pin_refuses_for_a_host_with_no_published_asset(self): + """A supported host with a None pin refuses rather than guessing bytes.""" + with mock.patch.dict(provisioner.RELEASE_PINS, {"linux-aarch64": None}): + with self.assertRaises(provisioner.ProvisionError) as caught: + provisioner.release_pin("linux-aarch64") + self.assertIn("no published release asset", str(caught.exception)) + + def test_default_pin_provisioning_refuses_when_the_host_pin_is_absent(self): + """A supported host with no pin is not a published runtime.""" + with mock.patch.dict(provisioner.RELEASE_PINS, {"linux-aarch64": None}): + with self.assertRaises(provisioner.ProvisionError) as caught: + provisioner.provision( + check_only=True, system="Linux", machine="aarch64", + ) + self.assertIn("no published release asset", str(caught.exception)) + + def test_caller_supplied_pins_bypass_the_release_table_not_the_host_guard(self): + with self.assertRaises(provisioner.ProvisionError) as caught: + provisioner.provision( + check_only=True, + system="Linux", + machine="riscv64", + expected_size=1, + expected_sha256="0" * 64, + ) + self.assertIn("unsupported host", str(caught.exception)) + + def test_rename_primitive_is_selected_per_host_and_refuses_elsewhere(self): + self.assertIs( + provisioner.rename_exclusive_for_host("Darwin"), + provisioner._renameatx_np_exclusive, + ) + self.assertIs( + provisioner.rename_exclusive_for_host("Linux"), + provisioner._renameat2_noreplace, + ) + with self.assertRaises(provisioner.ProvisionError) as caught: + provisioner.rename_exclusive_for_host("Windows") + self.assertIn("unsupported on Windows", str(caught.exception)) + + def test_each_primitive_refuses_to_run_on_the_wrong_host(self): + wrong = ( + (provisioner._renameatx_np_exclusive, "Linux"), + (provisioner._renameat2_noreplace, "Darwin"), + ) + for operation, foreign_system in wrong: + with self.subTest(operation=operation.__name__): + with mock.patch.object( + provisioner.platform, "system", return_value=foreign_system + ): + with self.assertRaises(provisioner.ProvisionError): + operation(-1, "a", -1, "b") + + def test_supported_hosts_and_release_pins_describe_the_same_hosts(self): + self.assertEqual( + set(provisioner.SUPPORTED_HOSTS.values()), + set(provisioner.RELEASE_PINS), + ) + + +@unittest.skipUnless(sys.platform.startswith("linux"), "Linux rename primitive") +class LinuxRenameNoReplaceTests(unittest.TestCase): + """renameat2(RENAME_NOREPLACE) must match renameatx_np(RENAME_EXCL) semantics.""" + + def _parents(self, root, source_name, target_name, *, payload=b"runtime"): + (root / source_name).write_bytes(payload) + return os.open(root, os.O_RDONLY | os.O_DIRECTORY) + + def test_rename_moves_into_a_free_name(self): + with tempfile.TemporaryDirectory() as directory: + root = Path(directory) + fd = self._parents(root, "src", "dst") + try: + provisioner._renameat2_noreplace(fd, "src", fd, "dst") + finally: + os.close(fd) + self.assertFalse((root / "src").exists()) + self.assertEqual((root / "dst").read_bytes(), b"runtime") + + def test_rename_refuses_to_clobber_an_existing_target(self): + with tempfile.TemporaryDirectory() as directory: + root = Path(directory) + (root / "dst").write_bytes(b"installed") + fd = self._parents(root, "src", "dst", payload=b"attacker") + try: + with self.assertRaises(FileExistsError) as caught: + provisioner._renameat2_noreplace(fd, "src", fd, "dst") + finally: + os.close(fd) + self.assertEqual(caught.exception.errno, errno.EEXIST) + self.assertEqual((root / "dst").read_bytes(), b"installed") + self.assertEqual((root / "src").read_bytes(), b"attacker") + + def test_missing_source_reports_enoent_not_a_silent_success(self): + with tempfile.TemporaryDirectory() as directory: + fd = os.open(directory, os.O_RDONLY | os.O_DIRECTORY) + try: + with self.assertRaises(OSError) as caught: + provisioner._renameat2_noreplace(fd, "absent", fd, "dst") + finally: + os.close(fd) + self.assertEqual(caught.exception.errno, errno.ENOENT) + self.assertNotIsInstance(caught.exception, FileExistsError) + + def test_install_no_replace_uses_the_host_primitive_end_to_end(self): + with tempfile.TemporaryDirectory() as directory: + root = Path(directory) + (root / "staged").mkdir() + (root / "staged" / "marker").write_bytes(b"x") + provisioner._install_no_replace(root / "staged", root / "final") + self.assertTrue((root / "final" / "marker").is_file()) + (root / "staged").mkdir() + with self.assertRaises(FileExistsError): + provisioner._install_no_replace(root / "staged", root / "final") + + if __name__ == "__main__": unittest.main() diff --git a/tests/release_validate.py b/tests/release_validate.py index 4db96b2..8065603 100644 --- a/tests/release_validate.py +++ b/tests/release_validate.py @@ -25,6 +25,7 @@ import hashlib import json import os +import platform import re import stat import subprocess @@ -428,7 +429,13 @@ def _emit_formal_receipt(path: str | Path, *, receipt: dict, cert_bytes: bytes, if release_epoch == CURRENT_PROOF_RELEASE_EPOCH else "range_proof_identity.json" ) + _host_tag = f"{platform.system().lower()}-{platform.machine().lower()}" + _host_proof_name = proof_name[:-5] + f".{_host_tag}.json" proof_candidates = [ + # A source build on this host carries host-suffixed proof identity that + # binds the locally built checker bytes; fall back to the macOS release + # identity when no host-specific record is present. + os.path.join(_here, "..", "release", "evidence", _host_proof_name), os.path.join(_here, "..", "release", "evidence", proof_name), os.path.join(_here, proof_name), ] diff --git a/tools/capability_drift_gate.py b/tools/capability_drift_gate.py index 70eeb54..cb7c20e 100644 --- a/tools/capability_drift_gate.py +++ b/tools/capability_drift_gate.py @@ -34,6 +34,7 @@ ".mcp.json", "README.md", "mcp/server.py", + "scripts/launch_mcp.sh", "scripts/launch_mcp.zsh", "scripts/provision_runtime.py", "scripts/verify_plugin.py", diff --git a/tools/formal_receipt.py b/tools/formal_receipt.py index 86e55f4..a73e095 100755 --- a/tools/formal_receipt.py +++ b/tools/formal_receipt.py @@ -484,6 +484,26 @@ def write_new_file_atomic(path: str | Path, data: bytes, mode: int = 0o600) -> P "c858e3bfc0ff2809a808170caabbf090077cb54996e76f065dbcd26ffb067d49" ) +def _host_current_identity_sha(base_filename: str, macos_default: str) -> str: + """File sha for the *current*-epoch proof identity on this host. + + A source build on a non-macOS host carries a host-suffixed proof identity + (``.-.json``) binding its locally built checker + bytes. When present it is authoritative for that host; otherwise the pinned + macOS release sha stands. macOS hosts always fall through to the default. + """ + try: + import platform as _platform + tag = f"{_platform.system().lower()}-{_platform.machine().lower()}" + stem = base_filename[:-5] if base_filename.endswith(".json") else base_filename + candidate = Path(__file__).resolve().parent.parent / "release" / "evidence" / f"{stem}.{tag}.json" + if candidate.is_file(): + return hashlib.sha256(candidate.read_bytes()).hexdigest() + except OSError: + pass + return macos_default + + _PROOF_COMPATIBILITY = { ("range", RANGE_PROOF_IDENTITY_V1_SCHEMA, "v1.5.0"): { "file_sha256": "1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67", @@ -492,12 +512,18 @@ def write_new_file_atomic(path: str | Path, data: bytes, mode: int = 0o600) -> P "theorem": "JackalIv.Cert.request_bound_certified_release", }, ("range", RANGE_PROOF_IDENTITY_V2_SCHEMA, CURRENT_PROOF_RELEASE_EPOCH): { - "file_sha256": "84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c", + "file_sha256": _host_current_identity_sha( + "range_proof_identity_v172.json", + "84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c", + ), "mode": "current", "theorem": "JackalIv.Cert.request_bound_certified_release", }, ("int_cert", INT_CERT_PROOF_IDENTITY_V2_SCHEMA, CURRENT_PROOF_RELEASE_EPOCH): { - "file_sha256": "a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf", + "file_sha256": _host_current_identity_sha( + "int_cert_proof_identity_v172.json", + "a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf", + ), "mode": "current", "theorem": "JackalIv.IntCert.int_cert_sound", }, diff --git a/tools/gaussian_release.py b/tools/gaussian_release.py index a1c69ef..3789615 100644 --- a/tools/gaussian_release.py +++ b/tools/gaussian_release.py @@ -5,6 +5,7 @@ import argparse import hashlib import json +import platform import os import re import subprocess @@ -207,7 +208,9 @@ def release(args: argparse.Namespace) -> dict[str, Any]: "integrate", args.expression, canonical_lo, canonical_hi, canonical_tolerance ) here = Path(__file__).resolve().parent + _host_tag = f"{platform.system().lower()}-{platform.machine().lower()}" proof_candidates = [ + here.parent / "release" / "evidence" / f"gaussian_proof_identity.{_host_tag}.json", here.parent / "release" / "evidence" / "gaussian_proof_identity.json", here / "gaussian_proof_identity.json", ] diff --git a/tools/int_cert_release.py b/tools/int_cert_release.py index 338743f..eb13b94 100755 --- a/tools/int_cert_release.py +++ b/tools/int_cert_release.py @@ -16,6 +16,7 @@ import argparse import hashlib import json +import platform import os import re import subprocess @@ -247,7 +248,10 @@ def release(args: argparse.Namespace) -> dict[str, Any]: if args.release_epoch == CURRENT_PROOF_RELEASE_EPOCH else "int_cert_proof_identity.json" ) + _host_tag = f"{platform.system().lower()}-{platform.machine().lower()}" + _host_proof_name = proof_name[:-5] + f".{_host_tag}.json" proof_candidates = [ + here.parent / "release" / "evidence" / _host_proof_name, here.parent / "release" / "evidence" / proof_name, here / proof_name, ] diff --git a/tools/lean_admission_audit.py b/tools/lean_admission_audit.py index 5384e07..937516e 100644 --- a/tools/lean_admission_audit.py +++ b/tools/lean_admission_audit.py @@ -34,20 +34,33 @@ DEFAULT_COMMAND_TIMEOUT_SECONDS = 180.0 MAX_COMMAND_TIMEOUT_SECONDS = 3600.0 + +def _host_tag() -> str: + import platform + return f"{platform.system().lower()}-{platform.machine().lower()}" + + +def _host_identity(rel: Path) -> Path: + """Prefer a host-suffixed proof identity that binds locally built checker + bytes; fall back to the committed macOS record.""" + host = rel.with_name(rel.stem + f".{_host_tag()}.json") + return host if (DEFAULT_ROOT / host).is_file() else rel + + IDENTITY_CONFIGS = ( ( "range", - Path("release/evidence/range_proof_identity_v172.json"), + _host_identity(Path("release/evidence/range_proof_identity_v172.json")), "jackal-range-proof-identity-v2", ), ( "gaussian", - Path("release/evidence/gaussian_proof_identity.json"), + _host_identity(Path("release/evidence/gaussian_proof_identity.json")), "jackal-gaussian-proof-identity-v1", ), ( "int-cert", - Path("release/evidence/int_cert_proof_identity_v172.json"), + _host_identity(Path("release/evidence/int_cert_proof_identity_v172.json")), "jackal-int-cert-proof-identity-v2", ), ) @@ -897,7 +910,13 @@ def main(argv: list[str] | None = None) -> int: ) return 0 if args.write: - write_atomic(root / ARTIFACT_REL, render_audit(root)) + artifact = ARTIFACT_REL + import platform + if platform.system() != "Darwin": + artifact = ARTIFACT_REL.with_name( + ARTIFACT_REL.stem + f".{_host_tag()}.json") + write_atomic(root / artifact, render_audit(root)) + print(f"LEAN_ADMISSION_AUDIT_WROTE {artifact}") else: check_committed(root) document = strict_json(root / ARTIFACT_REL) From b35b227bc1327ac88f52eaeea3c914c2bcf42671 Mon Sep 17 00:00:00 2001 From: sicarii Date: Sun, 23 Aug 2026 21:49:17 -0400 Subject: [PATCH 02/22] Enable domain-pack + program tools on Linux: all 41 tools host-clean MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The domain-pack protocol-v1 verifier (tools/domain_pack_verify.py) hard-gated to Darwin/arm64, so the four domain-pack/decision tools (jackal_decision_rank, jackal_decision_rank_v2, jackal_test_exists, jackal_claim_cites_test) refused on Linux with "requires Apple Silicon macOS". This admits Linux/aarch64 to that verifier and propagates the resulting digest change consistently. - domain_pack_verify.py: validate_host() gains a SUPPORTED_HOSTS set ({Darwin/arm64, Linux/aarch64}); the emitted report's host field now reflects the real host instead of a hardcoded "darwin-arm64". macOS behavior is unchanged. - domain_packs/registry_v1.json: pack_verifier_sha256 rebound to the edited verifier, registry_digest_sha256 recomputed over the canonical body. - The domain_pack_verifier + domain_pack_registry rows are updated in BOTH release/MANIFEST.sha256 and release/MANIFEST.linux-aarch64.sha256 (the verifier and registry are shared, platform-neutral source), and capability_inventory_v1.json + the plugin identity manifest are regenerated. - build_package_linux.sh: the JACKAL_LOCAL_BUILD domain-pack QA skip is removed; the staged domain-pack verification now runs unconditionally and passes on Linux. - provision_runtime.py: linux-aarch64 release pin updated for the rebuilt package (sha 15803b7e, 177404787 bytes). Verified through the provisioner-installed runtime: all 41 tools are host-clean — exact/checked/estimated/bounded/formal-bounded lanes compute, decision_rank and test_exists return exact/structural-exact, and the claim/verify/program tools reach real input validation with no host refusal. The codex_plugin suite, drift gate, capability inventory, plugin identity, and repin_linux --check all pass; the program-evidence verifier's 12/15 pass on Linux matches pristine (the 3 failures are pre-existing shallow-clone fixtures, not from this change). Co-Authored-By: Claude Opus 4.8 --- domain_packs/registry_v1.json | 4 +- plugins/jackel/PLUGIN_IDENTITY.sha256 | 2 +- plugins/jackel/scripts/provision_runtime.py | 8 ++-- release/MANIFEST.linux-aarch64.sha256 | 4 +- release/MANIFEST.sha256 | 4 +- release/build_package_linux.sh | 44 +++++++++------------ release/capability_inventory_v1.json | 2 +- tools/domain_pack_verify.py | 10 +++-- 8 files changed, 37 insertions(+), 41 deletions(-) diff --git a/domain_packs/registry_v1.json b/domain_packs/registry_v1.json index 30ac20c..387e0a8 100644 --- a/domain_packs/registry_v1.json +++ b/domain_packs/registry_v1.json @@ -8,7 +8,7 @@ "pack_spec_path": "domain_packs/PACK_SPEC.md", "pack_spec_sha256": "2d76022dc2375fa3a235f05890c8b3a36ac77b008ecc5d58fb658deb253a947a", "pack_verifier_path": "tools/domain_pack_verify.py", - "pack_verifier_sha256": "22984f511208af2d7a318f1a43306d95a4b0f61876d8b44f34f39a2ded6d573d", + "pack_verifier_sha256": "53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b", "inference_registry_path": "release/claim/inference_registry_v1.json", "inference_registry_sha256": "c70b33d5aee8071b5125e6a5f8ffe5226fc22a137d920c17d9b3463968be13f0", "packs": [ @@ -54,5 +54,5 @@ ] } ], - "registry_digest_sha256": "9f96f53795746b75f6e9d505e49f6f2578407d224f5e22fdad8a03e8a738fed8" + "registry_digest_sha256": "b4fba2533f43490c3e81a925e84bf8eef223a5e6017d8fddb06d76c9f19e893d" } diff --git a/plugins/jackel/PLUGIN_IDENTITY.sha256 b/plugins/jackel/PLUGIN_IDENTITY.sha256 index c17cd1f..6e41760 100644 --- a/plugins/jackel/PLUGIN_IDENTITY.sha256 +++ b/plugins/jackel/PLUGIN_IDENTITY.sha256 @@ -4,6 +4,6 @@ a165e6b00292a3768ad134562539dabf7874cf23bf9ac8f80e893f7970a63cdc .mcp.json b5916270588db1fbb68b4d520c5f5e9d0fabb84e26602f18ad0a2927a38cece9 mcp/server.py e4fb2996fc2a905a5101974ad6119e6c29fbc10cc8ca2f0223e18f89686dcdff scripts/launch_mcp.sh 878a9d94788a6c132fad151bbddebecb41c08615fe310278e586871fe8f9c44c scripts/launch_mcp.zsh -642228579919b5bf08c799c10b86467b2684e63253730ceda2cff1026a6e9537 scripts/provision_runtime.py +46eecc863ce8b2da1491255e1459333bfe76f865ab28e421f09f475dad2de65c scripts/provision_runtime.py 60f6a068c5f6bd81a2ab80e8d9d873864aefdf7f6ae7c2db37fe6572b41f898f scripts/verify_plugin.py 63f726fbde9e4484424388ef5af68dce92d7f55a4af9354e7d812833f090c972 skills/jackel/SKILL.md diff --git a/plugins/jackel/scripts/provision_runtime.py b/plugins/jackel/scripts/provision_runtime.py index e386046..37ec3d1 100644 --- a/plugins/jackel/scripts/provision_runtime.py +++ b/plugins/jackel/scripts/provision_runtime.py @@ -63,10 +63,10 @@ # upstream asset — install with `provision --tarball `. "asset": "jackal-v1.7.3-linux-aarch64.tar.gz", "url": None, - "package_size": 177404638, - "package_sha256": "d4618d6e153ff1a94ca7a064995e346c10874fe0e2b1afafdb19ef7b2cdb2720", - "extracted_size": 686413084, - "sha256sums_sha256": "d33dd68643c55db7014a48296371bdfadd748d5218b6a859899b2c578ad26256", + "package_size": 177404787, + "package_sha256": "15803b7ed348fe035ef66308d4239ae546732ea50b6e2ca0843e34027a589c3c", + "extracted_size": 686413270, + "sha256sums_sha256": "fcfcd14ae5b6235eefc2afc80d6e38c67f9bccadaeaef41291edfd271e30d902", "package_directory": "jackal-v1.7.3-linux-aarch64", }, } diff --git a/release/MANIFEST.linux-aarch64.sha256 b/release/MANIFEST.linux-aarch64.sha256 index b514d8a..084142d 100644 --- a/release/MANIFEST.linux-aarch64.sha256 +++ b/release/MANIFEST.linux-aarch64.sha256 @@ -39,8 +39,8 @@ exact_verifier tools/exact_verify.py 2c07e6257ce1524de3e31374371c6d5859dce710767 claim_kernel tools/claim_kernel.py 77b0f85ad5fb7214f88898b60ea29ea9fd7be740c38b655388444e6e5181f348 claim_router tools/claim_router.py 02328cf177a0423bdc5cbca6ec0ea946bb0679bbd3dc6c24140d32598e575afb claim_verifier tools/claim_bundle_verify.py e0fcb9540c730bd9bb492b528ed42d29d49fc775b3aa0f9b831b6264fd68fd22 -domain_pack_registry domain_packs/registry_v1.json 1a3b2c95dcdc7c7337fbe0ecb34043b70c3697752d6dc585f45f3c7d4f1b0706 -domain_pack_verifier tools/domain_pack_verify.py 22984f511208af2d7a318f1a43306d95a4b0f61876d8b44f34f39a2ded6d573d +domain_pack_registry domain_packs/registry_v1.json b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03 +domain_pack_verifier tools/domain_pack_verify.py 53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b domain_pack_test_exists_checker tools/test_exists_verify.py 598cb99e1eb70c9410ca87345efee346f73e43aaf3625427dca17ea04231caea domain_pack_decision_checker tools/decision_verify.py f1ad7c9fbd4c1d899dbb4bebabbbeb97e97a56bd4b279ad7d8ec3722bf12e0f6 anubis_program_verifier tools/anubis_program_verify.py 4b80e29bdffc0737f05a6e215fce8cce3b6b828c24afbf55c68443399e5119dc diff --git a/release/MANIFEST.sha256 b/release/MANIFEST.sha256 index d129b12..3b8abf7 100644 --- a/release/MANIFEST.sha256 +++ b/release/MANIFEST.sha256 @@ -39,8 +39,8 @@ exact_verifier tools/exact_verify.py 2c07e6257ce1524de3e31374371c6d5859dce710767 claim_kernel tools/claim_kernel.py 77b0f85ad5fb7214f88898b60ea29ea9fd7be740c38b655388444e6e5181f348 claim_router tools/claim_router.py 02328cf177a0423bdc5cbca6ec0ea946bb0679bbd3dc6c24140d32598e575afb claim_verifier tools/claim_bundle_verify.py e0fcb9540c730bd9bb492b528ed42d29d49fc775b3aa0f9b831b6264fd68fd22 -domain_pack_registry domain_packs/registry_v1.json 1a3b2c95dcdc7c7337fbe0ecb34043b70c3697752d6dc585f45f3c7d4f1b0706 -domain_pack_verifier tools/domain_pack_verify.py 22984f511208af2d7a318f1a43306d95a4b0f61876d8b44f34f39a2ded6d573d +domain_pack_registry domain_packs/registry_v1.json b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03 +domain_pack_verifier tools/domain_pack_verify.py 53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b domain_pack_test_exists_checker tools/test_exists_verify.py 598cb99e1eb70c9410ca87345efee346f73e43aaf3625427dca17ea04231caea domain_pack_decision_checker tools/decision_verify.py f1ad7c9fbd4c1d899dbb4bebabbbeb97e97a56bd4b279ad7d8ec3722bf12e0f6 anubis_program_verifier tools/anubis_program_verify.py 4b80e29bdffc0737f05a6e215fce8cce3b6b828c24afbf55c68443399e5119dc diff --git a/release/build_package_linux.sh b/release/build_package_linux.sh index a872f34..8634116 100755 --- a/release/build_package_linux.sh +++ b/release/build_package_linux.sh @@ -1171,34 +1171,26 @@ for label, relative in manifest_bound_files.items(): print("STAGED_IDENTITY_VALIDATION_PASS") PY -# The domain-pack protocol-v1 verifier host-gates to its supported platforms. -# On a host whose verifier is not yet admitted, this release-QA smoke is skipped -# for a local build (JACKAL_LOCAL_BUILD=1); the domain-pack RUNTIME tools then -# fail closed at call time exactly as the verifier dictates. Identity, proof, -# compat, lean-audit, plugin-identity and formal-lane smokes below still run. -if [ "${JACKAL_LOCAL_BUILD:-0}" = "1" ]; then - echo "STAGED_DOMAIN_PACK_SKIPPED reason=local-build host-verifier-not-admitted" -else +# Domain-pack protocol-v1 QA. The verifier admits this host, so it runs +# unconditionally as part of the staged release validation. PACK_VALIDATION=$(python3 -I -S -B "$PKG/tools/domain_pack_verify.py" \ - --root "$PKG" 2>&1) || { - echo "PACKAGE_V173_REFUSED reason=staged-domain-pack detail=$PACK_VALIDATION" >&2 - exit 4 - } - /usr/bin/printf '%s' "$PACK_VALIDATION" | python3 -I -S -B -c ' - import json - import sys - - try: - report = json.load(sys.stdin) - except (json.JSONDecodeError, UnicodeError): - raise SystemExit(1) - raise SystemExit(0 if isinstance(report, dict) and report.get("status") == "accepted" else 1) - ' || { - echo "PACKAGE_V173_REFUSED reason=staged-domain-pack-status detail=$PACK_VALIDATION" >&2 - exit 4 - } -fi + --root "$PKG" 2>&1) || { + echo "PACKAGE_V173_REFUSED reason=staged-domain-pack detail=$PACK_VALIDATION" >&2 + exit 4 +} +/usr/bin/printf '%s' "$PACK_VALIDATION" | python3 -I -S -B -c ' +import json +import sys +try: + report = json.load(sys.stdin) +except (json.JSONDecodeError, UnicodeError): + raise SystemExit(1) +raise SystemExit(0 if isinstance(report, dict) and report.get("status") == "accepted" else 1) +' || { + echo "PACKAGE_V173_REFUSED reason=staged-domain-pack-status detail=$PACK_VALIDATION" >&2 + exit 4 +} PLUGIN_SELFTEST=$("$PKG/plugin/hermes/jackal_hermes" selftest 2>&1) || { echo "PACKAGE_V173_REFUSED reason=staged-plugin-selftest detail=$PLUGIN_SELFTEST" >&2 exit 4 diff --git a/release/capability_inventory_v1.json b/release/capability_inventory_v1.json index ed5247d..976af2c 100644 --- a/release/capability_inventory_v1.json +++ b/release/capability_inventory_v1.json @@ -1 +1 @@ -{"catalog":{"path":"plugin/hermes/tools.json","sha256":"53c823f07db512b82e01a4f132ff43be426b4b227c436e8853c5144ae0504e87","version":"v1.7.3"},"inputs":[{"path":"tools/capability_inventory.py","sha256":"a966660ef94d7b788be9f92451a78e43b41e12ae2c4e942834c1703994c2ccc0"},{"path":"plugin/hermes/tools.json","sha256":"53c823f07db512b82e01a4f132ff43be426b4b227c436e8853c5144ae0504e87"},{"path":"plugin/hermes/profiles/core.json","sha256":"49f33ba23cca5ab940f1929604f61491bc914d092f291cda4fe4f06b37d042d3"},{"path":"plugin/hermes/profiles/formal.json","sha256":"9be2b3144486311d9ba7f1d41c5033eb8e2553e9d12b71d46e512401f57a084b"},{"path":"plugin/hermes/profiles/full.json","sha256":"0db937da01737bbc0341a591ecd23e55008d8ffc02368517c7d1e7da8b309dec"},{"path":"plugin/hermes/server.py","sha256":"4c42725d797ac78ed20d3e843e602b1c60c88bd13f74e06c65a6b4016b3b7daf"},{"path":"plugins/jackel/.codex-plugin/plugin.json","sha256":"49bbd046759b045add1caf1f19300431fe7d697b59bfd93b57daf1d7edb709ff"},{"path":"plugins/jackel/mcp/server.py","sha256":"b5916270588db1fbb68b4d520c5f5e9d0fabb84e26602f18ad0a2927a38cece9"},{"path":"release/MANIFEST.sha256","sha256":"ac52dafc0e9edbf74dde56b358c3c55ab5b705d3b66811558156c480b3530509"},{"path":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"path":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"path":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"}],"release":{"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"state":"v1.7.3","statement":"Published release identity; the annotated v1.7.3 tag and GitHub release must bind these exact bytes.","version":"v1.7.3"},"schema":"jackal-capability-inventory-v1","status_vocabulary":["bounded","checked","estimated","exact","formal-bounded","indeterminate","model-based","ok","refused","structural-exact","verified","verified-program-evidence","verified-program-receipt"],"tool_count":41,"tools":[{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_range_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"826bed7e2645735d5d333040eaa8c28425df90b6e87f8dd6aa94df1cc40ace45","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded receipt with the certificate embedded (or refuse). Inputs: expression: Anubis expression in the single variable x, restricted to the certified fragment.; input_lo: Interval lower bound as an integer or reduced ℚ (e.g. '1', '2/3').; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-gaussian","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_gaussian_integral","profiles":["formal","full"],"refusal_boundary":"Only the exact catalog-declared Gaussian form and canonical rational bounds/tolerance are admitted. Any other form, failed enclosure, checker rejection, or pin/identity mismatch refuses without downgrade.","release_state":"v1.7.3","schema_sha256":"4a43f67d68610c9e7b13f8bc8195c6c3e9ea24493494eb5aca8e768d707adb13","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a zero-libm formal-bounded Gaussian integral receipt, rerun the pinned checker, or refuse without downgrade. Inputs: expression: Exact canonical exp(-A*(x-mu)^2) expression; all other expressions refuse.; input_lo: Integration lower bound as a canonical rational.; input_hi: Integration upper bound as a canonical rational.; tolerance: Maximum enclosure width as a positive canonical rational."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-int-cert","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_bound_cert","profiles":["formal","full"],"refusal_boundary":"Only the request-bound v1.7.2 composed-integral fragment and canonical bounds/tolerance are admitted. Request-unbound v1.7.0 evidence, unsupported syntax, failed subdivision, checker rejection, or identity mismatch refuses without using the weaker float lane.","release_state":"v1.7.3","schema_sha256":"1229ede1ee518a9b19d3a201268e598fac6fd52fd2eef1bb379f920d6093b9cd","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a request-bound certified composed definite-integral formal receipt (v1.7.2): the untrusted exact-rational producer mirrors the engine's adaptive subdivision, the pinned Lean-proved jackal_int_cert_check binds the exact raw expression/bounds/tolerance and re-checks the whole subdivision-tree certificate (theorem int_cert_sound), and the receipt is independently re-verified before returning. Request-unbound v1.7.0 receipts are revoked. Certified fragment: num/var/neg/add/sub/mul/div/pow(0..4096)/sin/cos/abs in x. Everything else refuses. The weaker float lane jackal_integrate_bound stays status=bounded and is NOT this tool. Inputs: expression: Integrand in the single variable x, restricted to the certified fragment (num/var/neg/add/sub/mul/div/pow/sin/cos/abs).; input_lo: Integration lower bound as an integer or reduced canonical rational (e.g. '0', '2/3').; input_hi: Integration upper bound as a canonical rational, strictly above input_lo.; tolerance: Maximum enclosure width as a positive canonical rational (e.g. '1/100')."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-receipt-registry","identities":[{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_verify_receipt","profiles":["core","formal","full"],"refusal_boundary":"Only closed-registry range/rational, Gaussian, and current request-bound int-cert receipts matching independent caller expectations are replayed. Unknown epochs/variants, copied rather than caller-pinned expectations, revoked int-cert evidence, or checker/pin mismatch refuses.","release_state":"v1.7.3","schema_sha256":"988b83705212769a01eb2e5f5b44322b5728d5fd86eef4f64f7a4a37e378fc1f","status_classes":["verified","refused"],"supported_fragment":"Re-run the matching pinned Lean-proved checker over an embedded certificate using a closed epoch/variant registry: current v1.7.2 range/rational and request-bound int_cert, replay-only v1.5.0 range/rational, or Gaussian v1.5.0. Request-unbound v1.7.0 int_cert receipts refuse. Inputs: receipt: A jackal-formal-receipt-v1 JSON document.; expected_release_epoch: Caller-authorized release epoch, not copied from the receipt.; expected_command: Caller-authorized operation: range-bound-cert or integrate.; expected_expression: Exact raw expression supplied by the caller.; expected_input_lo: Exact raw lower-bound token supplied by the caller.; expected_input_hi: Exact raw upper-bound token supplied by the caller.; expected_tolerance: Exact raw tolerance token; required for Gaussian and int_cert receipts and forbidden for range receipts."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_sqrt_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"bc611de421d812aa6d6d8772fb986c17bcde74d7fe70ea31ff22433335d67c6d","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q sqrt(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'sqrt(x)' on a canonical rational interval; every other expression refuses without downgrade. v1.4.0 fragment extension. Inputs: expression: Must equal 'sqrt(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational (e.g. '2', '1/4'); must be >= 0.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_exp_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"9cc7bee07eebc566a9e267ad1b30c10a73cb25c18090ed2f9a3e9ec48550b928","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q exp(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'exp(x)' on a canonical rational interval [lo, hi] (general-sign since v1.5.0); every other expression refuses without downgrade. v1.4.1 fragment extension. Inputs: expression: Must equal 'exp(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational; any sign (general-sign since v1.5.0).; input_hi: Interval upper bound (canonical rational, hi >= lo); the producer picks a Taylor degree with 2*hi <= n+1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_ln_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"16dfb2b64dc9e290e1c062eba898233b04b187f1b244f6cc06433c48d1b7da45","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q ln(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'ln(x)' on a canonical rational interval with lo > 0; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'ln(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational; must be > 0.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_sin_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"d578799057048871ff13eca207bda2f9564261fce975801904d8cb34370cc7fe","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q sin(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'sin(x)' on a canonical rational interval whose midpoint m satisfies |m| <= 1; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'sin(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo); midpoint (lo+hi)/2 must satisfy |m| <= 1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_cos_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"d0f575ac0dbfe5e64aede075ae30bb1a625f05963e772febca6ac180b29f062b","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q cos(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'cos(x)' on a canonical rational interval whose midpoint m satisfies |m| <= 1; every other expression refuses without downgrade. Shares the sin_rat producer (--op cos). v1.5.0 fragment extension. Inputs: expression: Must equal 'cos(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo); midpoint (lo+hi)/2 must satisfy |m| <= 1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_atan_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"f16e48c7a37e284e124fe20766c7db2b90b4eed8fb748c2efebc9ee7c4b80767","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q atan(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'atan(x)' on a canonical rational interval; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'atan(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_tanh_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"6f9b24d732cc6fc2b0ad9ef7d51fa8cd88f2a344b3152c54f288f6a25a8fe05a","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q tanh enclosure via the untrusted composite producer + Lean-proved checker. NO libm on the proof-decision path. tanh is not an engine grammar token: admits ONLY the literal composite expression '1-2/(exp(2*x)+1)' (= tanh(x) mathematically) on a canonical rational interval with |lo|,|hi| <= 20; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal '1-2/(exp(2*x)+1)' after whitespace normalization (the frozen tanh-defining composite).; input_lo: Interval lower bound as an integer or reduced rational; |lo| <= 20.; input_hi: Interval upper bound (canonical rational, hi >= lo); |hi| <= 20."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_exact","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"42319cf6d3e3f7a8da025e880b8dfc02eb2c6e3128f8b93c11f41545d8bf1d8d","status_classes":["exact","refused"],"supported_fragment":"Exact big-rational arithmetic (status=exact). NOT formal: computationally exact, outside the Lean certificate chain. Inputs: expression: Integers, decimals, + - * / ^ (integer exponents), parentheses. Everything else refuses."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_evaluate","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"5baa3a344309d714a8b66c9fb4a14a97c8182b3cfe1326faa2e9967840eee17c","status_classes":["estimated","refused"],"supported_fragment":"IEEE f64 expression evaluation (status=estimated). A plain number, honestly labeled: no bound, no proof. Inputs: expression: Full expression grammar incl. transcendental functions and constants."},{"assurance_classes":["checked"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_diff","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"605972a25cde65779e921b8a27b7f1a0c19d540f5330791ec0fb571cccf858ad","status_classes":["checked","refused"],"supported_fragment":"Symbolic d/dx with numeric self-verification (status=checked). Sampled agreement is a check, not a proof of identity. Inputs: expression: Expression in x; non-differentiable functions fail closed."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"6d05a705ff580a831f75cbcd2079fe88c3b5d9c858bc6b0c3182ec55aa27cd27","status_classes":["estimated","refused"],"supported_fragment":"Fixed-grid Simpson + Richardson error estimate (status=estimated). Grid-limited: NOT a bound. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; panels: Panel count (e.g. '200')."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_adaptive","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"174132e83bff6d18972cf5d88b072b12d7102cad8fdf05197165c64bfac4fea1","status_classes":["estimated","refused"],"supported_fragment":"Adaptive Simpson with refusal semantics (status=estimated). Refuses when unconverged; agreement is still not a bound. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; tolerance: Local tolerance (e.g. '1e-9')."},{"assurance_classes":["bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_bound","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"9932617903499a2ed2baa4ac213f061f422bd8f2e60bca5bf05225a9f9f788a0","status_classes":["bounded","refused"],"supported_fragment":"Certified interval enclosure of an integral (status=bounded). CONDITIONAL on the stated f64/libm rounding model; implementation campaign-tested, NOT mechanized. Never labeled formal. For a Lean-checked formal-bounded composed enclosure over the certified fragment, use jackal_integrate_bound_cert instead. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; tolerance: Max enclosure width (e.g. '1e-6')."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_solve","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"caf1f55ca8ad1fef2e0fb4f5f5bb600edb147f257427de650335500979c13501","status_classes":["estimated","refused"],"supported_fragment":"Bisection root with residual + first-order conditioning diagnostics (status=estimated). Inputs: expression: f(x) whose root is sought.; input_lo: Bracket lower bound (sign change required).; input_hi: Bracket upper bound."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"ea4ca54f74334d678c3daf9c6686fca186041d27bb2f02dabca21a7747e7d416","status_classes":["exact","refused"],"supported_fragment":"Canonical s-expression + SHA-256 of any parsed expression (status=exact). NOT formal: exact computation outside the Lean certificate chain; no exact-cert emitted. Inputs: expression: Any expression the engine grammar parses."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"199fd63f51398c6e883a407d8e2435e42903e9c76f0227d815f3456b3568d9bc","status_classes":["exact","refused"],"supported_fragment":"Dense Q[x] canonical form, degree <= 64 (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Polynomial expression in x within the poly fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_eq","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"76d9390f705758c6ec2d5fe77cd6a1391908f93ef218ebfd5111c067dc32a819","status_classes":["exact","refused"],"supported_fragment":"Decidable polynomial identity over Q[x] (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: lhs: Left polynomial expression in x.; rhs: Right polynomial expression in x."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_gcd","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"dfff2a285e732d52520ea6fe5efabdab5bd6d956c224f30d163ccbbdbd406a5c","status_classes":["exact","refused"],"supported_fragment":"Monic polynomial gcd over Q[x] via Euclid (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: lhs: Left polynomial expression in x.; rhs: Right polynomial expression in x."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_ratfunc_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"3d4c7d73d13aa88606e9e005b7731c19ac63f9fe559b38e6ff777f979afd3b40","status_classes":["exact","refused"],"supported_fragment":"Rational-function canonical form P/Q, gcd-reduced, monic denominator, explicit denominator-nonzero side condition (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Rational-function expression in x within the ratfunc fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_roots_isolate","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"ea98289e6b6319b7c0b3e6e9832e07ff4a9dd06be1d7862956c50df6e1785978","status_classes":["exact","refused"],"supported_fragment":"Sturm-sequence isolation of all distinct real roots (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Polynomial expression in x within the poly fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_alg_sign","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"b4ad3c632887bc8875f8334dea3391017d73f30fa4895d988062882e89c2c1a5","status_classes":["exact","refused"],"supported_fragment":"Exact sign of a Q[x] polynomial at a rational point (status=exact). NOT formal; no exact-cert emitted. Inputs: expression: Polynomial expression in x within the poly fragment.; point: Rational evaluation point (e.g. '3/2')."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_alg_cmp","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"bfea42d3f97e6f0403d11155d667dfec7000719e2aa3af67c8897989a9e2eee4","status_classes":["exact","refused"],"supported_fragment":"Order decision between two isolated real algebraic numbers (status=exact). NOT formal; no exact-cert emitted. Inputs: p: First defining polynomial in x.; a1: First isolating interval lower bound (rational).; b1: First isolating interval upper bound (rational).; q: Second defining polynomial in x.; a2: Second isolating interval lower bound (rational).; b2: Second isolating interval upper bound (rational)."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_xgcd","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"1c7fb606e43e71eeb4ab288c08ea4a6c89efd95beb3f802e084d5d3c1a3beaf6","status_classes":["exact","refused"],"supported_fragment":"Extended gcd with Bezout certificate (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: a: First integer.; b: Second integer."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_mod_pow","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"b3edc74b3901989b9248f8b89feaed2cc396e218abf9ccfca7ab53a99a9c7bc1","status_classes":["exact","refused"],"supported_fragment":"Modular exponentiation via square-and-multiply (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: base: Base integer.; exp: Nonnegative exponent integer.; mod: Modulus integer >= 1."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_mod_inv","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"d0826f19759afacd20d4a5f0d6704a52bce158c6950bb852a5e0774886a4abd7","status_classes":["exact","refused"],"supported_fragment":"Modular inverse with product certificate (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: a: Integer to invert.; m: Modulus integer >= 2; gcd(a, m) must be 1."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_crt","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"d44aebbbcb3b00ad0d192581533c5cfdb164e26431f3ed850406c8ecfa5044b4","status_classes":["exact","refused"],"supported_fragment":"Chinese remainder reconstruction over pairwise-coprime moduli, up to 16 pairs (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: args: Space-separated residue/modulus pairs: 'r1 m1 r2 m2 [...]' (e.g. '2 3 3 5 2 7')."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_divides","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"1191b2b4ce3a9a5c3a1dafb0917fad46ca9c3375c73f4ae59ff7a389d513adb4","status_classes":["exact","refused"],"supported_fragment":"Exact divisibility decision (status=exact). NOT formal; no exact-cert emitted. Inputs: a: Candidate divisor integer.; b: Dividend integer."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_prime_cert","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"3ff03881b24f8fd94db68b210874010e66ce0e3d32666d98a21c1bc40ccc5646","status_classes":["exact","refused"],"supported_fragment":"Pratt primality certificate or composite divisor witness, budgeted and fail-closed (status=exact; n <= 10^60, Pratt tree depth <= 64, nodes <= 512). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: n: Integer >= 2, at most 61 digits."},{"assurance_classes":["estimated","model-based","checked","bounded","formal-bounded","exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"claim-router","identities":[{"label":"claim_kernel","locator":"tools/claim_kernel.py","sha256":"77b0f85ad5fb7214f88898b60ea29ea9fd7be740c38b655388444e6e5181f348"},{"label":"claim_router","locator":"tools/claim_router.py","sha256":"02328cf177a0423bdc5cbca6ec0ea946bb0679bbd3dc6c24140d32598e575afb"},{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"},{"label":"claim_inference_registry","locator":"release/claim/inference_registry_v1.json","sha256":"c70b33d5aee8071b5125e6a5f8ffe5226fc22a137d920c17d9b3463968be13f0"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_claim","profiles":["core","formal","full"],"refusal_boundary":"Only jackal-claim-request-v1 and its closed step vocabulary are compiled. Policy, identity, schema, route, or assurance failures refuse; fallback is off by default and any caller-enabled fallback remains explicit in the route trace rather than silently changing assurance.","release_state":"v1.7.3","schema_sha256":"4d2703ff772433f39ac8b6555727e856685b0e5042b9c2cc8fcaa4402d6b9153","status_classes":["ok","refused"],"supported_fragment":"Compile a structured jackal-claim-request-v1 into a canonical, content-addressed jackal-claim-bundle-v1 evidence graph through the deterministic policy router. Routes through exact, current/archival range-family, Gaussian, request-bound composed-integral, machine, and unit lanes; emits a route trace naming candidates and refusal reasons; and refuses rather than silently downgrading (allow_fallback defaults false). The bundle is independently replayable via jackal_verify_bundle. Inputs: request: jackal-claim-request-v1 object: {schema, steps:[{id, op, ...}], root, policy?, nonce?, emitted_at_unix?, max_age_seconds?, expires_at_unix?}. Step ops: input, exact, enclose, gaussian, integrate_cert, machine, interval_add/sub/mul/div, threshold, decision, convert, and, model, passthrough, attach."},{"assurance_classes":["estimated","model-based","checked","bounded","formal-bounded","exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"claim-verifier","identities":[{"label":"claim_verifier","locator":"tools/claim_bundle_verify.py","sha256":"e0fcb9540c730bd9bb492b528ed42d29d49fc775b3aa0f9b831b6264fd68fd22"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"},{"label":"claim_inference_registry","locator":"release/claim/inference_registry_v1.json","sha256":"c70b33d5aee8071b5125e6a5f8ffe5226fc22a137d920c17d9b3463968be13f0"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_verify_bundle","profiles":["core","formal","full"],"refusal_boundary":"Only canonical bundles matching separately caller-pinned epoch, policy, root proposition, time, and nonce are replayed. Semantic, graph, freshness, evidence, checker, or pin ambiguity returns refused or indeterminate exactly as declared; it is never converted to success.","release_state":"v1.7.3","schema_sha256":"9e3acec17637a352bc88e3b08e8679a34f1efae3539fe1cce05646212be4cb5f","status_classes":["verified","refused","indeterminate"],"supported_fragment":"Independently replay a jackal-claim-bundle-v1 against caller-pinned expectations. The standalone dependency-free verifier recomputes every canonical byte and hash, revalidates the DAG, selects only the closed current/archival range, Gaussian, or current request-bound int-cert checker/proof tuple, re-runs embedded evidence, recomputes machine/unit mathematics, re-evaluates every inference rule and assurance-axis propagation, enforces consequence-class floors and policy, and recomputes the deterministic rendering. Returns verified | refused | indeterminate with exact reasons — never a generic green badge. Inputs: bundle: The jackal-claim-bundle-v1 object to replay.; expected_release_epoch: Caller-pinned epoch (e.g. 'v1.6.0'); never copied from the bundle.; expected_policy_sha256: Caller-pinned SHA-256 of the canonical policy bytes.; expected_root_proposition: Caller-pinned canonical root proposition IR object.; verification_time_unix: Caller-supplied verification time (unix seconds) for freshness/expiry checks.; expected_nonce: Caller nonce; the bundle root must bind exactly this nonce."},{"assurance_classes":["structural-exact"],"consequence_ceiling":"informational","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"structural-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"1a3b2c95dcdc7c7337fbe0ecb34043b70c3697752d6dc585f45f3c7d4f1b0706"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"22984f511208af2d7a318f1a43306d95a4b0f61876d8b44f34f39a2ded6d573d"},{"label":"domain_pack_test_exists_checker","locator":"tools/test_exists_verify.py","sha256":"598cb99e1eb70c9410ca87345efee346f73e43aaf3625427dca17ea04231caea"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_test_exists","profiles":["full"],"refusal_boundary":"Only byte-exact source/citation structure described by the schema is accepted after independent file-byte recomputation. Path traversal, malformed symbols/hashes, missing text/declarations, or checker mismatch refuses; the result never asserts test execution or correctness.","release_state":"v1.7.3","schema_sha256":"9685ecf3bcf78a3a26916455cc528cdeac137420e8694447e2865b33890f9d46","status_classes":["structural-exact","refused"],"supported_fragment":"Domain pack jackal.programming.source, operation programming.source.test_exists.v1, routed through pack-route. States one byte-exact STRUCTURAL fact: a declaration-shaped occurrence of `symbol` exists at `declaration_line` in a file whose content hash is exactly `file_sha256`, and the file contains exactly `declaration_count` such occurrences. The engine validates the canonical FORM; the manifest-pinned independent checker tools/test_exists_verify.py then recomputes every claimed field from the real bytes on disk and only an ACCEPT verdict returns success, so a misstated hash, line or count refuses instead of minting a certificate. ASSURANCE ceiling exact; CONSEQUENCE ceiling informational, and the second does not rise with the first: a test-exists-cert is NEVER evidence that the code under test is correct, that the test executes, that it is collected by any runner, or that it asserts anything at all. NOT formal: no Lean checker and no theorem are involved. Do not cite this certificate in support of a correctness claim. Inputs: file_path: Repository-relative path token; absolute paths and parent traversal refuse `prog-path`.; file_sha256: Exactly 64 lowercase hex characters; the checker recomputes it from the file bytes.; symbol: Identifier of the declaration; a non-identifier refuses `prog-symbol`.; declaration_line: 1-based line of the declaration as a canonical positive integer.; declaration_count: Total declaration-shaped occurrences of `symbol` in the file; `0` refuses `prog-absent`."},{"assurance_classes":["structural-exact"],"consequence_ceiling":"informational","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"structural-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"1a3b2c95dcdc7c7337fbe0ecb34043b70c3697752d6dc585f45f3c7d4f1b0706"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"22984f511208af2d7a318f1a43306d95a4b0f61876d8b44f34f39a2ded6d573d"},{"label":"domain_pack_test_exists_checker","locator":"tools/test_exists_verify.py","sha256":"598cb99e1eb70c9410ca87345efee346f73e43aaf3625427dca17ea04231caea"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_claim_cites_test","profiles":["full"],"refusal_boundary":"Only byte-exact source/citation structure described by the schema is accepted after independent file-byte recomputation. Path traversal, malformed symbols/hashes, missing text/declarations, or checker mismatch refuses; the result never asserts test execution or correctness.","release_state":"v1.7.3","schema_sha256":"69a533155bde04bfd5dedd43e9d63acd02f3e2773757936e9e1714458e20abd4","status_classes":["structural-exact","refused"],"supported_fragment":"Domain pack jackal.programming.source, operation programming.source.claim_cites_test.v1, routed through pack-route. Resolves a citation: `claim_text` occurs verbatim in the document at `doc_path`/`doc_sha256`, and `symbol` has a declaration-shaped occurrence in the cited test file at `test_path`/`test_sha256`. Resolution is all this establishes. It does NOT establish that the cited test covers, exercises or supports the claim — the cited test may check something entirely different, which is the exact defect this operation exists to bound rather than hide. The manifest-pinned tools/test_exists_verify.py re-runs over the certificate and only ACCEPT returns success, so a claim text absent from the document or a dangling citation refuses. ASSURANCE ceiling exact; CONSEQUENCE ceiling informational, and the second does not rise with the first. NOT formal: no Lean checker and no theorem are involved. Inputs: doc_path: Repository-relative path of the document making the claim.; doc_sha256: Exactly 64 lowercase hex characters for the document bytes.; claim_text: The claim sentence, verbatim, 1..2048 bytes; it must occur in the document.; test_path: Repository-relative path of the cited test file.; test_sha256: Exactly 64 lowercase hex characters for the cited test file bytes.; symbol: Identifier the citation resolves to inside the cited test file."},{"assurance_classes":["exact"],"consequence_ceiling":"decision-boundary","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"decision-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"1a3b2c95dcdc7c7337fbe0ecb34043b70c3697752d6dc585f45f3c7d4f1b0706"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"22984f511208af2d7a318f1a43306d95a4b0f61876d8b44f34f39a2ded6d573d"},{"label":"domain_pack_decision_checker","locator":"tools/decision_verify.py","sha256":"f1ad7c9fbd4c1d899dbb4bebabbbeb97e97a56bd4b279ad7d8ec3722bf12e0f6"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_decision_rank","profiles":["full"],"refusal_boundary":"Only 2..6 schema-valid options under a caller-declared admissible numeric criterion are ranked. Invalid shape/sense/unit, value-judgment criteria, zero top margin, or checker mismatch refuses; caller values are not treated as measurements or confidence intervals.","release_state":"v1.7.3","schema_sha256":"843fe08464d40d97094eeb6424c0c29a3e2617172ba56262ca4122468a8bb92f","status_classes":["exact","refused"],"supported_fragment":"Domain pack jackal.decision.matrix, operation decision.matrix.rank.v1, routed through pack-route. Orders 2..6 labelled options by a caller-declared numeric criterion and emits a jackal-decision-cert-v1 naming the selected option, the runner-up and the exact margin; the manifest-pinned tools/decision_verify.py recomputes the whole ordering from the certificate's own option values and only ACCEPT returns success. Criterion admissibility is decided by the engine against a fixed word list, so a bare value judgment refuses `decision-value-judgment`; a top-two tie refuses `decision-margin-zero`. ASSURANCE ceiling exact; CONSEQUENCE ceiling decision-boundary. The arithmetic is exact and the choice of criterion is not: the declared criterion and the declared option values remain the caller's, this result is not a claim that the criterion is the right one, the values are not measurements, and the margin is not a confidence interval. For the closed-unit lane that additionally requires a declared unit, use jackal_decision_rank_v2. NOT formal: no Lean checker and no theorem are involved. Inputs: decision_id: Caller's identifier for this decision, bound into the certificate. Bytes are restricted to [A-Za-z0-9_]; anything else refuses `prog-symbol`.; criterion: The declared numeric criterion (e.g. 'latency_ms'); a value judgment refuses `decision-value-judgment`.; sense: Exactly 'min' or 'max'; anything else refuses `decision-sense-unknown`.; options: 2..6 whitespace-separated `label value` pairs, e.g. 'a 10 b 20 c 30'. Values are canonical integers. A label containing whitespace shifts the pairing and refuses `pack-args-shape`; it is never silently re-paired."},{"assurance_classes":["exact"],"consequence_ceiling":"decision-boundary","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"decision-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"1a3b2c95dcdc7c7337fbe0ecb34043b70c3697752d6dc585f45f3c7d4f1b0706"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"22984f511208af2d7a318f1a43306d95a4b0f61876d8b44f34f39a2ded6d573d"},{"label":"domain_pack_decision_checker","locator":"tools/decision_verify.py","sha256":"f1ad7c9fbd4c1d899dbb4bebabbbeb97e97a56bd4b279ad7d8ec3722bf12e0f6"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_decision_rank_v2","profiles":["full"],"refusal_boundary":"Only 2..6 schema-valid options under a caller-declared admissible numeric criterion are ranked. Invalid shape/sense/unit, value-judgment criteria, zero top margin, or checker mismatch refuses; caller values are not treated as measurements or confidence intervals.","release_state":"v1.7.3","schema_sha256":"cdc8abba09426977a5319b52410204f21e2e1eb7b38a9de31de751fcb862e78a","status_classes":["exact","refused"],"supported_fragment":"Domain pack jackal.decision.matrix, operation decision.matrix.rank.v2, routed through pack-route. Same deterministic ordering as jackal_decision_rank, plus a REQUIRED declared unit drawn from a closed vocabulary: the 65 canonical ids of release/claim/unit_registry_v1.json excluding the dimensionless identity `one` (66 ids in the registry, `one` is not admitted here). Matching is exact-token and case-sensitive; an alias, a spelled-out name such as 'millisecond', a different case, or the dimensionless identity all refuse `decision-unit-unknown`, and an empty unit refuses `decision-unit-missing`. Emits jackal-decision-cert-v2, re-checked by the manifest-pinned tools/decision_verify.py; only ACCEPT returns success. ASSURANCE ceiling exact; CONSEQUENCE ceiling decision-boundary. Honest residual: a declared unit is NOT a measurement. The closed vocabulary forces the caller to name a dimension, and nothing more — a value-judgment criterion that survives the engine's word list is still accepted when a real unit is declared (`most_elegant` in `ms` ranks), and the values themselves remain caller-declared. NOT formal: no Lean checker and no theorem are involved. Inputs: decision_id: Caller's identifier for this decision, bound into the certificate. Bytes are restricted to [A-Za-z0-9_]; anything else refuses `prog-symbol`.; criterion: The declared numeric criterion; a value judgment refuses `decision-value-judgment` even with an admissible unit.; unit: One canonical unit id from release/claim/unit_registry_v1.json, excluding `one`. Exact token, case-sensitive: 'ms' is admitted, 'millisecond' and 'MS' refuse `decision-unit-unknown`.; sense: Exactly 'min' or 'max'; anything else refuses `decision-sense-unknown`.; options: 2..6 whitespace-separated `label value` pairs, e.g. 'a 10 b 20 c 30'. Values are canonical integers. A label containing whitespace shifts the pairing and refuses `pack-args-shape`; it is never silently re-paired."},{"assurance_classes":["verified-program-evidence"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"4b80e29bdffc0737f05a6e215fce8cce3b6b828c24afbf55c68443399e5119dc"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_check_program","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"177cfcf9dfcd6bbc6e657eb83b88f04bfedaa0f28f81307077a776e2052df1e2","status_classes":["verified-program-evidence","refused"],"supported_fragment":"Run a caller-pinned Anubis compiler only as `build --evidence` in Safe mode, never execute the compiled artifact, then independently close and replay the resulting strict anubis.program-evidence.v3 package under inventory-safe-v1. Emits only verified-program-evidence or a named refusal. This profile checks producer-attested function/policy inventories but explicitly does not establish policy-construct totality, source-to-VC proof, SMT-to-CNF proof, source-native refinement, runtime behavior, or universal soundness. Inputs: source_path: Local regular non-symlink Anubis source path.; anubis_bin: Local regular non-symlink Anubis executable; caller-pinned and hashed before/after build.; expected_source_sha256: Caller-pinned exact source SHA-256.; expected_compiler_sha256: Caller-pinned approved Anubis executable SHA-256.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1; contracted-safe-v1 refuses.; nonce: Caller nonce bound into the receipt.; out_root: New local output root; existing paths refuse."},{"assurance_classes":["verified-program-evidence"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"4b80e29bdffc0737f05a6e215fce8cce3b6b828c24afbf55c68443399e5119dc"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_verify_program","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"45c7aae87c329925f6bd6b9100efc7d099d70fcaeaba915ee59937f019e1153d","status_classes":["verified-program-evidence","refused"],"supported_fragment":"Independently verify caller-selected Anubis Safe source and evidence bytes under inventory-safe-v1: strict v3 roster, exact manifest closure, source/compiler/artifact/policy pins, producer-summary reconciliation, one-to-one solver/proof paths and counters, approved Z3 UNSAT replay, and independent RUP replay. Never executes the artifact and never claims independent policy-construct totality or source-native refinement. Inputs: source_path: Caller-selected regular non-symlink Anubis source path.; evidence_dir: Caller-selected strict anubis.program-evidence.v3 directory.; expected_source_sha256: Caller-pinned exact source SHA-256.; expected_compiler_sha256: Caller-pinned producer executable SHA-256.; expected_artifact_sha256: Caller-pinned sealed artifact SHA-256; artifact bytes are read but never executed.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1.; nonce: Caller nonce bound into the receipt."},{"assurance_classes":["verified-program-receipt"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"4b80e29bdffc0737f05a6e215fce8cce3b6b828c24afbf55c68443399e5119dc"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_verify_program_receipt","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"6bb75d81aebf6f2b3b20900357204e9ef0858cdac412ea016868028cdd2a67d3","status_classes":["verified-program-receipt","refused"],"supported_fragment":"Recompute a jackal-anubis-program-receipt-v1 from caller-selected source/evidence bytes and independent caller pins, rejecting outer-digest-consistent semantic laundering. Success is only verified-program-receipt; it does not raise the underlying inventory-safe-v1 assurance ceiling. Inputs: receipt: Program receipt object to replay; its own pins are never trusted.; source_path: Caller-selected regular source path.; evidence_dir: Caller-selected evidence directory.; expected_source_sha256: Caller-pinned source SHA-256.; expected_compiler_sha256: Caller-pinned compiler SHA-256.; expected_artifact_sha256: Caller-pinned artifact SHA-256.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1.; nonce: Caller nonce; never copied from the receipt."}],"unique_tool_count":41} +{"catalog":{"path":"plugin/hermes/tools.json","sha256":"53c823f07db512b82e01a4f132ff43be426b4b227c436e8853c5144ae0504e87","version":"v1.7.3"},"inputs":[{"path":"tools/capability_inventory.py","sha256":"a966660ef94d7b788be9f92451a78e43b41e12ae2c4e942834c1703994c2ccc0"},{"path":"plugin/hermes/tools.json","sha256":"53c823f07db512b82e01a4f132ff43be426b4b227c436e8853c5144ae0504e87"},{"path":"plugin/hermes/profiles/core.json","sha256":"49f33ba23cca5ab940f1929604f61491bc914d092f291cda4fe4f06b37d042d3"},{"path":"plugin/hermes/profiles/formal.json","sha256":"9be2b3144486311d9ba7f1d41c5033eb8e2553e9d12b71d46e512401f57a084b"},{"path":"plugin/hermes/profiles/full.json","sha256":"0db937da01737bbc0341a591ecd23e55008d8ffc02368517c7d1e7da8b309dec"},{"path":"plugin/hermes/server.py","sha256":"4c42725d797ac78ed20d3e843e602b1c60c88bd13f74e06c65a6b4016b3b7daf"},{"path":"plugins/jackel/.codex-plugin/plugin.json","sha256":"49bbd046759b045add1caf1f19300431fe7d697b59bfd93b57daf1d7edb709ff"},{"path":"plugins/jackel/mcp/server.py","sha256":"b5916270588db1fbb68b4d520c5f5e9d0fabb84e26602f18ad0a2927a38cece9"},{"path":"release/MANIFEST.sha256","sha256":"3c3d86fffe58b8ec6d93c06c61c4397f89ecd8f69b135a1ec6a4e1f2980700fa"},{"path":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"path":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"path":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"}],"release":{"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"state":"v1.7.3","statement":"Published release identity; the annotated v1.7.3 tag and GitHub release must bind these exact bytes.","version":"v1.7.3"},"schema":"jackal-capability-inventory-v1","status_vocabulary":["bounded","checked","estimated","exact","formal-bounded","indeterminate","model-based","ok","refused","structural-exact","verified","verified-program-evidence","verified-program-receipt"],"tool_count":41,"tools":[{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_range_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"826bed7e2645735d5d333040eaa8c28425df90b6e87f8dd6aa94df1cc40ace45","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded receipt with the certificate embedded (or refuse). Inputs: expression: Anubis expression in the single variable x, restricted to the certified fragment.; input_lo: Interval lower bound as an integer or reduced ℚ (e.g. '1', '2/3').; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-gaussian","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_gaussian_integral","profiles":["formal","full"],"refusal_boundary":"Only the exact catalog-declared Gaussian form and canonical rational bounds/tolerance are admitted. Any other form, failed enclosure, checker rejection, or pin/identity mismatch refuses without downgrade.","release_state":"v1.7.3","schema_sha256":"4a43f67d68610c9e7b13f8bc8195c6c3e9ea24493494eb5aca8e768d707adb13","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a zero-libm formal-bounded Gaussian integral receipt, rerun the pinned checker, or refuse without downgrade. Inputs: expression: Exact canonical exp(-A*(x-mu)^2) expression; all other expressions refuse.; input_lo: Integration lower bound as a canonical rational.; input_hi: Integration upper bound as a canonical rational.; tolerance: Maximum enclosure width as a positive canonical rational."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-int-cert","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_bound_cert","profiles":["formal","full"],"refusal_boundary":"Only the request-bound v1.7.2 composed-integral fragment and canonical bounds/tolerance are admitted. Request-unbound v1.7.0 evidence, unsupported syntax, failed subdivision, checker rejection, or identity mismatch refuses without using the weaker float lane.","release_state":"v1.7.3","schema_sha256":"1229ede1ee518a9b19d3a201268e598fac6fd52fd2eef1bb379f920d6093b9cd","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a request-bound certified composed definite-integral formal receipt (v1.7.2): the untrusted exact-rational producer mirrors the engine's adaptive subdivision, the pinned Lean-proved jackal_int_cert_check binds the exact raw expression/bounds/tolerance and re-checks the whole subdivision-tree certificate (theorem int_cert_sound), and the receipt is independently re-verified before returning. Request-unbound v1.7.0 receipts are revoked. Certified fragment: num/var/neg/add/sub/mul/div/pow(0..4096)/sin/cos/abs in x. Everything else refuses. The weaker float lane jackal_integrate_bound stays status=bounded and is NOT this tool. Inputs: expression: Integrand in the single variable x, restricted to the certified fragment (num/var/neg/add/sub/mul/div/pow/sin/cos/abs).; input_lo: Integration lower bound as an integer or reduced canonical rational (e.g. '0', '2/3').; input_hi: Integration upper bound as a canonical rational, strictly above input_lo.; tolerance: Maximum enclosure width as a positive canonical rational (e.g. '1/100')."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-receipt-registry","identities":[{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_verify_receipt","profiles":["core","formal","full"],"refusal_boundary":"Only closed-registry range/rational, Gaussian, and current request-bound int-cert receipts matching independent caller expectations are replayed. Unknown epochs/variants, copied rather than caller-pinned expectations, revoked int-cert evidence, or checker/pin mismatch refuses.","release_state":"v1.7.3","schema_sha256":"988b83705212769a01eb2e5f5b44322b5728d5fd86eef4f64f7a4a37e378fc1f","status_classes":["verified","refused"],"supported_fragment":"Re-run the matching pinned Lean-proved checker over an embedded certificate using a closed epoch/variant registry: current v1.7.2 range/rational and request-bound int_cert, replay-only v1.5.0 range/rational, or Gaussian v1.5.0. Request-unbound v1.7.0 int_cert receipts refuse. Inputs: receipt: A jackal-formal-receipt-v1 JSON document.; expected_release_epoch: Caller-authorized release epoch, not copied from the receipt.; expected_command: Caller-authorized operation: range-bound-cert or integrate.; expected_expression: Exact raw expression supplied by the caller.; expected_input_lo: Exact raw lower-bound token supplied by the caller.; expected_input_hi: Exact raw upper-bound token supplied by the caller.; expected_tolerance: Exact raw tolerance token; required for Gaussian and int_cert receipts and forbidden for range receipts."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_sqrt_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"bc611de421d812aa6d6d8772fb986c17bcde74d7fe70ea31ff22433335d67c6d","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q sqrt(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'sqrt(x)' on a canonical rational interval; every other expression refuses without downgrade. v1.4.0 fragment extension. Inputs: expression: Must equal 'sqrt(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational (e.g. '2', '1/4'); must be >= 0.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_exp_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"9cc7bee07eebc566a9e267ad1b30c10a73cb25c18090ed2f9a3e9ec48550b928","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q exp(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'exp(x)' on a canonical rational interval [lo, hi] (general-sign since v1.5.0); every other expression refuses without downgrade. v1.4.1 fragment extension. Inputs: expression: Must equal 'exp(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational; any sign (general-sign since v1.5.0).; input_hi: Interval upper bound (canonical rational, hi >= lo); the producer picks a Taylor degree with 2*hi <= n+1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_ln_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"16dfb2b64dc9e290e1c062eba898233b04b187f1b244f6cc06433c48d1b7da45","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q ln(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'ln(x)' on a canonical rational interval with lo > 0; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'ln(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational; must be > 0.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_sin_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"d578799057048871ff13eca207bda2f9564261fce975801904d8cb34370cc7fe","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q sin(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'sin(x)' on a canonical rational interval whose midpoint m satisfies |m| <= 1; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'sin(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo); midpoint (lo+hi)/2 must satisfy |m| <= 1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_cos_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"d0f575ac0dbfe5e64aede075ae30bb1a625f05963e772febca6ac180b29f062b","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q cos(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'cos(x)' on a canonical rational interval whose midpoint m satisfies |m| <= 1; every other expression refuses without downgrade. Shares the sin_rat producer (--op cos). v1.5.0 fragment extension. Inputs: expression: Must equal 'cos(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo); midpoint (lo+hi)/2 must satisfy |m| <= 1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_atan_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"f16e48c7a37e284e124fe20766c7db2b90b4eed8fb748c2efebc9ee7c4b80767","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q atan(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'atan(x)' on a canonical rational interval; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'atan(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_tanh_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"6f9b24d732cc6fc2b0ad9ef7d51fa8cd88f2a344b3152c54f288f6a25a8fe05a","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q tanh enclosure via the untrusted composite producer + Lean-proved checker. NO libm on the proof-decision path. tanh is not an engine grammar token: admits ONLY the literal composite expression '1-2/(exp(2*x)+1)' (= tanh(x) mathematically) on a canonical rational interval with |lo|,|hi| <= 20; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal '1-2/(exp(2*x)+1)' after whitespace normalization (the frozen tanh-defining composite).; input_lo: Interval lower bound as an integer or reduced rational; |lo| <= 20.; input_hi: Interval upper bound (canonical rational, hi >= lo); |hi| <= 20."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_exact","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"42319cf6d3e3f7a8da025e880b8dfc02eb2c6e3128f8b93c11f41545d8bf1d8d","status_classes":["exact","refused"],"supported_fragment":"Exact big-rational arithmetic (status=exact). NOT formal: computationally exact, outside the Lean certificate chain. Inputs: expression: Integers, decimals, + - * / ^ (integer exponents), parentheses. Everything else refuses."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_evaluate","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"5baa3a344309d714a8b66c9fb4a14a97c8182b3cfe1326faa2e9967840eee17c","status_classes":["estimated","refused"],"supported_fragment":"IEEE f64 expression evaluation (status=estimated). A plain number, honestly labeled: no bound, no proof. Inputs: expression: Full expression grammar incl. transcendental functions and constants."},{"assurance_classes":["checked"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_diff","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"605972a25cde65779e921b8a27b7f1a0c19d540f5330791ec0fb571cccf858ad","status_classes":["checked","refused"],"supported_fragment":"Symbolic d/dx with numeric self-verification (status=checked). Sampled agreement is a check, not a proof of identity. Inputs: expression: Expression in x; non-differentiable functions fail closed."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"6d05a705ff580a831f75cbcd2079fe88c3b5d9c858bc6b0c3182ec55aa27cd27","status_classes":["estimated","refused"],"supported_fragment":"Fixed-grid Simpson + Richardson error estimate (status=estimated). Grid-limited: NOT a bound. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; panels: Panel count (e.g. '200')."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_adaptive","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"174132e83bff6d18972cf5d88b072b12d7102cad8fdf05197165c64bfac4fea1","status_classes":["estimated","refused"],"supported_fragment":"Adaptive Simpson with refusal semantics (status=estimated). Refuses when unconverged; agreement is still not a bound. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; tolerance: Local tolerance (e.g. '1e-9')."},{"assurance_classes":["bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_bound","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"9932617903499a2ed2baa4ac213f061f422bd8f2e60bca5bf05225a9f9f788a0","status_classes":["bounded","refused"],"supported_fragment":"Certified interval enclosure of an integral (status=bounded). CONDITIONAL on the stated f64/libm rounding model; implementation campaign-tested, NOT mechanized. Never labeled formal. For a Lean-checked formal-bounded composed enclosure over the certified fragment, use jackal_integrate_bound_cert instead. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; tolerance: Max enclosure width (e.g. '1e-6')."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_solve","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"caf1f55ca8ad1fef2e0fb4f5f5bb600edb147f257427de650335500979c13501","status_classes":["estimated","refused"],"supported_fragment":"Bisection root with residual + first-order conditioning diagnostics (status=estimated). Inputs: expression: f(x) whose root is sought.; input_lo: Bracket lower bound (sign change required).; input_hi: Bracket upper bound."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"ea4ca54f74334d678c3daf9c6686fca186041d27bb2f02dabca21a7747e7d416","status_classes":["exact","refused"],"supported_fragment":"Canonical s-expression + SHA-256 of any parsed expression (status=exact). NOT formal: exact computation outside the Lean certificate chain; no exact-cert emitted. Inputs: expression: Any expression the engine grammar parses."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"199fd63f51398c6e883a407d8e2435e42903e9c76f0227d815f3456b3568d9bc","status_classes":["exact","refused"],"supported_fragment":"Dense Q[x] canonical form, degree <= 64 (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Polynomial expression in x within the poly fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_eq","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"76d9390f705758c6ec2d5fe77cd6a1391908f93ef218ebfd5111c067dc32a819","status_classes":["exact","refused"],"supported_fragment":"Decidable polynomial identity over Q[x] (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: lhs: Left polynomial expression in x.; rhs: Right polynomial expression in x."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_gcd","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"dfff2a285e732d52520ea6fe5efabdab5bd6d956c224f30d163ccbbdbd406a5c","status_classes":["exact","refused"],"supported_fragment":"Monic polynomial gcd over Q[x] via Euclid (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: lhs: Left polynomial expression in x.; rhs: Right polynomial expression in x."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_ratfunc_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"3d4c7d73d13aa88606e9e005b7731c19ac63f9fe559b38e6ff777f979afd3b40","status_classes":["exact","refused"],"supported_fragment":"Rational-function canonical form P/Q, gcd-reduced, monic denominator, explicit denominator-nonzero side condition (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Rational-function expression in x within the ratfunc fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_roots_isolate","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"ea98289e6b6319b7c0b3e6e9832e07ff4a9dd06be1d7862956c50df6e1785978","status_classes":["exact","refused"],"supported_fragment":"Sturm-sequence isolation of all distinct real roots (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Polynomial expression in x within the poly fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_alg_sign","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"b4ad3c632887bc8875f8334dea3391017d73f30fa4895d988062882e89c2c1a5","status_classes":["exact","refused"],"supported_fragment":"Exact sign of a Q[x] polynomial at a rational point (status=exact). NOT formal; no exact-cert emitted. Inputs: expression: Polynomial expression in x within the poly fragment.; point: Rational evaluation point (e.g. '3/2')."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_alg_cmp","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"bfea42d3f97e6f0403d11155d667dfec7000719e2aa3af67c8897989a9e2eee4","status_classes":["exact","refused"],"supported_fragment":"Order decision between two isolated real algebraic numbers (status=exact). NOT formal; no exact-cert emitted. Inputs: p: First defining polynomial in x.; a1: First isolating interval lower bound (rational).; b1: First isolating interval upper bound (rational).; q: Second defining polynomial in x.; a2: Second isolating interval lower bound (rational).; b2: Second isolating interval upper bound (rational)."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_xgcd","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"1c7fb606e43e71eeb4ab288c08ea4a6c89efd95beb3f802e084d5d3c1a3beaf6","status_classes":["exact","refused"],"supported_fragment":"Extended gcd with Bezout certificate (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: a: First integer.; b: Second integer."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_mod_pow","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"b3edc74b3901989b9248f8b89feaed2cc396e218abf9ccfca7ab53a99a9c7bc1","status_classes":["exact","refused"],"supported_fragment":"Modular exponentiation via square-and-multiply (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: base: Base integer.; exp: Nonnegative exponent integer.; mod: Modulus integer >= 1."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_mod_inv","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"d0826f19759afacd20d4a5f0d6704a52bce158c6950bb852a5e0774886a4abd7","status_classes":["exact","refused"],"supported_fragment":"Modular inverse with product certificate (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: a: Integer to invert.; m: Modulus integer >= 2; gcd(a, m) must be 1."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_crt","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"d44aebbbcb3b00ad0d192581533c5cfdb164e26431f3ed850406c8ecfa5044b4","status_classes":["exact","refused"],"supported_fragment":"Chinese remainder reconstruction over pairwise-coprime moduli, up to 16 pairs (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: args: Space-separated residue/modulus pairs: 'r1 m1 r2 m2 [...]' (e.g. '2 3 3 5 2 7')."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_divides","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"1191b2b4ce3a9a5c3a1dafb0917fad46ca9c3375c73f4ae59ff7a389d513adb4","status_classes":["exact","refused"],"supported_fragment":"Exact divisibility decision (status=exact). NOT formal; no exact-cert emitted. Inputs: a: Candidate divisor integer.; b: Dividend integer."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_prime_cert","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"3ff03881b24f8fd94db68b210874010e66ce0e3d32666d98a21c1bc40ccc5646","status_classes":["exact","refused"],"supported_fragment":"Pratt primality certificate or composite divisor witness, budgeted and fail-closed (status=exact; n <= 10^60, Pratt tree depth <= 64, nodes <= 512). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: n: Integer >= 2, at most 61 digits."},{"assurance_classes":["estimated","model-based","checked","bounded","formal-bounded","exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"claim-router","identities":[{"label":"claim_kernel","locator":"tools/claim_kernel.py","sha256":"77b0f85ad5fb7214f88898b60ea29ea9fd7be740c38b655388444e6e5181f348"},{"label":"claim_router","locator":"tools/claim_router.py","sha256":"02328cf177a0423bdc5cbca6ec0ea946bb0679bbd3dc6c24140d32598e575afb"},{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"},{"label":"claim_inference_registry","locator":"release/claim/inference_registry_v1.json","sha256":"c70b33d5aee8071b5125e6a5f8ffe5226fc22a137d920c17d9b3463968be13f0"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_claim","profiles":["core","formal","full"],"refusal_boundary":"Only jackal-claim-request-v1 and its closed step vocabulary are compiled. Policy, identity, schema, route, or assurance failures refuse; fallback is off by default and any caller-enabled fallback remains explicit in the route trace rather than silently changing assurance.","release_state":"v1.7.3","schema_sha256":"4d2703ff772433f39ac8b6555727e856685b0e5042b9c2cc8fcaa4402d6b9153","status_classes":["ok","refused"],"supported_fragment":"Compile a structured jackal-claim-request-v1 into a canonical, content-addressed jackal-claim-bundle-v1 evidence graph through the deterministic policy router. Routes through exact, current/archival range-family, Gaussian, request-bound composed-integral, machine, and unit lanes; emits a route trace naming candidates and refusal reasons; and refuses rather than silently downgrading (allow_fallback defaults false). The bundle is independently replayable via jackal_verify_bundle. Inputs: request: jackal-claim-request-v1 object: {schema, steps:[{id, op, ...}], root, policy?, nonce?, emitted_at_unix?, max_age_seconds?, expires_at_unix?}. Step ops: input, exact, enclose, gaussian, integrate_cert, machine, interval_add/sub/mul/div, threshold, decision, convert, and, model, passthrough, attach."},{"assurance_classes":["estimated","model-based","checked","bounded","formal-bounded","exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"claim-verifier","identities":[{"label":"claim_verifier","locator":"tools/claim_bundle_verify.py","sha256":"e0fcb9540c730bd9bb492b528ed42d29d49fc775b3aa0f9b831b6264fd68fd22"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"},{"label":"claim_inference_registry","locator":"release/claim/inference_registry_v1.json","sha256":"c70b33d5aee8071b5125e6a5f8ffe5226fc22a137d920c17d9b3463968be13f0"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_verify_bundle","profiles":["core","formal","full"],"refusal_boundary":"Only canonical bundles matching separately caller-pinned epoch, policy, root proposition, time, and nonce are replayed. Semantic, graph, freshness, evidence, checker, or pin ambiguity returns refused or indeterminate exactly as declared; it is never converted to success.","release_state":"v1.7.3","schema_sha256":"9e3acec17637a352bc88e3b08e8679a34f1efae3539fe1cce05646212be4cb5f","status_classes":["verified","refused","indeterminate"],"supported_fragment":"Independently replay a jackal-claim-bundle-v1 against caller-pinned expectations. The standalone dependency-free verifier recomputes every canonical byte and hash, revalidates the DAG, selects only the closed current/archival range, Gaussian, or current request-bound int-cert checker/proof tuple, re-runs embedded evidence, recomputes machine/unit mathematics, re-evaluates every inference rule and assurance-axis propagation, enforces consequence-class floors and policy, and recomputes the deterministic rendering. Returns verified | refused | indeterminate with exact reasons — never a generic green badge. Inputs: bundle: The jackal-claim-bundle-v1 object to replay.; expected_release_epoch: Caller-pinned epoch (e.g. 'v1.6.0'); never copied from the bundle.; expected_policy_sha256: Caller-pinned SHA-256 of the canonical policy bytes.; expected_root_proposition: Caller-pinned canonical root proposition IR object.; verification_time_unix: Caller-supplied verification time (unix seconds) for freshness/expiry checks.; expected_nonce: Caller nonce; the bundle root must bind exactly this nonce."},{"assurance_classes":["structural-exact"],"consequence_ceiling":"informational","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"structural-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_test_exists_checker","locator":"tools/test_exists_verify.py","sha256":"598cb99e1eb70c9410ca87345efee346f73e43aaf3625427dca17ea04231caea"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_test_exists","profiles":["full"],"refusal_boundary":"Only byte-exact source/citation structure described by the schema is accepted after independent file-byte recomputation. Path traversal, malformed symbols/hashes, missing text/declarations, or checker mismatch refuses; the result never asserts test execution or correctness.","release_state":"v1.7.3","schema_sha256":"9685ecf3bcf78a3a26916455cc528cdeac137420e8694447e2865b33890f9d46","status_classes":["structural-exact","refused"],"supported_fragment":"Domain pack jackal.programming.source, operation programming.source.test_exists.v1, routed through pack-route. States one byte-exact STRUCTURAL fact: a declaration-shaped occurrence of `symbol` exists at `declaration_line` in a file whose content hash is exactly `file_sha256`, and the file contains exactly `declaration_count` such occurrences. The engine validates the canonical FORM; the manifest-pinned independent checker tools/test_exists_verify.py then recomputes every claimed field from the real bytes on disk and only an ACCEPT verdict returns success, so a misstated hash, line or count refuses instead of minting a certificate. ASSURANCE ceiling exact; CONSEQUENCE ceiling informational, and the second does not rise with the first: a test-exists-cert is NEVER evidence that the code under test is correct, that the test executes, that it is collected by any runner, or that it asserts anything at all. NOT formal: no Lean checker and no theorem are involved. Do not cite this certificate in support of a correctness claim. Inputs: file_path: Repository-relative path token; absolute paths and parent traversal refuse `prog-path`.; file_sha256: Exactly 64 lowercase hex characters; the checker recomputes it from the file bytes.; symbol: Identifier of the declaration; a non-identifier refuses `prog-symbol`.; declaration_line: 1-based line of the declaration as a canonical positive integer.; declaration_count: Total declaration-shaped occurrences of `symbol` in the file; `0` refuses `prog-absent`."},{"assurance_classes":["structural-exact"],"consequence_ceiling":"informational","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"structural-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_test_exists_checker","locator":"tools/test_exists_verify.py","sha256":"598cb99e1eb70c9410ca87345efee346f73e43aaf3625427dca17ea04231caea"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_claim_cites_test","profiles":["full"],"refusal_boundary":"Only byte-exact source/citation structure described by the schema is accepted after independent file-byte recomputation. Path traversal, malformed symbols/hashes, missing text/declarations, or checker mismatch refuses; the result never asserts test execution or correctness.","release_state":"v1.7.3","schema_sha256":"69a533155bde04bfd5dedd43e9d63acd02f3e2773757936e9e1714458e20abd4","status_classes":["structural-exact","refused"],"supported_fragment":"Domain pack jackal.programming.source, operation programming.source.claim_cites_test.v1, routed through pack-route. Resolves a citation: `claim_text` occurs verbatim in the document at `doc_path`/`doc_sha256`, and `symbol` has a declaration-shaped occurrence in the cited test file at `test_path`/`test_sha256`. Resolution is all this establishes. It does NOT establish that the cited test covers, exercises or supports the claim — the cited test may check something entirely different, which is the exact defect this operation exists to bound rather than hide. The manifest-pinned tools/test_exists_verify.py re-runs over the certificate and only ACCEPT returns success, so a claim text absent from the document or a dangling citation refuses. ASSURANCE ceiling exact; CONSEQUENCE ceiling informational, and the second does not rise with the first. NOT formal: no Lean checker and no theorem are involved. Inputs: doc_path: Repository-relative path of the document making the claim.; doc_sha256: Exactly 64 lowercase hex characters for the document bytes.; claim_text: The claim sentence, verbatim, 1..2048 bytes; it must occur in the document.; test_path: Repository-relative path of the cited test file.; test_sha256: Exactly 64 lowercase hex characters for the cited test file bytes.; symbol: Identifier the citation resolves to inside the cited test file."},{"assurance_classes":["exact"],"consequence_ceiling":"decision-boundary","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"decision-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_decision_checker","locator":"tools/decision_verify.py","sha256":"f1ad7c9fbd4c1d899dbb4bebabbbeb97e97a56bd4b279ad7d8ec3722bf12e0f6"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_decision_rank","profiles":["full"],"refusal_boundary":"Only 2..6 schema-valid options under a caller-declared admissible numeric criterion are ranked. Invalid shape/sense/unit, value-judgment criteria, zero top margin, or checker mismatch refuses; caller values are not treated as measurements or confidence intervals.","release_state":"v1.7.3","schema_sha256":"843fe08464d40d97094eeb6424c0c29a3e2617172ba56262ca4122468a8bb92f","status_classes":["exact","refused"],"supported_fragment":"Domain pack jackal.decision.matrix, operation decision.matrix.rank.v1, routed through pack-route. Orders 2..6 labelled options by a caller-declared numeric criterion and emits a jackal-decision-cert-v1 naming the selected option, the runner-up and the exact margin; the manifest-pinned tools/decision_verify.py recomputes the whole ordering from the certificate's own option values and only ACCEPT returns success. Criterion admissibility is decided by the engine against a fixed word list, so a bare value judgment refuses `decision-value-judgment`; a top-two tie refuses `decision-margin-zero`. ASSURANCE ceiling exact; CONSEQUENCE ceiling decision-boundary. The arithmetic is exact and the choice of criterion is not: the declared criterion and the declared option values remain the caller's, this result is not a claim that the criterion is the right one, the values are not measurements, and the margin is not a confidence interval. For the closed-unit lane that additionally requires a declared unit, use jackal_decision_rank_v2. NOT formal: no Lean checker and no theorem are involved. Inputs: decision_id: Caller's identifier for this decision, bound into the certificate. Bytes are restricted to [A-Za-z0-9_]; anything else refuses `prog-symbol`.; criterion: The declared numeric criterion (e.g. 'latency_ms'); a value judgment refuses `decision-value-judgment`.; sense: Exactly 'min' or 'max'; anything else refuses `decision-sense-unknown`.; options: 2..6 whitespace-separated `label value` pairs, e.g. 'a 10 b 20 c 30'. Values are canonical integers. A label containing whitespace shifts the pairing and refuses `pack-args-shape`; it is never silently re-paired."},{"assurance_classes":["exact"],"consequence_ceiling":"decision-boundary","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"decision-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_decision_checker","locator":"tools/decision_verify.py","sha256":"f1ad7c9fbd4c1d899dbb4bebabbbeb97e97a56bd4b279ad7d8ec3722bf12e0f6"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_decision_rank_v2","profiles":["full"],"refusal_boundary":"Only 2..6 schema-valid options under a caller-declared admissible numeric criterion are ranked. Invalid shape/sense/unit, value-judgment criteria, zero top margin, or checker mismatch refuses; caller values are not treated as measurements or confidence intervals.","release_state":"v1.7.3","schema_sha256":"cdc8abba09426977a5319b52410204f21e2e1eb7b38a9de31de751fcb862e78a","status_classes":["exact","refused"],"supported_fragment":"Domain pack jackal.decision.matrix, operation decision.matrix.rank.v2, routed through pack-route. Same deterministic ordering as jackal_decision_rank, plus a REQUIRED declared unit drawn from a closed vocabulary: the 65 canonical ids of release/claim/unit_registry_v1.json excluding the dimensionless identity `one` (66 ids in the registry, `one` is not admitted here). Matching is exact-token and case-sensitive; an alias, a spelled-out name such as 'millisecond', a different case, or the dimensionless identity all refuse `decision-unit-unknown`, and an empty unit refuses `decision-unit-missing`. Emits jackal-decision-cert-v2, re-checked by the manifest-pinned tools/decision_verify.py; only ACCEPT returns success. ASSURANCE ceiling exact; CONSEQUENCE ceiling decision-boundary. Honest residual: a declared unit is NOT a measurement. The closed vocabulary forces the caller to name a dimension, and nothing more — a value-judgment criterion that survives the engine's word list is still accepted when a real unit is declared (`most_elegant` in `ms` ranks), and the values themselves remain caller-declared. NOT formal: no Lean checker and no theorem are involved. Inputs: decision_id: Caller's identifier for this decision, bound into the certificate. Bytes are restricted to [A-Za-z0-9_]; anything else refuses `prog-symbol`.; criterion: The declared numeric criterion; a value judgment refuses `decision-value-judgment` even with an admissible unit.; unit: One canonical unit id from release/claim/unit_registry_v1.json, excluding `one`. Exact token, case-sensitive: 'ms' is admitted, 'millisecond' and 'MS' refuse `decision-unit-unknown`.; sense: Exactly 'min' or 'max'; anything else refuses `decision-sense-unknown`.; options: 2..6 whitespace-separated `label value` pairs, e.g. 'a 10 b 20 c 30'. Values are canonical integers. A label containing whitespace shifts the pairing and refuses `pack-args-shape`; it is never silently re-paired."},{"assurance_classes":["verified-program-evidence"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"4b80e29bdffc0737f05a6e215fce8cce3b6b828c24afbf55c68443399e5119dc"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_check_program","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"177cfcf9dfcd6bbc6e657eb83b88f04bfedaa0f28f81307077a776e2052df1e2","status_classes":["verified-program-evidence","refused"],"supported_fragment":"Run a caller-pinned Anubis compiler only as `build --evidence` in Safe mode, never execute the compiled artifact, then independently close and replay the resulting strict anubis.program-evidence.v3 package under inventory-safe-v1. Emits only verified-program-evidence or a named refusal. This profile checks producer-attested function/policy inventories but explicitly does not establish policy-construct totality, source-to-VC proof, SMT-to-CNF proof, source-native refinement, runtime behavior, or universal soundness. Inputs: source_path: Local regular non-symlink Anubis source path.; anubis_bin: Local regular non-symlink Anubis executable; caller-pinned and hashed before/after build.; expected_source_sha256: Caller-pinned exact source SHA-256.; expected_compiler_sha256: Caller-pinned approved Anubis executable SHA-256.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1; contracted-safe-v1 refuses.; nonce: Caller nonce bound into the receipt.; out_root: New local output root; existing paths refuse."},{"assurance_classes":["verified-program-evidence"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"4b80e29bdffc0737f05a6e215fce8cce3b6b828c24afbf55c68443399e5119dc"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_verify_program","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"45c7aae87c329925f6bd6b9100efc7d099d70fcaeaba915ee59937f019e1153d","status_classes":["verified-program-evidence","refused"],"supported_fragment":"Independently verify caller-selected Anubis Safe source and evidence bytes under inventory-safe-v1: strict v3 roster, exact manifest closure, source/compiler/artifact/policy pins, producer-summary reconciliation, one-to-one solver/proof paths and counters, approved Z3 UNSAT replay, and independent RUP replay. Never executes the artifact and never claims independent policy-construct totality or source-native refinement. Inputs: source_path: Caller-selected regular non-symlink Anubis source path.; evidence_dir: Caller-selected strict anubis.program-evidence.v3 directory.; expected_source_sha256: Caller-pinned exact source SHA-256.; expected_compiler_sha256: Caller-pinned producer executable SHA-256.; expected_artifact_sha256: Caller-pinned sealed artifact SHA-256; artifact bytes are read but never executed.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1.; nonce: Caller nonce bound into the receipt."},{"assurance_classes":["verified-program-receipt"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"4b80e29bdffc0737f05a6e215fce8cce3b6b828c24afbf55c68443399e5119dc"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_verify_program_receipt","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"6bb75d81aebf6f2b3b20900357204e9ef0858cdac412ea016868028cdd2a67d3","status_classes":["verified-program-receipt","refused"],"supported_fragment":"Recompute a jackal-anubis-program-receipt-v1 from caller-selected source/evidence bytes and independent caller pins, rejecting outer-digest-consistent semantic laundering. Success is only verified-program-receipt; it does not raise the underlying inventory-safe-v1 assurance ceiling. Inputs: receipt: Program receipt object to replay; its own pins are never trusted.; source_path: Caller-selected regular source path.; evidence_dir: Caller-selected evidence directory.; expected_source_sha256: Caller-pinned source SHA-256.; expected_compiler_sha256: Caller-pinned compiler SHA-256.; expected_artifact_sha256: Caller-pinned artifact SHA-256.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1.; nonce: Caller nonce; never copied from the receipt."}],"unique_tool_count":41} diff --git a/tools/domain_pack_verify.py b/tools/domain_pack_verify.py index 99218e2..90d9b78 100644 --- a/tools/domain_pack_verify.py +++ b/tools/domain_pack_verify.py @@ -489,13 +489,17 @@ def _release_tuple(value: object, context: str) -> tuple[int, int, int]: return int(major), int(minor), int(patch) +SUPPORTED_HOSTS = {("Darwin", "arm64"), ("Linux", "aarch64")} + + def validate_host() -> None: system = platform.system() machine = platform.machine() - if system != "Darwin" or machine != "arm64": + if (system, machine) not in SUPPORTED_HOSTS: + supported = ", ".join(f"{s}/{m}" for s, m in sorted(SUPPORTED_HOSTS)) refuse( "unsupported host: domain-pack protocol v1 requires " - f"Apple Silicon macOS, got {system}/{machine}" + f"one of {supported}, got {system}/{machine}" ) @@ -806,7 +810,7 @@ def verify_repository(root: Path | str) -> dict[str, Any]: "schema": schema["registry_schema"], "protocol_version": "1", "authority": "anubis-safe-mode", - "host": "darwin-arm64", + "host": f"{platform.system().lower()}-{platform.machine().lower()}", "verification_scope": "metadata-identity-and-policy-only", "anubis_execution_status": "NOT_EXECUTED", "assurance_status": "NOT_MINTED", From 8f81bdf7d71ebd07c21650d524cb66be36290757 Mon Sep 17 00:00:00 2001 From: sicarii Date: Sun, 23 Aug 2026 22:21:35 -0400 Subject: [PATCH 03/22] Omarchy edition: native archival checker, zero macOS bytes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Linux package previously shipped one macOS binary — jackal_cert_check_v170, the archival v1.7.0 range-replay checker, pulled from the Apple release archive. It could not execute on Linux, so the archival replay lane was a dead file. This rebuilds it native and re-pins the archival chain, so the Omarchy (Linux aarch64) edition carries zero macOS bytes: all five binaries are native ELF. - The v1.7.0 range checker is rebuilt from the v1.7.0 tag's Lean source against the same Lean 4.32 / Mathlib v4.32 toolchain (native ELF, sha d515cdc2). It ACCEPTs a valid enclosure and REJECTs a tampered one, verified in the installed runtime. - A native archival v1 proof identity (schema jackal-range-proof-identity-v1, binding the native checker bytes) is generated at the v1.7.0 tag and shipped as release/evidence/range_proof_identity.linux-aarch64.json. - Host-aware archival pins: formal_receipt.py resolves both the archival range checker sha and the archival identity file sha per host (native on Linux via release/evidence/archival_range_checker.linux-aarch64, macOS bytes as the fallback); the Linux compat floor and manifest carry the native shas; repin_linux.py rebinds the archival-range-checker and archival-range-proof rows. - build_package_linux.sh no longer downloads the Apple v1.7.0 archive: it copies the native archival checker and the platform-neutral archival coverage inventory from JACKAL_ARCHIVAL_DIR, verifying both against their pins. Verified: the built package and installed runtime contain zero Mach-O binaries; full identity + semantic validation passes (including the archival identity / checker consistency checks); plugin identity_match=true; all 41 tools and every formal lane work. macOS release identity (MANIFEST.sha256, the macOS archival identity, macOS compat floor) is untouched — the host-aware fallbacks keep the macOS edition on its original bytes. Co-Authored-By: Claude Opus 4.8 --- plugins/jackel/PLUGIN_IDENTITY.sha256 | 2 +- plugins/jackel/scripts/provision_runtime.py | 8 +- release/MANIFEST.linux-aarch64.sha256 | 6 +- release/build_package_linux.sh | 70 +-- release/compat/v172_floor.linux-aarch64.json | 8 +- .../archival_range_checker.linux-aarch64 | 1 + .../range_proof_identity.linux-aarch64.json | 550 ++++++++++++++++++ release/tools/repin_linux.py | 13 + tools/formal_receipt.py | 29 +- 9 files changed, 619 insertions(+), 68 deletions(-) create mode 100644 release/evidence/archival_range_checker.linux-aarch64 create mode 100644 release/evidence/range_proof_identity.linux-aarch64.json diff --git a/plugins/jackel/PLUGIN_IDENTITY.sha256 b/plugins/jackel/PLUGIN_IDENTITY.sha256 index 6e41760..b835790 100644 --- a/plugins/jackel/PLUGIN_IDENTITY.sha256 +++ b/plugins/jackel/PLUGIN_IDENTITY.sha256 @@ -4,6 +4,6 @@ a165e6b00292a3768ad134562539dabf7874cf23bf9ac8f80e893f7970a63cdc .mcp.json b5916270588db1fbb68b4d520c5f5e9d0fabb84e26602f18ad0a2927a38cece9 mcp/server.py e4fb2996fc2a905a5101974ad6119e6c29fbc10cc8ca2f0223e18f89686dcdff scripts/launch_mcp.sh 878a9d94788a6c132fad151bbddebecb41c08615fe310278e586871fe8f9c44c scripts/launch_mcp.zsh -46eecc863ce8b2da1491255e1459333bfe76f865ab28e421f09f475dad2de65c scripts/provision_runtime.py +916a8f4279f99954f21ab20e2b4281457ced54da153adf95618491c1afb9cced scripts/provision_runtime.py 60f6a068c5f6bd81a2ab80e8d9d873864aefdf7f6ae7c2db37fe6572b41f898f scripts/verify_plugin.py 63f726fbde9e4484424388ef5af68dce92d7f55a4af9354e7d812833f090c972 skills/jackel/SKILL.md diff --git a/plugins/jackel/scripts/provision_runtime.py b/plugins/jackel/scripts/provision_runtime.py index 37ec3d1..4b0e218 100644 --- a/plugins/jackel/scripts/provision_runtime.py +++ b/plugins/jackel/scripts/provision_runtime.py @@ -63,10 +63,10 @@ # upstream asset — install with `provision --tarball `. "asset": "jackal-v1.7.3-linux-aarch64.tar.gz", "url": None, - "package_size": 177404787, - "package_sha256": "15803b7ed348fe035ef66308d4239ae546732ea50b6e2ca0843e34027a589c3c", - "extracted_size": 686413270, - "sha256sums_sha256": "fcfcd14ae5b6235eefc2afc80d6e38c67f9bccadaeaef41291edfd271e30d902", + "package_size": 183743522, + "package_sha256": "a0ad634be9db97b31294ce5e62267a96583da03783a04d496af35c9df5530b1c", + "extracted_size": 730019814, + "sha256sums_sha256": "0492872b881d2ea1d84a4b14c4332fc74dccdeb78cc60ff317b05e27ac50c744", "package_directory": "jackal-v1.7.3-linux-aarch64", }, } diff --git a/release/MANIFEST.linux-aarch64.sha256 b/release/MANIFEST.linux-aarch64.sha256 index 084142d..527de7c 100644 --- a/release/MANIFEST.linux-aarch64.sha256 +++ b/release/MANIFEST.linux-aarch64.sha256 @@ -2,15 +2,15 @@ evaluator jackal-native 4c0ae28d2f41353332dbb29f1b6084cd275d08bad73a84942fbe6f500255d872 checker jackal_cert_check 89e4e42d8daa57d4a9a19f9b95b29bd5e96fae5ad7060ac3adf355f1dfeb870c archival-v170-archive-source github-release-v1.7.0 21c7ede586f30a58772f321f7dbb36ab66213e199785489f99133710ac56096e -archival-range-checker jackal_cert_check_v170 05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a +archival-range-checker jackal_cert_check_v170 d515cdc2e66e53e46aef49ebb0d804a3ebd30d0b69fc7e8de7a3a19aac5170f2 archival-range-coverage-inventory formal_coverage_inventory_v170.json 18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6 archival-plugin-hermes v1.7.0-plugin d141c909e8f5f03e268a2112f291e6bd79fafff906522eb7ca9accc247a3274b gaussian-producer tools/gaussian_certificate.py 20c24622b786940a8e82198f2364fb7593e761902fa0736289b179642f1e4306 gaussian-checker jackal_gaussian_check 1f21c6b2e41c171414405c0aa6fee089851716d1add707727ace45395f4ed379 range-proof-identity release/evidence/range_proof_identity_v172.linux-aarch64.json c6caed2434cbd77cba19bb0279936bfa322a696301e6d20c932a9b412f2fa0ca range-proof-digest e373a459c1ddbd87be1b8bb881440338872a527cf1805d13340833e2e7d098d1 -archival-range-proof-identity release/evidence/range_proof_identity.json 1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67 -archival-range-proof-digest 5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e +archival-range-proof-identity release/evidence/range_proof_identity.linux-aarch64.json 4b1c2958481e1047551c42b8f23a827a8422ad9e8881ec913ec88a4cd95b44f2 +archival-range-proof-digest 022c19e317e68049e48b69bfa8567f4ba617610aa5a6bf3c59d8c9a98995c518 gaussian-proof-identity release/evidence/gaussian_proof_identity.linux-aarch64.json 610624b48f48dcd089e0ad14ddac7ebbc25071e7d70cc8516ad6c3c09c747404 gaussian-proof-digest 489780aab2b7b5f16bc529b141c5c7967a9307cbc539c3fff8eab9f0789263fe lean-admission-audit release/evidence/lean_admission_audit_v173.json cabda2a1fb8c021ce384d9c2267f52f98e6799bb50b6b828e7d9eefa55bf2b2e diff --git a/release/build_package_linux.sh b/release/build_package_linux.sh index 8634116..79ebcb0 100755 --- a/release/build_package_linux.sh +++ b/release/build_package_linux.sh @@ -44,9 +44,8 @@ COMPILER=${JACKAL_ANUBIS_COMPILER_PATH:-} RANGE_CHECKER="$ROOT/proofs/lean/.lake/build/bin/jackal_cert_check" GAUSSIAN_CHECKER="$ROOT/proofs/lean/.lake/build/bin/jackal_gaussian_check" INT_CHECKER="$ROOT/proofs/lean/.lake/build/bin/jackal_int_cert_check" -V170_ARCHIVE_URL="https://github.com/AnubisQuantumCipher/jackal/releases/download/v1.7.0/jackal-v1.7.0-macos-arm64.tar.gz" V170_ARCHIVE_SHA256="21c7ede586f30a58772f321f7dbb36ab66213e199785489f99133710ac56096e" -V170_RANGE_CHECKER_SHA256="05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a" +V170_RANGE_CHECKER_SHA256="d515cdc2e66e53e46aef49ebb0d804a3ebd30d0b69fc7e8de7a3a19aac5170f2" V170_COVERAGE_INVENTORY_SHA256="18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6" V170_PLUGIN_HERMES_SHA256="d141c909e8f5f03e268a2112f291e6bd79fafff906522eb7ca9accc247a3274b" @@ -110,6 +109,7 @@ proofs/lean/.lake/build/bin/jackal_int_cert_check release/evidence/range_proof_identity_v172.json release/evidence/int_cert_proof_identity_v172.json release/evidence/range_proof_identity.json +release/evidence/range_proof_identity.linux-aarch64.json release/evidence/int_cert_proof_identity.json release/evidence/gaussian_proof_identity.json release/evidence/range_proof_identity_v172.linux-aarch64.json @@ -327,58 +327,24 @@ copy_file "$ROOT/release/coverage/formal_coverage_inventory.json" "$PKG/formal_c # Accept an operator-supplied local copy of the published archive, otherwise # fetch the public release asset, then verify the whole archive before reading # only the two named regular-file members. No archive path is extracted. -V170_ARCHIVE="$STAGE/jackal-v1.7.0-macos-arm64.tar.gz" -if [ -n "${JACKAL_V170_ARCHIVE:-}" ]; then - require_regular "$JACKAL_V170_ARCHIVE" - /bin/cp "$JACKAL_V170_ARCHIVE" "$V170_ARCHIVE" -else - /usr/bin/curl --fail --location --silent --show-error \ - --proto '=https' --tlsv1.2 \ - --connect-timeout 20 --max-time 900 \ - --retry 3 --retry-max-time 900 --retry-connrefused \ - "$V170_ARCHIVE_URL" --output "$V170_ARCHIVE" -fi -[ "$(sha256 "$V170_ARCHIVE")" = "$V170_ARCHIVE_SHA256" ] || { - echo "PACKAGE_V173_REFUSED reason=archival-archive-identity" >&2 +# Omarchy (Linux) edition: the archival v1.7.0 range checker is a natively +# rebuilt ELF, not the macOS release binary. Copy it and the platform-neutral +# archival coverage inventory from JACKAL_ARCHIVAL_DIR instead of downloading +# the Apple archive, so the package carries zero macOS bytes. +ARCHIVAL_DIR="${JACKAL_ARCHIVAL_DIR:?set JACKAL_ARCHIVAL_DIR to the native archival artifacts}" +require_regular "$ARCHIVAL_DIR/jackal_cert_check_v170" +require_regular "$ARCHIVAL_DIR/formal_coverage_inventory_v170.json" +[ "$(sha256 "$ARCHIVAL_DIR/jackal_cert_check_v170")" = "$V170_RANGE_CHECKER_SHA256" ] || { + echo "PACKAGE_V173_REFUSED reason=archival-checker-identity" >&2 exit 4 } -python3 -I -S -B - "$V170_ARCHIVE" "$PKG" \ - "$V170_RANGE_CHECKER_SHA256" "$V170_COVERAGE_INVENTORY_SHA256" <<'PY' -import hashlib -import os -import pathlib -import sys -import tarfile - -archive = pathlib.Path(sys.argv[1]) -package = pathlib.Path(sys.argv[2]) -expected = { - "jackal-v1.7.0-macos-arm64/jackal_cert_check": ( - package / "jackal_cert_check_v170", sys.argv[3], 0o755 - ), - "jackal-v1.7.0-macos-arm64/formal_coverage_inventory.json": ( - package / "evidence/formal_coverage_inventory_v170.json", sys.argv[4], - 0o644 - ), +[ "$(sha256 "$ARCHIVAL_DIR/formal_coverage_inventory_v170.json")" = "$V170_COVERAGE_INVENTORY_SHA256" ] || { + echo "PACKAGE_V173_REFUSED reason=archival-inventory-identity" >&2 + exit 4 } -with tarfile.open(archive, "r:gz") as bundle: - members = {member.name: member for member in bundle.getmembers()} - for name, (destination, digest, mode) in expected.items(): - member = members.get(name) - if member is None or not member.isfile() or member.size > 256 * 1024 * 1024: - raise SystemExit(f"archival-checker-member-refused:{name}") - source = bundle.extractfile(member) - if source is None: - raise SystemExit(f"archival-checker-read-refused:{name}") - data = source.read(256 * 1024 * 1024 + 1) - if len(data) != member.size or hashlib.sha256(data).hexdigest() != digest: - raise SystemExit(f"archival-checker-identity-refused:{name}") - with destination.open("xb") as output: - output.write(data) - output.flush() - os.fsync(output.fileno()) - destination.chmod(mode) -PY +/bin/cp "$ARCHIVAL_DIR/jackal_cert_check_v170" "$PKG/jackal_cert_check_v170" +/bin/chmod 0755 "$PKG/jackal_cert_check_v170" +/bin/cp "$ARCHIVAL_DIR/formal_coverage_inventory_v170.json" "$PKG/evidence/formal_coverage_inventory_v170.json" for relative in \ tests/release_validate.py \ @@ -433,7 +399,7 @@ copy_file "$ROOT/release/compat/v170_floor.json" "$PKG/evidence/compat_v170_floo copy_file "$ROOT/release/compat/v150_floor.json" "$PKG/evidence/compat_v150_floor.json" copy_file "$ROOT/release/evidence/range_ordering_aba_v172.json" "$PKG/evidence/range_ordering_aba_v172.json" copy_file "$ROOT/release/evidence/int_cert_premise_aba_v172.json" "$PKG/evidence/int_cert_premise_aba_v172.json" -copy_file "$ROOT/release/evidence/range_proof_identity.json" "$PKG/evidence/range_proof_identity_v1.json" +copy_file "$ROOT/release/evidence/range_proof_identity.linux-aarch64.json" "$PKG/evidence/range_proof_identity_v1.json" copy_file "$ROOT/release/evidence/int_cert_proof_identity.json" "$PKG/evidence/int_cert_proof_identity_v1.json" copy_file "$ROOT/release/evidence/range_proof_identity_v172.linux-aarch64.json" "$PKG/evidence/range_proof_identity_v172.json" copy_file "$ROOT/release/evidence/int_cert_proof_identity_v172.linux-aarch64.json" "$PKG/evidence/int_cert_proof_identity_v172.json" diff --git a/release/compat/v172_floor.linux-aarch64.json b/release/compat/v172_floor.linux-aarch64.json index 38d45d0..d748433 100644 --- a/release/compat/v172_floor.linux-aarch64.json +++ b/release/compat/v172_floor.linux-aarch64.json @@ -30,9 +30,9 @@ "v1.5.0" ], "checker_file": "jackal_cert_check_v170", - "checker_sha256": "05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a", + "checker_sha256": "d515cdc2e66e53e46aef49ebb0d804a3ebd30d0b69fc7e8de7a3a19aac5170f2", "identity_file": "release/evidence/range_proof_identity.json", - "identity_file_sha256": "1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67", + "identity_file_sha256": "4b1c2958481e1047551c42b8f23a827a8422ad9e8881ec913ec88a4cd95b44f2", "inventory_file": "release/coverage/formal_coverage_inventory_v170.json", "inventory_file_sha256": "18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6", "mode": "replay-only", @@ -54,9 +54,9 @@ "v1.5.0" ], "checker_file": "jackal_cert_check_v170", - "checker_sha256": "05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a", + "checker_sha256": "d515cdc2e66e53e46aef49ebb0d804a3ebd30d0b69fc7e8de7a3a19aac5170f2", "identity_file": "release/evidence/range_proof_identity.json", - "identity_file_sha256": "1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67", + "identity_file_sha256": "4b1c2958481e1047551c42b8f23a827a8422ad9e8881ec913ec88a4cd95b44f2", "inventory_file": "release/coverage/formal_coverage_inventory_v170.json", "inventory_file_sha256": "18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6", "mode": "replay-only", diff --git a/release/evidence/archival_range_checker.linux-aarch64 b/release/evidence/archival_range_checker.linux-aarch64 new file mode 100644 index 0000000..5cca6fa --- /dev/null +++ b/release/evidence/archival_range_checker.linux-aarch64 @@ -0,0 +1 @@ +d515cdc2e66e53e46aef49ebb0d804a3ebd30d0b69fc7e8de7a3a19aac5170f2 \ No newline at end of file diff --git a/release/evidence/range_proof_identity.linux-aarch64.json b/release/evidence/range_proof_identity.linux-aarch64.json new file mode 100644 index 0000000..ba7a816 --- /dev/null +++ b/release/evidence/range_proof_identity.linux-aarch64.json @@ -0,0 +1,550 @@ +{ + "build_attestation": { + "attestation_digest_sha256": "9f8620e36761804c6d9895d83a7b468e4ecb5763bad26ab90edead0cd823ad27", + "authentication": { + "authenticated": false, + "scheme": "none", + "statement": "This deterministic record binds observed checker bytes to named inputs. It is not a signature and does not authenticate the builder or artifact." + }, + "build_command": [ + "lake", + "build", + "jackal_cert_check" + ], + "checker": { + "bytes": 181565968, + "path": "proofs/lean/.lake/build/bin/jackal_cert_check", + "sha256": "d515cdc2e66e53e46aef49ebb0d804a3ebd30d0b69fc7e8de7a3a19aac5170f2", + "target": "jackal_cert_check" + }, + "claim_boundary": "This is reproducibility/build-provenance evidence, not a proof of compiler, linker, operating-system, hardware, or supply-chain correctness.", + "compiler_observed_for_build_platform": { + "build": "Release", + "commit": "8c9756b28d64dab099da31a4c09229a9e6a2ef35", + "executable_bytes": 13824, + "executable_sha256": "79fb1d26fa5a39385d59fdc48a711a14b0710ca6480271acce99b4d177cea085", + "target": "aarch64-unknown-linux-gnu", + "version": "4.32.0" + }, + "inputs": { + "lean_commit": "8c9756b28d64dab099da31a4c09229a9e6a2ef35", + "mathlib_commit": "81a5d257c8e410db227a6665ed08f64fea08e997", + "source_closure_sha256": "8e8f00e71c554b81f63b7e604151e621370ae5cb4fe706d598024f4de1b90c2c", + "toolchain_configuration": [ + { + "path": "proofs/lean/lakefile.toml", + "sha256": "21eef36ea0d9a665622b171dcf1f96460aa250ef214314d766112e01dadf1eaf" + }, + { + "path": "proofs/lean/lake-manifest.json", + "sha256": "f521808691ba1ab175c5cdeec098a76586d345fea93370a38c2d2b73645f69d4" + }, + { + "path": "proofs/lean/lean-toolchain", + "sha256": "2773c517aa90b66ea8a2c52bddddf84393157797f8341be0df45294fff7fd32e" + } + ] + }, + "kind": "unsigned-local-build-binding-v1", + "working_directory": "proofs/lean" + }, + "checker": { + "bytes": 181565968, + "path": "proofs/lean/.lake/build/bin/jackal_cert_check", + "sha256": "d515cdc2e66e53e46aef49ebb0d804a3ebd30d0b69fc7e8de7a3a19aac5170f2", + "target": "jackal_cert_check" + }, + "fragment": { + "assurance": "formal-bounded", + "certificate_magic": "jackal-eval-cert v2", + "checker_boolean_definition": "JackalIv.Cert.checkCert", + "checker_entrypoint_definition": "runRequestBound", + "checker_executable": "jackal_cert_check", + "family": "range-request-bound-v1", + "lane": "range", + "parser_definition": "JackalIv.Cert.parseCert", + "premises_not_discharged_by_checker": [ + "ModelTCB hdr nodes = LibmModel hdr nodes ∧ ConstTCB nodes", + "input interval ordering ((input_lo : ℚ) : ℝ) ≤ (input_hi : ℚ) : ℝ" + ], + "request_matcher_definition": "JackalIv.Cert.requestMatches", + "runtime_alternate_implementation_boundary": "request acceptance uses no implemented_by definition; two exact dump-only implemented_by attributes elsewhere in the imported closure are pinned", + "soundness_theorem": "JackalIv.Cert.request_bound_certified_release", + "theorem_premises": [ + "requestMatches command rawExpr rawLo rawHi hdr nodes = true (runtime checked)", + "checkCert hdr nodes = true (runtime checked)", + "ModelTCB hdr nodes", + "((hdr.input_lo : ℚ) : ℝ) ≤ ((hdr.input_hi : ℚ) : ℝ)" + ] + }, + "generator": { + "path": "release/tools/gaussian_proof_identity.py", + "sha256": "05bfa1709b0968da37b95c3d80c619de003ee4ba6987f6cea2844293fa8e4ccd" + }, + "identity_digest_sha256": "022c19e317e68049e48b69bfa8567f4ba617610aa5a6bf3c59d8c9a98995c518", + "proof": { + "axiom_audit_command": "lake env lean /dev/stdin with checked-in #print axioms set", + "axiom_policy": { + "allowed_exactly": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "forbidden": [ + "sorryAx", + "any additional axiom" + ] + }, + "theorems": [ + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "theorem": "JackalIv.Cert.request_bound_certified_release" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "theorem": "JackalIv.Cert.requestMatches_true" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "theorem": "JackalIv.Cert.lowerRaw_toExpr" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "theorem": "JackalIv.Cert.rawExprOf_toExpr" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "theorem": "JackalIv.Cert.cert_check_sound" + }, + { + "axioms": [ + "propext", + "Classical.choice", + "Quot.sound" + ], + "theorem": "JackalIv.parse_lower_encloses" + } + ] + }, + "schema": "jackal-range-proof-identity-v1", + "source_closure": { + "aggregate_sha256": "8e8f00e71c554b81f63b7e604151e621370ae5cb4fe706d598024f4de1b90c2c", + "definition": "Every repository-local transitive Lean import reachable from root_modules; external imports are bound through lake-manifest.json and named here.", + "external_imports": [ + "Mathlib", + "Mathlib.Analysis.Complex.Exponential", + "Mathlib.Analysis.Real.Pi.Bounds", + "Mathlib.Analysis.SpecialFunctions.Trigonometric.Arctan", + "Mathlib.Analysis.SpecialFunctions.Trigonometric.Bounds" + ], + "files": [ + { + "bytes": 11165, + "imports": [ + "JackalIv.Model", + "JackalIv.Pad" + ], + "module": "JackalIv.Arith", + "path": "proofs/lean/JackalIv/Arith.lean", + "sha256": "2bc091be9dd47acae8d4b8af7b272827a3cea7b5ec08773566ad8fe40a12bf83" + }, + { + "bytes": 27102, + "imports": [ + "JackalIv.CertTypes", + "JackalIv.Gaussian", + "JackalIv.Transcend" + ], + "module": "JackalIv.CertCheck", + "path": "proofs/lean/JackalIv/CertCheck.lean", + "sha256": "02cec1630ed5f822f226155e0d4b7c1b62acf056826b03e5e8b191544789b6de" + }, + { + "bytes": 3753, + "imports": [ + "JackalIv.CertRequest" + ], + "module": "JackalIv.CertCheckMain", + "path": "proofs/lean/JackalIv/CertCheckMain.lean", + "sha256": "433ef0b15add892020e57932fad5c0b9c376273b132bb94bb293d262ca2a7a8e" + }, + { + "bytes": 54454, + "imports": [ + "JackalIv.CertCheck" + ], + "module": "JackalIv.CertCodec", + "path": "proofs/lean/JackalIv/CertCodec.lean", + "sha256": "66ac121b53dd12ec395dbd88ddf16f726bf3afdb4946f1f4deabee8af001cd9d" + }, + { + "bytes": 28768, + "imports": [ + "JackalIv.CertCodec", + "JackalIv.CertSound", + "JackalIv.Correspondence" + ], + "module": "JackalIv.CertRequest", + "path": "proofs/lean/JackalIv/CertRequest.lean", + "sha256": "775e229a0b7e7a799db034f1a147271aa6ec35f6015e13c20f772ee0206a8d3f" + }, + { + "bytes": 52899, + "imports": [ + "JackalIv.CertCheck", + "JackalIv.Embed" + ], + "module": "JackalIv.CertSound", + "path": "proofs/lean/JackalIv/CertSound.lean", + "sha256": "bc602fc99d0652fb78de65488065337000ac5fa78038273d22abc702215a0ec9" + }, + { + "bytes": 16791, + "imports": [ + "JackalIv.Syntax" + ], + "module": "JackalIv.CertTypes", + "path": "proofs/lean/JackalIv/CertTypes.lean", + "sha256": "0f241bce34f817a1f415d9722d0c34652cb4f312b7261d842b4000b23d7b4139" + }, + { + "bytes": 6139, + "imports": [ + "JackalIv.Parser", + "JackalIv.Lower", + "JackalIv.Dump", + "JackalIv.Embed" + ], + "module": "JackalIv.Correspondence", + "path": "proofs/lean/JackalIv/Correspondence.lean", + "sha256": "2b4acd4c904c8069f65a230eabf5bd1cacc0c73d077df650bbf12a24c12b18f3" + }, + { + "bytes": 12026, + "imports": [ + "JackalIv.Parser" + ], + "module": "JackalIv.Dump", + "path": "proofs/lean/JackalIv/Dump.lean", + "sha256": "3baba94104288e5783c763723f9582a25db40131849a41e743669cfac8445495" + }, + { + "bytes": 33040, + "imports": [ + "JackalIv.Syntax", + "JackalIv.Gaussian" + ], + "module": "JackalIv.Embed", + "path": "proofs/lean/JackalIv/Embed.lean", + "sha256": "0a1ff6ddbcea4ca9d36ad3ae099ac361bd2e863250f42e4b3fecac6d79b4947c" + }, + { + "bytes": 17004, + "imports": [ + "JackalIv.Model", + "JackalIv.Pad", + "JackalIv.Arith", + "JackalIv.Monotone", + "JackalIv.Pow" + ], + "module": "JackalIv.Exact", + "path": "proofs/lean/JackalIv/Exact.lean", + "sha256": "a4c0f493b0d69b1a9756205d7b61f5852bde225a5fe532140ec178b97576ce28" + }, + { + "bytes": 7290, + "imports": [ + "JackalIv.Taylor", + "Mathlib.Analysis.Complex.Exponential" + ], + "module": "JackalIv.Gaussian", + "path": "proofs/lean/JackalIv/Gaussian.lean", + "sha256": "2aaaaa895141dab699f6cd936639948976e9560c07d015708e02545b02a045fe" + }, + { + "bytes": 17818, + "imports": [ + "JackalIv.Syntax" + ], + "module": "JackalIv.Lower", + "path": "proofs/lean/JackalIv/Lower.lean", + "sha256": "32d7f453bee0ddc1999b2693f8bb9bdb9706976172e29a120e23aa118409d9f2" + }, + { + "bytes": 3704, + "imports": [ + "Mathlib" + ], + "module": "JackalIv.Model", + "path": "proofs/lean/JackalIv/Model.lean", + "sha256": "81b13207259c86ccd816cf3d93dd70f11cc042722f2b42320b61ec7a301cb306" + }, + { + "bytes": 6837, + "imports": [ + "JackalIv.Model", + "JackalIv.Pad" + ], + "module": "JackalIv.Monotone", + "path": "proofs/lean/JackalIv/Monotone.lean", + "sha256": "87f262d6f0fb7d60b7ea1fdc716c95625c6131830aee0e2d5a45d62397533a8e" + }, + { + "bytes": 4695, + "imports": [ + "JackalIv.Model" + ], + "module": "JackalIv.Pad", + "path": "proofs/lean/JackalIv/Pad.lean", + "sha256": "82cce18646e2522695fec7c68796f9a60a85abc20b6bfe1c45dac8070578c5d1" + }, + { + "bytes": 23310, + "imports": [ + "JackalIv.Syntax" + ], + "module": "JackalIv.Parser", + "path": "proofs/lean/JackalIv/Parser.lean", + "sha256": "fe5d803c7af09e36d1543517921af618351390f49ebbb46f0ecc1f79b2a86cc3" + }, + { + "bytes": 11388, + "imports": [ + "JackalIv.Model", + "JackalIv.Pad", + "JackalIv.Arith" + ], + "module": "JackalIv.Pow", + "path": "proofs/lean/JackalIv/Pow.lean", + "sha256": "0d80581069c3934274ca4992c6c07867e10821c8fedc43ec6c6fedd6e0971332" + }, + { + "bytes": 17044, + "imports": [ + "JackalIv.Model", + "JackalIv.Pad", + "JackalIv.Arith", + "JackalIv.Monotone", + "JackalIv.Exact", + "JackalIv.Pow", + "JackalIv.Trig" + ], + "module": "JackalIv.Syntax", + "path": "proofs/lean/JackalIv/Syntax.lean", + "sha256": "552bf222b26a615b779a5f0c8abf44beb258609551b158ee3141729dedcf7651" + }, + { + "bytes": 25406, + "imports": [ + "JackalIv.Model", + "JackalIv.Pad" + ], + "module": "JackalIv.Taylor", + "path": "proofs/lean/JackalIv/Taylor.lean", + "sha256": "b3a5c2bbb8374b845624f13fc66b7cb8ad0bf0ca987c6b923631f3ea275febd2" + }, + { + "bytes": 20215, + "imports": [ + "JackalIv.Gaussian", + "Mathlib.Analysis.SpecialFunctions.Trigonometric.Bounds", + "Mathlib.Analysis.SpecialFunctions.Trigonometric.Arctan", + "Mathlib.Analysis.Real.Pi.Bounds" + ], + "module": "JackalIv.Transcend", + "path": "proofs/lean/JackalIv/Transcend.lean", + "sha256": "2fce308fdf161d6fc1edb3d41cb0148e6d8544ab0954a17a7c29ae915a7f1569" + }, + { + "bytes": 24529, + "imports": [ + "JackalIv.Model", + "JackalIv.Pad" + ], + "module": "JackalIv.Trig", + "path": "proofs/lean/JackalIv/Trig.lean", + "sha256": "c65e6db19679c0081d833d4a15cf9d46b4f73e395ed7564505fc0c2e586078d4" + } + ], + "local_construct_policy": { + "allowed_exact_source_lines": [ + { + "construct": "implemented_by", + "path": "proofs/lean/JackalIv/Correspondence.lean", + "source_lines": [ + "@[implemented_by Dump.parseSexpImpl]", + "@[implemented_by Dump.lowerSexpImpl]" + ] + } + ], + "forbidden_by_default": [ + "admit", + "axiom_declaration", + "extern", + "implemented_by", + "native_decide", + "partial", + "sorry", + "unsafe" + ] + }, + "root_modules": [ + "JackalIv.CertCheckMain" + ] + }, + "toolchain": { + "configuration_files": [ + { + "path": "proofs/lean/lakefile.toml", + "sha256": "21eef36ea0d9a665622b171dcf1f96460aa250ef214314d766112e01dadf1eaf" + }, + { + "path": "proofs/lean/lake-manifest.json", + "sha256": "f521808691ba1ab175c5cdeec098a76586d345fea93370a38c2d2b73645f69d4" + }, + { + "path": "proofs/lean/lean-toolchain", + "sha256": "2773c517aa90b66ea8a2c52bddddf84393157797f8341be0df45294fff7fd32e" + } + ], + "lake_version": "Lake version 5.0.0-src+8c9756b (Lean version 4.32.0)", + "lean": { + "build": "Release", + "commit": "8c9756b28d64dab099da31a4c09229a9e6a2ef35", + "version": "4.32.0" + }, + "lean_toolchain": "leanprover/lean4:v4.32.0", + "manifest_packages": [ + { + "config_file": "lakefile.toml", + "inherited": true, + "input_revision": "v4.32.0", + "manifest_file": "lake-manifest.json", + "name": "Cli", + "revision": "88679d088c9720c27ebdf2ba4dafe17341747f94", + "scope": "leanprover", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover/lean4-cli" + }, + { + "config_file": "lakefile.toml", + "inherited": true, + "input_revision": "main", + "manifest_file": "lake-manifest.json", + "name": "LeanSearchClient", + "revision": "c5d5b8fe6e5158def25cd28eb94e4141ad97c843", + "scope": "leanprover-community", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover-community/LeanSearchClient" + }, + { + "config_file": "lakefile.toml", + "inherited": true, + "input_revision": "master", + "manifest_file": "lake-manifest.json", + "name": "Qq", + "revision": "38d591e778f100aec9762bb582f9c7f55f50e9dc", + "scope": "leanprover-community", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover-community/quote4" + }, + { + "config_file": "lakefile.toml", + "inherited": true, + "input_revision": "master", + "manifest_file": "lake-manifest.json", + "name": "aesop", + "revision": "a7dbf0c63b694e47f425f3dcddbc0e178bb432d3", + "scope": "leanprover-community", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover-community/aesop" + }, + { + "config_file": "lakefile.toml", + "inherited": true, + "input_revision": "main", + "manifest_file": "lake-manifest.json", + "name": "batteries", + "revision": "023ce7d62a0531e22a5331e20b587817a80d49ff", + "scope": "leanprover-community", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover-community/batteries" + }, + { + "config_file": "lakefile.toml", + "inherited": true, + "input_revision": "main", + "manifest_file": "lake-manifest.json", + "name": "importGraph", + "revision": "7e9612bf0b9ee66db3cb5b9988a35afc706f5a12", + "scope": "leanprover-community", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover-community/import-graph" + }, + { + "config_file": "lakefile.lean", + "inherited": false, + "input_revision": "v4.32.0", + "manifest_file": "lake-manifest.json", + "name": "mathlib", + "revision": "81a5d257c8e410db227a6665ed08f64fea08e997", + "scope": "", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover-community/mathlib4" + }, + { + "config_file": "lakefile.toml", + "inherited": true, + "input_revision": "main", + "manifest_file": "lake-manifest.json", + "name": "plausible", + "revision": "e12c1910fe855cbfc38803cd4e55543906d5fa62", + "scope": "leanprover-community", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover-community/plausible" + }, + { + "config_file": "lakefile.lean", + "inherited": true, + "input_revision": "main", + "manifest_file": "lake-manifest.json", + "name": "proofwidgets", + "revision": "6e311e2a844da9b2cc3971187df2fe0066947b93", + "scope": "leanprover-community", + "subdirectory": null, + "type": "git", + "url": "https://github.com/leanprover-community/ProofWidgets4" + } + ], + "mathlib_commit": "81a5d257c8e410db227a6665ed08f64fea08e997", + "package_checkout_policy": "Every git package checkout is clean and its HEAD equals its full lake-manifest revision during generation and verification." + } +} diff --git a/release/tools/repin_linux.py b/release/tools/repin_linux.py index 23b15db..222d60f 100755 --- a/release/tools/repin_linux.py +++ b/release/tools/repin_linux.py @@ -44,6 +44,7 @@ "range-proof-identity": ("range_proof_identity_v172", "range-proof-digest"), "gaussian-proof-identity": ("gaussian_proof_identity", "gaussian-proof-digest"), "int-cert-proof-identity": ("int_cert_proof_identity_v172", "int-cert-proof-digest"), + "archival-range-proof-identity": ("range_proof_identity", "archival-range-proof-digest"), } EVIDENCE_DIR = "release/evidence" @@ -80,6 +81,15 @@ def build_manifest() -> str: comp_sha = sha256(comp) tag = host_tag() + # Omarchy edition rebinds the archival v1.7.0 range checker row to the + # natively rebuilt checker named by release/evidence/archival_range_checker.. + archival_marker = ROOT / EVIDENCE_DIR / f"archival_range_checker.{tag}" + archival_sha = None + if archival_marker.is_file(): + text = archival_marker.read_text().strip() + if len(text) == 64: + archival_sha = text + def host_evidence(base: str) -> Path | None: candidate = ROOT / EVIDENCE_DIR / f"{base}.{tag}.json" return candidate if candidate.is_file() else None @@ -123,6 +133,9 @@ def host_evidence(base: str) -> Path | None: out.append(f"{label} {rel} {sha256(ev)}") elif label in digest_overrides: out.append(f"{label} {digest_overrides[label]}") + elif label == "archival-range-checker" and archival_sha is not None: + name = line.split()[1] + out.append(f"{label} {name} {archival_sha}") else: out.append(line) missing = set(BINARY_ROWS) - seen_binary diff --git a/tools/formal_receipt.py b/tools/formal_receipt.py index a73e095..eb386e9 100755 --- a/tools/formal_receipt.py +++ b/tools/formal_receipt.py @@ -471,9 +471,27 @@ def write_new_file_atomic(path: str | Path, data: bytes, mode: int = 0o600) -> P RANGE_ARCHIVAL_RELEASE_EPOCHS = frozenset({"v1.5.0"}) RATIONAL_ARCHIVAL_RELEASE_EPOCHS = RANGE_ARCHIVAL_RELEASE_EPOCHS INT_CERT_ARCHIVAL_RELEASE_EPOCHS = frozenset() -ARCHIVAL_RANGE_CHECKER_SHA256 = ( - "05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a" -) +def _host_archival_range_checker_sha256() -> str: + """Archival v1.7.0 range checker identity for this host. + + The Omarchy (Linux) edition ships a natively rebuilt v1.7.0 checker; macOS + keeps the original release bytes. A host-suffixed evidence marker selects + the native identity when present. + """ + try: + import platform as _platform + if _platform.system() != "Darwin": + marker = Path(__file__).resolve().parent.parent / "release" / "evidence" / f"archival_range_checker.{_platform.system().lower()}-{_platform.machine().lower()}" + if marker.is_file(): + text = marker.read_text().strip() + if len(text) == 64: + return text + except OSError: + pass + return "05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a" + + +ARCHIVAL_RANGE_CHECKER_SHA256 = _host_archival_range_checker_sha256() ARCHIVAL_RANGE_INVENTORY_FILE = ( "release/coverage/formal_coverage_inventory_v170.json" ) @@ -506,7 +524,10 @@ def _host_current_identity_sha(base_filename: str, macos_default: str) -> str: _PROOF_COMPATIBILITY = { ("range", RANGE_PROOF_IDENTITY_V1_SCHEMA, "v1.5.0"): { - "file_sha256": "1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67", + "file_sha256": _host_current_identity_sha( + "range_proof_identity.json", + "1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67", + ), "mode": "replay-only", "checker_sha256": ARCHIVAL_RANGE_CHECKER_SHA256, "theorem": "JackalIv.Cert.request_bound_certified_release", From f541ce62e5cdff1a03d72fb01cfe3c2d0e8ad4ac Mon Sep 17 00:00:00 2001 From: sicarii Date: Sun, 23 Aug 2026 23:36:52 -0400 Subject: [PATCH 04/22] Declare linux-x86_64 architecture gate (execution pending) Adds ("Linux","x86_64") to SUPPORTED_HOSTS with a null RELEASE_PIN so the host is recognized and provisioning refuses "no published release asset for host linux-x86_64" until a native x86_64 package is built and OBSERVED on x86_64 hardware (planned bare-metal iMac Pro). No x86_64 function is claimed. The aarch64/x86_64 arch-substitution refusal follows from the per-host pin/directory binding. Plugin identity regenerated for the changed provisioner. Part of the Omarchy JACKAL native-product mission: architecture gate for a versioned Linux product with architecture-specific native artifacts, not an aarch64-only fork. Co-Authored-By: Claude Opus 4.8 --- plugins/jackel/PLUGIN_IDENTITY.sha256 | 2 +- plugins/jackel/scripts/provision_runtime.py | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/plugins/jackel/PLUGIN_IDENTITY.sha256 b/plugins/jackel/PLUGIN_IDENTITY.sha256 index b835790..09227bc 100644 --- a/plugins/jackel/PLUGIN_IDENTITY.sha256 +++ b/plugins/jackel/PLUGIN_IDENTITY.sha256 @@ -4,6 +4,6 @@ a165e6b00292a3768ad134562539dabf7874cf23bf9ac8f80e893f7970a63cdc .mcp.json b5916270588db1fbb68b4d520c5f5e9d0fabb84e26602f18ad0a2927a38cece9 mcp/server.py e4fb2996fc2a905a5101974ad6119e6c29fbc10cc8ca2f0223e18f89686dcdff scripts/launch_mcp.sh 878a9d94788a6c132fad151bbddebecb41c08615fe310278e586871fe8f9c44c scripts/launch_mcp.zsh -916a8f4279f99954f21ab20e2b4281457ced54da153adf95618491c1afb9cced scripts/provision_runtime.py +66ee96ecbaddee96c2eedf9c94d938be21da322e46f42cef3845b60e6995af53 scripts/provision_runtime.py 60f6a068c5f6bd81a2ab80e8d9d873864aefdf7f6ae7c2db37fe6572b41f898f scripts/verify_plugin.py 63f726fbde9e4484424388ef5af68dce92d7f55a4af9354e7d812833f090c972 skills/jackel/SKILL.md diff --git a/plugins/jackel/scripts/provision_runtime.py b/plugins/jackel/scripts/provision_runtime.py index 4b0e218..bc8181f 100644 --- a/plugins/jackel/scripts/provision_runtime.py +++ b/plugins/jackel/scripts/provision_runtime.py @@ -43,6 +43,7 @@ SUPPORTED_HOSTS = { ("Darwin", "arm64"): "macos-arm64", ("Linux", "aarch64"): "linux-aarch64", + ("Linux", "x86_64"): "linux-x86_64", } # ``None`` means "this host is supported by the installer but no release asset @@ -69,6 +70,10 @@ "sha256sums_sha256": "0492872b881d2ea1d84a4b14c4332fc74dccdeb78cc60ff317b05e27ac50c744", "package_directory": "jackal-v1.7.3-linux-aarch64", }, + # Gate declared for the planned bare-metal Linux x86_64 (iMac Pro). No pin + # and no function claimed until a native package is built and OBSERVED on + # x86_64 hardware or an explicitly authorized x86_64 substrate. + "linux-x86_64": None, } MAX_ARCHIVE_MEMBERS = 8192 MAX_RUNTIME_RECORDS = MAX_ARCHIVE_MEMBERS From 1c79aa17f4c21dd36499e9f9dfb8578197e3369b Mon Sep 17 00:00:00 2001 From: sicarii Date: Mon, 24 Aug 2026 00:42:06 -0400 Subject: [PATCH 05/22] Admit architecture-qualified Z3 4.15.4 anchor for Linux aarch64 (bounded sign-off) Under the architect's 2026-08-23 bounded sign-off: admit a native Linux aarch64 Z3 4.15.4 as a separate architecture-qualified program-evidence trust anchor. The guest's system Z3 4.16.0 is NOT admitted. - Z3 4.15.4 pinned from official source (archive dae52625, tree 0e4123f4, version verified), independently double-built byte-identical (b6fcd93b) in two isolated directories under a recorded deterministic recipe; native aarch64 ELF, no dependency on the guest 4.16.0. - tools/anubis_program_verify.py: host-aware _approved_z3_for_host() selects the Darwin anchor (preserved EXACTLY) or the Linux aarch64 anchor (b6fcd93b), enforcing exact digest + semver 4.15.4 + no-symlink + owner/mode + single-snapshot identity. The inventory-safe-v1 policy body is byte-frozen (POLICY_SHA256 1b94350a unchanged); no verification semantics, residual, or refusal is loosened. - Negative controls verified: Linux 4.16.0 refused (z3-identity-mismatch), symlink/one-byte-tamper/world-writable refused, pristine restores (A->B->A). - The approved Z3 is shipped in the package (jackal_z3_v4154) and pinned in the Linux manifest (approved-z3-linux-aarch64); build_package_linux.sh copies it from JACKAL_Z3_DIR; repin_linux appends the anchor row. - jackal_anubis_verify_program + verify_program_receipt now PASS from the installed package with all six residuals open and the artifact never executed. The shared verifier hash change updates the anubis_program_verifier row in both manifests and the capability inventory (authorized; macOS proof/checker/floor and the inventory-safe-v1 policy body remain byte-identical to baseline). jackal_anubis_check_program remains BLOCKED on the SEPARATE approved-check-compiler anchor, which this Z3 sign-off does not authorize. Co-Authored-By: Claude Opus 4.8 --- plugins/jackel/PLUGIN_IDENTITY.sha256 | 2 +- plugins/jackel/scripts/provision_runtime.py | 8 +-- release/MANIFEST.linux-aarch64.sha256 | 3 +- release/MANIFEST.sha256 | 2 +- release/build_package_linux.sh | 14 +++++ release/capability_inventory_v1.json | 2 +- release/evidence/approved_z3.linux-aarch64 | 1 + release/tools/repin_linux.py | 6 ++ tools/anubis_program_verify.py | 64 ++++++++++++++++++++- 9 files changed, 91 insertions(+), 11 deletions(-) create mode 100644 release/evidence/approved_z3.linux-aarch64 diff --git a/plugins/jackel/PLUGIN_IDENTITY.sha256 b/plugins/jackel/PLUGIN_IDENTITY.sha256 index 09227bc..7ce20fe 100644 --- a/plugins/jackel/PLUGIN_IDENTITY.sha256 +++ b/plugins/jackel/PLUGIN_IDENTITY.sha256 @@ -4,6 +4,6 @@ a165e6b00292a3768ad134562539dabf7874cf23bf9ac8f80e893f7970a63cdc .mcp.json b5916270588db1fbb68b4d520c5f5e9d0fabb84e26602f18ad0a2927a38cece9 mcp/server.py e4fb2996fc2a905a5101974ad6119e6c29fbc10cc8ca2f0223e18f89686dcdff scripts/launch_mcp.sh 878a9d94788a6c132fad151bbddebecb41c08615fe310278e586871fe8f9c44c scripts/launch_mcp.zsh -66ee96ecbaddee96c2eedf9c94d938be21da322e46f42cef3845b60e6995af53 scripts/provision_runtime.py +5308729c795255063f852967b3c2374ec4145ea42989dd669d2fcfa856324177 scripts/provision_runtime.py 60f6a068c5f6bd81a2ab80e8d9d873864aefdf7f6ae7c2db37fe6572b41f898f scripts/verify_plugin.py 63f726fbde9e4484424388ef5af68dce92d7f55a4af9354e7d812833f090c972 skills/jackel/SKILL.md diff --git a/plugins/jackel/scripts/provision_runtime.py b/plugins/jackel/scripts/provision_runtime.py index bc8181f..71c4f5f 100644 --- a/plugins/jackel/scripts/provision_runtime.py +++ b/plugins/jackel/scripts/provision_runtime.py @@ -64,10 +64,10 @@ # upstream asset — install with `provision --tarball `. "asset": "jackal-v1.7.3-linux-aarch64.tar.gz", "url": None, - "package_size": 183743522, - "package_sha256": "a0ad634be9db97b31294ce5e62267a96583da03783a04d496af35c9df5530b1c", - "extracted_size": 730019814, - "sha256sums_sha256": "0492872b881d2ea1d84a4b14c4332fc74dccdeb78cc60ff317b05e27ac50c744", + "package_size": 199147947, + "package_sha256": "17f917cac0866dbbf71bbdf1505a0efe479eb7604e807a1713acb96f6bb29989", + "extracted_size": 765433623, + "sha256sums_sha256": "ff40b2f37fa5d449e0f07ed604d5779d14f495aeb8707199b2e19ae67cb70972", "package_directory": "jackal-v1.7.3-linux-aarch64", }, # Gate declared for the planned bare-metal Linux x86_64 (iMac Pro). No pin diff --git a/release/MANIFEST.linux-aarch64.sha256 b/release/MANIFEST.linux-aarch64.sha256 index 527de7c..d38f691 100644 --- a/release/MANIFEST.linux-aarch64.sha256 +++ b/release/MANIFEST.linux-aarch64.sha256 @@ -43,7 +43,8 @@ domain_pack_registry domain_packs/registry_v1.json b71fb06d36cdee13e7fbf271a80df domain_pack_verifier tools/domain_pack_verify.py 53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b domain_pack_test_exists_checker tools/test_exists_verify.py 598cb99e1eb70c9410ca87345efee346f73e43aaf3625427dca17ea04231caea domain_pack_decision_checker tools/decision_verify.py f1ad7c9fbd4c1d899dbb4bebabbbeb97e97a56bd4b279ad7d8ec3722bf12e0f6 -anubis_program_verifier tools/anubis_program_verify.py 4b80e29bdffc0737f05a6e215fce8cce3b6b828c24afbf55c68443399e5119dc +anubis_program_verifier tools/anubis_program_verify.py 867f4bba40ce3f343d3f6a0be6ff35bc8135b08119e2506912d43dd1758a04e7 anubis_program_policy release/program/inventory_safe_v1.json 361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb claim_inference_registry release/claim/inference_registry_v1.json c70b33d5aee8071b5125e6a5f8ffe5226fc22a137d920c17d9b3463968be13f0 claim_unit_registry release/claim/unit_registry_v1.json d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c +approved-z3-linux-aarch64 jackal_z3_v4154 b6fcd93b2ccec9aa848ac148c4d9b4270577ad046601f211784586eb9f0135c4 diff --git a/release/MANIFEST.sha256 b/release/MANIFEST.sha256 index 3b8abf7..b0609a7 100644 --- a/release/MANIFEST.sha256 +++ b/release/MANIFEST.sha256 @@ -43,7 +43,7 @@ domain_pack_registry domain_packs/registry_v1.json b71fb06d36cdee13e7fbf271a80df domain_pack_verifier tools/domain_pack_verify.py 53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b domain_pack_test_exists_checker tools/test_exists_verify.py 598cb99e1eb70c9410ca87345efee346f73e43aaf3625427dca17ea04231caea domain_pack_decision_checker tools/decision_verify.py f1ad7c9fbd4c1d899dbb4bebabbbeb97e97a56bd4b279ad7d8ec3722bf12e0f6 -anubis_program_verifier tools/anubis_program_verify.py 4b80e29bdffc0737f05a6e215fce8cce3b6b828c24afbf55c68443399e5119dc +anubis_program_verifier tools/anubis_program_verify.py 867f4bba40ce3f343d3f6a0be6ff35bc8135b08119e2506912d43dd1758a04e7 anubis_program_policy release/program/inventory_safe_v1.json 361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb claim_inference_registry release/claim/inference_registry_v1.json c70b33d5aee8071b5125e6a5f8ffe5226fc22a137d920c17d9b3463968be13f0 claim_unit_registry release/claim/unit_registry_v1.json d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c diff --git a/release/build_package_linux.sh b/release/build_package_linux.sh index 79ebcb0..e27b8b8 100755 --- a/release/build_package_linux.sh +++ b/release/build_package_linux.sh @@ -346,6 +346,19 @@ require_regular "$ARCHIVAL_DIR/formal_coverage_inventory_v170.json" /bin/chmod 0755 "$PKG/jackal_cert_check_v170" /bin/cp "$ARCHIVAL_DIR/formal_coverage_inventory_v170.json" "$PKG/evidence/formal_coverage_inventory_v170.json" +# Omarchy edition: ship the architecture-qualified approved Z3 4.15.4 (native +# double-built ELF) as a package member the program-evidence verifier resolves +# as its sibling. Verified against the manifest-pinned identity. +Z3DIR="${JACKAL_Z3_DIR:?set JACKAL_Z3_DIR to the approved native Z3 4.15.4}" +require_regular "$Z3DIR/jackal_z3_v4154" +APPROVED_Z3_SHA256="b6fcd93b2ccec9aa848ac148c4d9b4270577ad046601f211784586eb9f0135c4" +[ "$(sha256 "$Z3DIR/jackal_z3_v4154")" = "$APPROVED_Z3_SHA256" ] || { + echo "PACKAGE_V173_REFUSED reason=approved-z3-identity observed=$(sha256 "$Z3DIR/jackal_z3_v4154")" >&2 + exit 4 +} +/bin/cp "$Z3DIR/jackal_z3_v4154" "$PKG/jackal_z3_v4154" +/bin/chmod 0755 "$PKG/jackal_z3_v4154" + for relative in \ tests/release_validate.py \ tools/gaussian_certificate.py tools/gaussian_release.py \ @@ -725,6 +738,7 @@ domain_pack_test_exists_checker tools/test_exists_verify.py $(sha256 "$PKG/tools domain_pack_decision_checker tools/decision_verify.py $(sha256 "$PKG/tools/decision_verify.py") anubis_program_verifier tools/anubis_program_verify.py $(sha256 "$PKG/tools/anubis_program_verify.py") anubis_program_policy program/inventory_safe_v1.json $(sha256 "$PKG/program/inventory_safe_v1.json") +approved_z3_linux_aarch64 jackal_z3_v4154 $(sha256 "$PKG/jackal_z3_v4154") EOF cat > "$PKG/NON-CLAIMS.txt" <<'EOF' diff --git a/release/capability_inventory_v1.json b/release/capability_inventory_v1.json index 976af2c..9f1ed3f 100644 --- a/release/capability_inventory_v1.json +++ b/release/capability_inventory_v1.json @@ -1 +1 @@ -{"catalog":{"path":"plugin/hermes/tools.json","sha256":"53c823f07db512b82e01a4f132ff43be426b4b227c436e8853c5144ae0504e87","version":"v1.7.3"},"inputs":[{"path":"tools/capability_inventory.py","sha256":"a966660ef94d7b788be9f92451a78e43b41e12ae2c4e942834c1703994c2ccc0"},{"path":"plugin/hermes/tools.json","sha256":"53c823f07db512b82e01a4f132ff43be426b4b227c436e8853c5144ae0504e87"},{"path":"plugin/hermes/profiles/core.json","sha256":"49f33ba23cca5ab940f1929604f61491bc914d092f291cda4fe4f06b37d042d3"},{"path":"plugin/hermes/profiles/formal.json","sha256":"9be2b3144486311d9ba7f1d41c5033eb8e2553e9d12b71d46e512401f57a084b"},{"path":"plugin/hermes/profiles/full.json","sha256":"0db937da01737bbc0341a591ecd23e55008d8ffc02368517c7d1e7da8b309dec"},{"path":"plugin/hermes/server.py","sha256":"4c42725d797ac78ed20d3e843e602b1c60c88bd13f74e06c65a6b4016b3b7daf"},{"path":"plugins/jackel/.codex-plugin/plugin.json","sha256":"49bbd046759b045add1caf1f19300431fe7d697b59bfd93b57daf1d7edb709ff"},{"path":"plugins/jackel/mcp/server.py","sha256":"b5916270588db1fbb68b4d520c5f5e9d0fabb84e26602f18ad0a2927a38cece9"},{"path":"release/MANIFEST.sha256","sha256":"3c3d86fffe58b8ec6d93c06c61c4397f89ecd8f69b135a1ec6a4e1f2980700fa"},{"path":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"path":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"path":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"}],"release":{"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"state":"v1.7.3","statement":"Published release identity; the annotated v1.7.3 tag and GitHub release must bind these exact bytes.","version":"v1.7.3"},"schema":"jackal-capability-inventory-v1","status_vocabulary":["bounded","checked","estimated","exact","formal-bounded","indeterminate","model-based","ok","refused","structural-exact","verified","verified-program-evidence","verified-program-receipt"],"tool_count":41,"tools":[{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_range_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"826bed7e2645735d5d333040eaa8c28425df90b6e87f8dd6aa94df1cc40ace45","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded receipt with the certificate embedded (or refuse). Inputs: expression: Anubis expression in the single variable x, restricted to the certified fragment.; input_lo: Interval lower bound as an integer or reduced ℚ (e.g. '1', '2/3').; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-gaussian","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_gaussian_integral","profiles":["formal","full"],"refusal_boundary":"Only the exact catalog-declared Gaussian form and canonical rational bounds/tolerance are admitted. Any other form, failed enclosure, checker rejection, or pin/identity mismatch refuses without downgrade.","release_state":"v1.7.3","schema_sha256":"4a43f67d68610c9e7b13f8bc8195c6c3e9ea24493494eb5aca8e768d707adb13","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a zero-libm formal-bounded Gaussian integral receipt, rerun the pinned checker, or refuse without downgrade. Inputs: expression: Exact canonical exp(-A*(x-mu)^2) expression; all other expressions refuse.; input_lo: Integration lower bound as a canonical rational.; input_hi: Integration upper bound as a canonical rational.; tolerance: Maximum enclosure width as a positive canonical rational."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-int-cert","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_bound_cert","profiles":["formal","full"],"refusal_boundary":"Only the request-bound v1.7.2 composed-integral fragment and canonical bounds/tolerance are admitted. Request-unbound v1.7.0 evidence, unsupported syntax, failed subdivision, checker rejection, or identity mismatch refuses without using the weaker float lane.","release_state":"v1.7.3","schema_sha256":"1229ede1ee518a9b19d3a201268e598fac6fd52fd2eef1bb379f920d6093b9cd","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a request-bound certified composed definite-integral formal receipt (v1.7.2): the untrusted exact-rational producer mirrors the engine's adaptive subdivision, the pinned Lean-proved jackal_int_cert_check binds the exact raw expression/bounds/tolerance and re-checks the whole subdivision-tree certificate (theorem int_cert_sound), and the receipt is independently re-verified before returning. Request-unbound v1.7.0 receipts are revoked. Certified fragment: num/var/neg/add/sub/mul/div/pow(0..4096)/sin/cos/abs in x. Everything else refuses. The weaker float lane jackal_integrate_bound stays status=bounded and is NOT this tool. Inputs: expression: Integrand in the single variable x, restricted to the certified fragment (num/var/neg/add/sub/mul/div/pow/sin/cos/abs).; input_lo: Integration lower bound as an integer or reduced canonical rational (e.g. '0', '2/3').; input_hi: Integration upper bound as a canonical rational, strictly above input_lo.; tolerance: Maximum enclosure width as a positive canonical rational (e.g. '1/100')."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-receipt-registry","identities":[{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_verify_receipt","profiles":["core","formal","full"],"refusal_boundary":"Only closed-registry range/rational, Gaussian, and current request-bound int-cert receipts matching independent caller expectations are replayed. Unknown epochs/variants, copied rather than caller-pinned expectations, revoked int-cert evidence, or checker/pin mismatch refuses.","release_state":"v1.7.3","schema_sha256":"988b83705212769a01eb2e5f5b44322b5728d5fd86eef4f64f7a4a37e378fc1f","status_classes":["verified","refused"],"supported_fragment":"Re-run the matching pinned Lean-proved checker over an embedded certificate using a closed epoch/variant registry: current v1.7.2 range/rational and request-bound int_cert, replay-only v1.5.0 range/rational, or Gaussian v1.5.0. Request-unbound v1.7.0 int_cert receipts refuse. Inputs: receipt: A jackal-formal-receipt-v1 JSON document.; expected_release_epoch: Caller-authorized release epoch, not copied from the receipt.; expected_command: Caller-authorized operation: range-bound-cert or integrate.; expected_expression: Exact raw expression supplied by the caller.; expected_input_lo: Exact raw lower-bound token supplied by the caller.; expected_input_hi: Exact raw upper-bound token supplied by the caller.; expected_tolerance: Exact raw tolerance token; required for Gaussian and int_cert receipts and forbidden for range receipts."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_sqrt_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"bc611de421d812aa6d6d8772fb986c17bcde74d7fe70ea31ff22433335d67c6d","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q sqrt(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'sqrt(x)' on a canonical rational interval; every other expression refuses without downgrade. v1.4.0 fragment extension. Inputs: expression: Must equal 'sqrt(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational (e.g. '2', '1/4'); must be >= 0.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_exp_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"9cc7bee07eebc566a9e267ad1b30c10a73cb25c18090ed2f9a3e9ec48550b928","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q exp(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'exp(x)' on a canonical rational interval [lo, hi] (general-sign since v1.5.0); every other expression refuses without downgrade. v1.4.1 fragment extension. Inputs: expression: Must equal 'exp(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational; any sign (general-sign since v1.5.0).; input_hi: Interval upper bound (canonical rational, hi >= lo); the producer picks a Taylor degree with 2*hi <= n+1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_ln_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"16dfb2b64dc9e290e1c062eba898233b04b187f1b244f6cc06433c48d1b7da45","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q ln(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'ln(x)' on a canonical rational interval with lo > 0; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'ln(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational; must be > 0.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_sin_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"d578799057048871ff13eca207bda2f9564261fce975801904d8cb34370cc7fe","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q sin(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'sin(x)' on a canonical rational interval whose midpoint m satisfies |m| <= 1; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'sin(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo); midpoint (lo+hi)/2 must satisfy |m| <= 1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_cos_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"d0f575ac0dbfe5e64aede075ae30bb1a625f05963e772febca6ac180b29f062b","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q cos(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'cos(x)' on a canonical rational interval whose midpoint m satisfies |m| <= 1; every other expression refuses without downgrade. Shares the sin_rat producer (--op cos). v1.5.0 fragment extension. Inputs: expression: Must equal 'cos(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo); midpoint (lo+hi)/2 must satisfy |m| <= 1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_atan_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"f16e48c7a37e284e124fe20766c7db2b90b4eed8fb748c2efebc9ee7c4b80767","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q atan(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'atan(x)' on a canonical rational interval; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'atan(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_tanh_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"6f9b24d732cc6fc2b0ad9ef7d51fa8cd88f2a344b3152c54f288f6a25a8fe05a","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q tanh enclosure via the untrusted composite producer + Lean-proved checker. NO libm on the proof-decision path. tanh is not an engine grammar token: admits ONLY the literal composite expression '1-2/(exp(2*x)+1)' (= tanh(x) mathematically) on a canonical rational interval with |lo|,|hi| <= 20; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal '1-2/(exp(2*x)+1)' after whitespace normalization (the frozen tanh-defining composite).; input_lo: Interval lower bound as an integer or reduced rational; |lo| <= 20.; input_hi: Interval upper bound (canonical rational, hi >= lo); |hi| <= 20."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_exact","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"42319cf6d3e3f7a8da025e880b8dfc02eb2c6e3128f8b93c11f41545d8bf1d8d","status_classes":["exact","refused"],"supported_fragment":"Exact big-rational arithmetic (status=exact). NOT formal: computationally exact, outside the Lean certificate chain. Inputs: expression: Integers, decimals, + - * / ^ (integer exponents), parentheses. Everything else refuses."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_evaluate","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"5baa3a344309d714a8b66c9fb4a14a97c8182b3cfe1326faa2e9967840eee17c","status_classes":["estimated","refused"],"supported_fragment":"IEEE f64 expression evaluation (status=estimated). A plain number, honestly labeled: no bound, no proof. Inputs: expression: Full expression grammar incl. transcendental functions and constants."},{"assurance_classes":["checked"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_diff","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"605972a25cde65779e921b8a27b7f1a0c19d540f5330791ec0fb571cccf858ad","status_classes":["checked","refused"],"supported_fragment":"Symbolic d/dx with numeric self-verification (status=checked). Sampled agreement is a check, not a proof of identity. Inputs: expression: Expression in x; non-differentiable functions fail closed."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"6d05a705ff580a831f75cbcd2079fe88c3b5d9c858bc6b0c3182ec55aa27cd27","status_classes":["estimated","refused"],"supported_fragment":"Fixed-grid Simpson + Richardson error estimate (status=estimated). Grid-limited: NOT a bound. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; panels: Panel count (e.g. '200')."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_adaptive","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"174132e83bff6d18972cf5d88b072b12d7102cad8fdf05197165c64bfac4fea1","status_classes":["estimated","refused"],"supported_fragment":"Adaptive Simpson with refusal semantics (status=estimated). Refuses when unconverged; agreement is still not a bound. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; tolerance: Local tolerance (e.g. '1e-9')."},{"assurance_classes":["bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_bound","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"9932617903499a2ed2baa4ac213f061f422bd8f2e60bca5bf05225a9f9f788a0","status_classes":["bounded","refused"],"supported_fragment":"Certified interval enclosure of an integral (status=bounded). CONDITIONAL on the stated f64/libm rounding model; implementation campaign-tested, NOT mechanized. Never labeled formal. For a Lean-checked formal-bounded composed enclosure over the certified fragment, use jackal_integrate_bound_cert instead. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; tolerance: Max enclosure width (e.g. '1e-6')."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_solve","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"caf1f55ca8ad1fef2e0fb4f5f5bb600edb147f257427de650335500979c13501","status_classes":["estimated","refused"],"supported_fragment":"Bisection root with residual + first-order conditioning diagnostics (status=estimated). Inputs: expression: f(x) whose root is sought.; input_lo: Bracket lower bound (sign change required).; input_hi: Bracket upper bound."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"ea4ca54f74334d678c3daf9c6686fca186041d27bb2f02dabca21a7747e7d416","status_classes":["exact","refused"],"supported_fragment":"Canonical s-expression + SHA-256 of any parsed expression (status=exact). NOT formal: exact computation outside the Lean certificate chain; no exact-cert emitted. Inputs: expression: Any expression the engine grammar parses."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"199fd63f51398c6e883a407d8e2435e42903e9c76f0227d815f3456b3568d9bc","status_classes":["exact","refused"],"supported_fragment":"Dense Q[x] canonical form, degree <= 64 (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Polynomial expression in x within the poly fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_eq","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"76d9390f705758c6ec2d5fe77cd6a1391908f93ef218ebfd5111c067dc32a819","status_classes":["exact","refused"],"supported_fragment":"Decidable polynomial identity over Q[x] (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: lhs: Left polynomial expression in x.; rhs: Right polynomial expression in x."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_gcd","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"dfff2a285e732d52520ea6fe5efabdab5bd6d956c224f30d163ccbbdbd406a5c","status_classes":["exact","refused"],"supported_fragment":"Monic polynomial gcd over Q[x] via Euclid (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: lhs: Left polynomial expression in x.; rhs: Right polynomial expression in x."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_ratfunc_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"3d4c7d73d13aa88606e9e005b7731c19ac63f9fe559b38e6ff777f979afd3b40","status_classes":["exact","refused"],"supported_fragment":"Rational-function canonical form P/Q, gcd-reduced, monic denominator, explicit denominator-nonzero side condition (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Rational-function expression in x within the ratfunc fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_roots_isolate","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"ea98289e6b6319b7c0b3e6e9832e07ff4a9dd06be1d7862956c50df6e1785978","status_classes":["exact","refused"],"supported_fragment":"Sturm-sequence isolation of all distinct real roots (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Polynomial expression in x within the poly fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_alg_sign","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"b4ad3c632887bc8875f8334dea3391017d73f30fa4895d988062882e89c2c1a5","status_classes":["exact","refused"],"supported_fragment":"Exact sign of a Q[x] polynomial at a rational point (status=exact). NOT formal; no exact-cert emitted. Inputs: expression: Polynomial expression in x within the poly fragment.; point: Rational evaluation point (e.g. '3/2')."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_alg_cmp","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"bfea42d3f97e6f0403d11155d667dfec7000719e2aa3af67c8897989a9e2eee4","status_classes":["exact","refused"],"supported_fragment":"Order decision between two isolated real algebraic numbers (status=exact). NOT formal; no exact-cert emitted. Inputs: p: First defining polynomial in x.; a1: First isolating interval lower bound (rational).; b1: First isolating interval upper bound (rational).; q: Second defining polynomial in x.; a2: Second isolating interval lower bound (rational).; b2: Second isolating interval upper bound (rational)."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_xgcd","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"1c7fb606e43e71eeb4ab288c08ea4a6c89efd95beb3f802e084d5d3c1a3beaf6","status_classes":["exact","refused"],"supported_fragment":"Extended gcd with Bezout certificate (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: a: First integer.; b: Second integer."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_mod_pow","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"b3edc74b3901989b9248f8b89feaed2cc396e218abf9ccfca7ab53a99a9c7bc1","status_classes":["exact","refused"],"supported_fragment":"Modular exponentiation via square-and-multiply (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: base: Base integer.; exp: Nonnegative exponent integer.; mod: Modulus integer >= 1."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_mod_inv","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"d0826f19759afacd20d4a5f0d6704a52bce158c6950bb852a5e0774886a4abd7","status_classes":["exact","refused"],"supported_fragment":"Modular inverse with product certificate (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: a: Integer to invert.; m: Modulus integer >= 2; gcd(a, m) must be 1."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_crt","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"d44aebbbcb3b00ad0d192581533c5cfdb164e26431f3ed850406c8ecfa5044b4","status_classes":["exact","refused"],"supported_fragment":"Chinese remainder reconstruction over pairwise-coprime moduli, up to 16 pairs (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: args: Space-separated residue/modulus pairs: 'r1 m1 r2 m2 [...]' (e.g. '2 3 3 5 2 7')."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_divides","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"1191b2b4ce3a9a5c3a1dafb0917fad46ca9c3375c73f4ae59ff7a389d513adb4","status_classes":["exact","refused"],"supported_fragment":"Exact divisibility decision (status=exact). NOT formal; no exact-cert emitted. Inputs: a: Candidate divisor integer.; b: Dividend integer."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_prime_cert","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"3ff03881b24f8fd94db68b210874010e66ce0e3d32666d98a21c1bc40ccc5646","status_classes":["exact","refused"],"supported_fragment":"Pratt primality certificate or composite divisor witness, budgeted and fail-closed (status=exact; n <= 10^60, Pratt tree depth <= 64, nodes <= 512). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: n: Integer >= 2, at most 61 digits."},{"assurance_classes":["estimated","model-based","checked","bounded","formal-bounded","exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"claim-router","identities":[{"label":"claim_kernel","locator":"tools/claim_kernel.py","sha256":"77b0f85ad5fb7214f88898b60ea29ea9fd7be740c38b655388444e6e5181f348"},{"label":"claim_router","locator":"tools/claim_router.py","sha256":"02328cf177a0423bdc5cbca6ec0ea946bb0679bbd3dc6c24140d32598e575afb"},{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"},{"label":"claim_inference_registry","locator":"release/claim/inference_registry_v1.json","sha256":"c70b33d5aee8071b5125e6a5f8ffe5226fc22a137d920c17d9b3463968be13f0"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_claim","profiles":["core","formal","full"],"refusal_boundary":"Only jackal-claim-request-v1 and its closed step vocabulary are compiled. Policy, identity, schema, route, or assurance failures refuse; fallback is off by default and any caller-enabled fallback remains explicit in the route trace rather than silently changing assurance.","release_state":"v1.7.3","schema_sha256":"4d2703ff772433f39ac8b6555727e856685b0e5042b9c2cc8fcaa4402d6b9153","status_classes":["ok","refused"],"supported_fragment":"Compile a structured jackal-claim-request-v1 into a canonical, content-addressed jackal-claim-bundle-v1 evidence graph through the deterministic policy router. Routes through exact, current/archival range-family, Gaussian, request-bound composed-integral, machine, and unit lanes; emits a route trace naming candidates and refusal reasons; and refuses rather than silently downgrading (allow_fallback defaults false). The bundle is independently replayable via jackal_verify_bundle. Inputs: request: jackal-claim-request-v1 object: {schema, steps:[{id, op, ...}], root, policy?, nonce?, emitted_at_unix?, max_age_seconds?, expires_at_unix?}. Step ops: input, exact, enclose, gaussian, integrate_cert, machine, interval_add/sub/mul/div, threshold, decision, convert, and, model, passthrough, attach."},{"assurance_classes":["estimated","model-based","checked","bounded","formal-bounded","exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"claim-verifier","identities":[{"label":"claim_verifier","locator":"tools/claim_bundle_verify.py","sha256":"e0fcb9540c730bd9bb492b528ed42d29d49fc775b3aa0f9b831b6264fd68fd22"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"},{"label":"claim_inference_registry","locator":"release/claim/inference_registry_v1.json","sha256":"c70b33d5aee8071b5125e6a5f8ffe5226fc22a137d920c17d9b3463968be13f0"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_verify_bundle","profiles":["core","formal","full"],"refusal_boundary":"Only canonical bundles matching separately caller-pinned epoch, policy, root proposition, time, and nonce are replayed. Semantic, graph, freshness, evidence, checker, or pin ambiguity returns refused or indeterminate exactly as declared; it is never converted to success.","release_state":"v1.7.3","schema_sha256":"9e3acec17637a352bc88e3b08e8679a34f1efae3539fe1cce05646212be4cb5f","status_classes":["verified","refused","indeterminate"],"supported_fragment":"Independently replay a jackal-claim-bundle-v1 against caller-pinned expectations. The standalone dependency-free verifier recomputes every canonical byte and hash, revalidates the DAG, selects only the closed current/archival range, Gaussian, or current request-bound int-cert checker/proof tuple, re-runs embedded evidence, recomputes machine/unit mathematics, re-evaluates every inference rule and assurance-axis propagation, enforces consequence-class floors and policy, and recomputes the deterministic rendering. Returns verified | refused | indeterminate with exact reasons — never a generic green badge. Inputs: bundle: The jackal-claim-bundle-v1 object to replay.; expected_release_epoch: Caller-pinned epoch (e.g. 'v1.6.0'); never copied from the bundle.; expected_policy_sha256: Caller-pinned SHA-256 of the canonical policy bytes.; expected_root_proposition: Caller-pinned canonical root proposition IR object.; verification_time_unix: Caller-supplied verification time (unix seconds) for freshness/expiry checks.; expected_nonce: Caller nonce; the bundle root must bind exactly this nonce."},{"assurance_classes":["structural-exact"],"consequence_ceiling":"informational","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"structural-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_test_exists_checker","locator":"tools/test_exists_verify.py","sha256":"598cb99e1eb70c9410ca87345efee346f73e43aaf3625427dca17ea04231caea"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_test_exists","profiles":["full"],"refusal_boundary":"Only byte-exact source/citation structure described by the schema is accepted after independent file-byte recomputation. Path traversal, malformed symbols/hashes, missing text/declarations, or checker mismatch refuses; the result never asserts test execution or correctness.","release_state":"v1.7.3","schema_sha256":"9685ecf3bcf78a3a26916455cc528cdeac137420e8694447e2865b33890f9d46","status_classes":["structural-exact","refused"],"supported_fragment":"Domain pack jackal.programming.source, operation programming.source.test_exists.v1, routed through pack-route. States one byte-exact STRUCTURAL fact: a declaration-shaped occurrence of `symbol` exists at `declaration_line` in a file whose content hash is exactly `file_sha256`, and the file contains exactly `declaration_count` such occurrences. The engine validates the canonical FORM; the manifest-pinned independent checker tools/test_exists_verify.py then recomputes every claimed field from the real bytes on disk and only an ACCEPT verdict returns success, so a misstated hash, line or count refuses instead of minting a certificate. ASSURANCE ceiling exact; CONSEQUENCE ceiling informational, and the second does not rise with the first: a test-exists-cert is NEVER evidence that the code under test is correct, that the test executes, that it is collected by any runner, or that it asserts anything at all. NOT formal: no Lean checker and no theorem are involved. Do not cite this certificate in support of a correctness claim. Inputs: file_path: Repository-relative path token; absolute paths and parent traversal refuse `prog-path`.; file_sha256: Exactly 64 lowercase hex characters; the checker recomputes it from the file bytes.; symbol: Identifier of the declaration; a non-identifier refuses `prog-symbol`.; declaration_line: 1-based line of the declaration as a canonical positive integer.; declaration_count: Total declaration-shaped occurrences of `symbol` in the file; `0` refuses `prog-absent`."},{"assurance_classes":["structural-exact"],"consequence_ceiling":"informational","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"structural-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_test_exists_checker","locator":"tools/test_exists_verify.py","sha256":"598cb99e1eb70c9410ca87345efee346f73e43aaf3625427dca17ea04231caea"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_claim_cites_test","profiles":["full"],"refusal_boundary":"Only byte-exact source/citation structure described by the schema is accepted after independent file-byte recomputation. Path traversal, malformed symbols/hashes, missing text/declarations, or checker mismatch refuses; the result never asserts test execution or correctness.","release_state":"v1.7.3","schema_sha256":"69a533155bde04bfd5dedd43e9d63acd02f3e2773757936e9e1714458e20abd4","status_classes":["structural-exact","refused"],"supported_fragment":"Domain pack jackal.programming.source, operation programming.source.claim_cites_test.v1, routed through pack-route. Resolves a citation: `claim_text` occurs verbatim in the document at `doc_path`/`doc_sha256`, and `symbol` has a declaration-shaped occurrence in the cited test file at `test_path`/`test_sha256`. Resolution is all this establishes. It does NOT establish that the cited test covers, exercises or supports the claim — the cited test may check something entirely different, which is the exact defect this operation exists to bound rather than hide. The manifest-pinned tools/test_exists_verify.py re-runs over the certificate and only ACCEPT returns success, so a claim text absent from the document or a dangling citation refuses. ASSURANCE ceiling exact; CONSEQUENCE ceiling informational, and the second does not rise with the first. NOT formal: no Lean checker and no theorem are involved. Inputs: doc_path: Repository-relative path of the document making the claim.; doc_sha256: Exactly 64 lowercase hex characters for the document bytes.; claim_text: The claim sentence, verbatim, 1..2048 bytes; it must occur in the document.; test_path: Repository-relative path of the cited test file.; test_sha256: Exactly 64 lowercase hex characters for the cited test file bytes.; symbol: Identifier the citation resolves to inside the cited test file."},{"assurance_classes":["exact"],"consequence_ceiling":"decision-boundary","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"decision-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_decision_checker","locator":"tools/decision_verify.py","sha256":"f1ad7c9fbd4c1d899dbb4bebabbbeb97e97a56bd4b279ad7d8ec3722bf12e0f6"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_decision_rank","profiles":["full"],"refusal_boundary":"Only 2..6 schema-valid options under a caller-declared admissible numeric criterion are ranked. Invalid shape/sense/unit, value-judgment criteria, zero top margin, or checker mismatch refuses; caller values are not treated as measurements or confidence intervals.","release_state":"v1.7.3","schema_sha256":"843fe08464d40d97094eeb6424c0c29a3e2617172ba56262ca4122468a8bb92f","status_classes":["exact","refused"],"supported_fragment":"Domain pack jackal.decision.matrix, operation decision.matrix.rank.v1, routed through pack-route. Orders 2..6 labelled options by a caller-declared numeric criterion and emits a jackal-decision-cert-v1 naming the selected option, the runner-up and the exact margin; the manifest-pinned tools/decision_verify.py recomputes the whole ordering from the certificate's own option values and only ACCEPT returns success. Criterion admissibility is decided by the engine against a fixed word list, so a bare value judgment refuses `decision-value-judgment`; a top-two tie refuses `decision-margin-zero`. ASSURANCE ceiling exact; CONSEQUENCE ceiling decision-boundary. The arithmetic is exact and the choice of criterion is not: the declared criterion and the declared option values remain the caller's, this result is not a claim that the criterion is the right one, the values are not measurements, and the margin is not a confidence interval. For the closed-unit lane that additionally requires a declared unit, use jackal_decision_rank_v2. NOT formal: no Lean checker and no theorem are involved. Inputs: decision_id: Caller's identifier for this decision, bound into the certificate. Bytes are restricted to [A-Za-z0-9_]; anything else refuses `prog-symbol`.; criterion: The declared numeric criterion (e.g. 'latency_ms'); a value judgment refuses `decision-value-judgment`.; sense: Exactly 'min' or 'max'; anything else refuses `decision-sense-unknown`.; options: 2..6 whitespace-separated `label value` pairs, e.g. 'a 10 b 20 c 30'. Values are canonical integers. A label containing whitespace shifts the pairing and refuses `pack-args-shape`; it is never silently re-paired."},{"assurance_classes":["exact"],"consequence_ceiling":"decision-boundary","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"decision-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_decision_checker","locator":"tools/decision_verify.py","sha256":"f1ad7c9fbd4c1d899dbb4bebabbbeb97e97a56bd4b279ad7d8ec3722bf12e0f6"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_decision_rank_v2","profiles":["full"],"refusal_boundary":"Only 2..6 schema-valid options under a caller-declared admissible numeric criterion are ranked. Invalid shape/sense/unit, value-judgment criteria, zero top margin, or checker mismatch refuses; caller values are not treated as measurements or confidence intervals.","release_state":"v1.7.3","schema_sha256":"cdc8abba09426977a5319b52410204f21e2e1eb7b38a9de31de751fcb862e78a","status_classes":["exact","refused"],"supported_fragment":"Domain pack jackal.decision.matrix, operation decision.matrix.rank.v2, routed through pack-route. Same deterministic ordering as jackal_decision_rank, plus a REQUIRED declared unit drawn from a closed vocabulary: the 65 canonical ids of release/claim/unit_registry_v1.json excluding the dimensionless identity `one` (66 ids in the registry, `one` is not admitted here). Matching is exact-token and case-sensitive; an alias, a spelled-out name such as 'millisecond', a different case, or the dimensionless identity all refuse `decision-unit-unknown`, and an empty unit refuses `decision-unit-missing`. Emits jackal-decision-cert-v2, re-checked by the manifest-pinned tools/decision_verify.py; only ACCEPT returns success. ASSURANCE ceiling exact; CONSEQUENCE ceiling decision-boundary. Honest residual: a declared unit is NOT a measurement. The closed vocabulary forces the caller to name a dimension, and nothing more — a value-judgment criterion that survives the engine's word list is still accepted when a real unit is declared (`most_elegant` in `ms` ranks), and the values themselves remain caller-declared. NOT formal: no Lean checker and no theorem are involved. Inputs: decision_id: Caller's identifier for this decision, bound into the certificate. Bytes are restricted to [A-Za-z0-9_]; anything else refuses `prog-symbol`.; criterion: The declared numeric criterion; a value judgment refuses `decision-value-judgment` even with an admissible unit.; unit: One canonical unit id from release/claim/unit_registry_v1.json, excluding `one`. Exact token, case-sensitive: 'ms' is admitted, 'millisecond' and 'MS' refuse `decision-unit-unknown`.; sense: Exactly 'min' or 'max'; anything else refuses `decision-sense-unknown`.; options: 2..6 whitespace-separated `label value` pairs, e.g. 'a 10 b 20 c 30'. Values are canonical integers. A label containing whitespace shifts the pairing and refuses `pack-args-shape`; it is never silently re-paired."},{"assurance_classes":["verified-program-evidence"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"4b80e29bdffc0737f05a6e215fce8cce3b6b828c24afbf55c68443399e5119dc"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_check_program","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"177cfcf9dfcd6bbc6e657eb83b88f04bfedaa0f28f81307077a776e2052df1e2","status_classes":["verified-program-evidence","refused"],"supported_fragment":"Run a caller-pinned Anubis compiler only as `build --evidence` in Safe mode, never execute the compiled artifact, then independently close and replay the resulting strict anubis.program-evidence.v3 package under inventory-safe-v1. Emits only verified-program-evidence or a named refusal. This profile checks producer-attested function/policy inventories but explicitly does not establish policy-construct totality, source-to-VC proof, SMT-to-CNF proof, source-native refinement, runtime behavior, or universal soundness. Inputs: source_path: Local regular non-symlink Anubis source path.; anubis_bin: Local regular non-symlink Anubis executable; caller-pinned and hashed before/after build.; expected_source_sha256: Caller-pinned exact source SHA-256.; expected_compiler_sha256: Caller-pinned approved Anubis executable SHA-256.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1; contracted-safe-v1 refuses.; nonce: Caller nonce bound into the receipt.; out_root: New local output root; existing paths refuse."},{"assurance_classes":["verified-program-evidence"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"4b80e29bdffc0737f05a6e215fce8cce3b6b828c24afbf55c68443399e5119dc"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_verify_program","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"45c7aae87c329925f6bd6b9100efc7d099d70fcaeaba915ee59937f019e1153d","status_classes":["verified-program-evidence","refused"],"supported_fragment":"Independently verify caller-selected Anubis Safe source and evidence bytes under inventory-safe-v1: strict v3 roster, exact manifest closure, source/compiler/artifact/policy pins, producer-summary reconciliation, one-to-one solver/proof paths and counters, approved Z3 UNSAT replay, and independent RUP replay. Never executes the artifact and never claims independent policy-construct totality or source-native refinement. Inputs: source_path: Caller-selected regular non-symlink Anubis source path.; evidence_dir: Caller-selected strict anubis.program-evidence.v3 directory.; expected_source_sha256: Caller-pinned exact source SHA-256.; expected_compiler_sha256: Caller-pinned producer executable SHA-256.; expected_artifact_sha256: Caller-pinned sealed artifact SHA-256; artifact bytes are read but never executed.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1.; nonce: Caller nonce bound into the receipt."},{"assurance_classes":["verified-program-receipt"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"4b80e29bdffc0737f05a6e215fce8cce3b6b828c24afbf55c68443399e5119dc"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_verify_program_receipt","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"6bb75d81aebf6f2b3b20900357204e9ef0858cdac412ea016868028cdd2a67d3","status_classes":["verified-program-receipt","refused"],"supported_fragment":"Recompute a jackal-anubis-program-receipt-v1 from caller-selected source/evidence bytes and independent caller pins, rejecting outer-digest-consistent semantic laundering. Success is only verified-program-receipt; it does not raise the underlying inventory-safe-v1 assurance ceiling. Inputs: receipt: Program receipt object to replay; its own pins are never trusted.; source_path: Caller-selected regular source path.; evidence_dir: Caller-selected evidence directory.; expected_source_sha256: Caller-pinned source SHA-256.; expected_compiler_sha256: Caller-pinned compiler SHA-256.; expected_artifact_sha256: Caller-pinned artifact SHA-256.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1.; nonce: Caller nonce; never copied from the receipt."}],"unique_tool_count":41} +{"catalog":{"path":"plugin/hermes/tools.json","sha256":"53c823f07db512b82e01a4f132ff43be426b4b227c436e8853c5144ae0504e87","version":"v1.7.3"},"inputs":[{"path":"tools/capability_inventory.py","sha256":"a966660ef94d7b788be9f92451a78e43b41e12ae2c4e942834c1703994c2ccc0"},{"path":"plugin/hermes/tools.json","sha256":"53c823f07db512b82e01a4f132ff43be426b4b227c436e8853c5144ae0504e87"},{"path":"plugin/hermes/profiles/core.json","sha256":"49f33ba23cca5ab940f1929604f61491bc914d092f291cda4fe4f06b37d042d3"},{"path":"plugin/hermes/profiles/formal.json","sha256":"9be2b3144486311d9ba7f1d41c5033eb8e2553e9d12b71d46e512401f57a084b"},{"path":"plugin/hermes/profiles/full.json","sha256":"0db937da01737bbc0341a591ecd23e55008d8ffc02368517c7d1e7da8b309dec"},{"path":"plugin/hermes/server.py","sha256":"4c42725d797ac78ed20d3e843e602b1c60c88bd13f74e06c65a6b4016b3b7daf"},{"path":"plugins/jackel/.codex-plugin/plugin.json","sha256":"49bbd046759b045add1caf1f19300431fe7d697b59bfd93b57daf1d7edb709ff"},{"path":"plugins/jackel/mcp/server.py","sha256":"b5916270588db1fbb68b4d520c5f5e9d0fabb84e26602f18ad0a2927a38cece9"},{"path":"release/MANIFEST.sha256","sha256":"63fdf1062a78dace5907af4c12a894c7ba73c1ed9e252e0cf475c121cead373b"},{"path":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"path":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"path":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"}],"release":{"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"state":"v1.7.3","statement":"Published release identity; the annotated v1.7.3 tag and GitHub release must bind these exact bytes.","version":"v1.7.3"},"schema":"jackal-capability-inventory-v1","status_vocabulary":["bounded","checked","estimated","exact","formal-bounded","indeterminate","model-based","ok","refused","structural-exact","verified","verified-program-evidence","verified-program-receipt"],"tool_count":41,"tools":[{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_range_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"826bed7e2645735d5d333040eaa8c28425df90b6e87f8dd6aa94df1cc40ace45","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded receipt with the certificate embedded (or refuse). Inputs: expression: Anubis expression in the single variable x, restricted to the certified fragment.; input_lo: Interval lower bound as an integer or reduced ℚ (e.g. '1', '2/3').; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-gaussian","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_gaussian_integral","profiles":["formal","full"],"refusal_boundary":"Only the exact catalog-declared Gaussian form and canonical rational bounds/tolerance are admitted. Any other form, failed enclosure, checker rejection, or pin/identity mismatch refuses without downgrade.","release_state":"v1.7.3","schema_sha256":"4a43f67d68610c9e7b13f8bc8195c6c3e9ea24493494eb5aca8e768d707adb13","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a zero-libm formal-bounded Gaussian integral receipt, rerun the pinned checker, or refuse without downgrade. Inputs: expression: Exact canonical exp(-A*(x-mu)^2) expression; all other expressions refuse.; input_lo: Integration lower bound as a canonical rational.; input_hi: Integration upper bound as a canonical rational.; tolerance: Maximum enclosure width as a positive canonical rational."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-int-cert","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_bound_cert","profiles":["formal","full"],"refusal_boundary":"Only the request-bound v1.7.2 composed-integral fragment and canonical bounds/tolerance are admitted. Request-unbound v1.7.0 evidence, unsupported syntax, failed subdivision, checker rejection, or identity mismatch refuses without using the weaker float lane.","release_state":"v1.7.3","schema_sha256":"1229ede1ee518a9b19d3a201268e598fac6fd52fd2eef1bb379f920d6093b9cd","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a request-bound certified composed definite-integral formal receipt (v1.7.2): the untrusted exact-rational producer mirrors the engine's adaptive subdivision, the pinned Lean-proved jackal_int_cert_check binds the exact raw expression/bounds/tolerance and re-checks the whole subdivision-tree certificate (theorem int_cert_sound), and the receipt is independently re-verified before returning. Request-unbound v1.7.0 receipts are revoked. Certified fragment: num/var/neg/add/sub/mul/div/pow(0..4096)/sin/cos/abs in x. Everything else refuses. The weaker float lane jackal_integrate_bound stays status=bounded and is NOT this tool. Inputs: expression: Integrand in the single variable x, restricted to the certified fragment (num/var/neg/add/sub/mul/div/pow/sin/cos/abs).; input_lo: Integration lower bound as an integer or reduced canonical rational (e.g. '0', '2/3').; input_hi: Integration upper bound as a canonical rational, strictly above input_lo.; tolerance: Maximum enclosure width as a positive canonical rational (e.g. '1/100')."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-receipt-registry","identities":[{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_verify_receipt","profiles":["core","formal","full"],"refusal_boundary":"Only closed-registry range/rational, Gaussian, and current request-bound int-cert receipts matching independent caller expectations are replayed. Unknown epochs/variants, copied rather than caller-pinned expectations, revoked int-cert evidence, or checker/pin mismatch refuses.","release_state":"v1.7.3","schema_sha256":"988b83705212769a01eb2e5f5b44322b5728d5fd86eef4f64f7a4a37e378fc1f","status_classes":["verified","refused"],"supported_fragment":"Re-run the matching pinned Lean-proved checker over an embedded certificate using a closed epoch/variant registry: current v1.7.2 range/rational and request-bound int_cert, replay-only v1.5.0 range/rational, or Gaussian v1.5.0. Request-unbound v1.7.0 int_cert receipts refuse. Inputs: receipt: A jackal-formal-receipt-v1 JSON document.; expected_release_epoch: Caller-authorized release epoch, not copied from the receipt.; expected_command: Caller-authorized operation: range-bound-cert or integrate.; expected_expression: Exact raw expression supplied by the caller.; expected_input_lo: Exact raw lower-bound token supplied by the caller.; expected_input_hi: Exact raw upper-bound token supplied by the caller.; expected_tolerance: Exact raw tolerance token; required for Gaussian and int_cert receipts and forbidden for range receipts."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_sqrt_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"bc611de421d812aa6d6d8772fb986c17bcde74d7fe70ea31ff22433335d67c6d","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q sqrt(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'sqrt(x)' on a canonical rational interval; every other expression refuses without downgrade. v1.4.0 fragment extension. Inputs: expression: Must equal 'sqrt(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational (e.g. '2', '1/4'); must be >= 0.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_exp_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"9cc7bee07eebc566a9e267ad1b30c10a73cb25c18090ed2f9a3e9ec48550b928","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q exp(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'exp(x)' on a canonical rational interval [lo, hi] (general-sign since v1.5.0); every other expression refuses without downgrade. v1.4.1 fragment extension. Inputs: expression: Must equal 'exp(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational; any sign (general-sign since v1.5.0).; input_hi: Interval upper bound (canonical rational, hi >= lo); the producer picks a Taylor degree with 2*hi <= n+1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_ln_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"16dfb2b64dc9e290e1c062eba898233b04b187f1b244f6cc06433c48d1b7da45","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q ln(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'ln(x)' on a canonical rational interval with lo > 0; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'ln(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational; must be > 0.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_sin_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"d578799057048871ff13eca207bda2f9564261fce975801904d8cb34370cc7fe","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q sin(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'sin(x)' on a canonical rational interval whose midpoint m satisfies |m| <= 1; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'sin(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo); midpoint (lo+hi)/2 must satisfy |m| <= 1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_cos_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"d0f575ac0dbfe5e64aede075ae30bb1a625f05963e772febca6ac180b29f062b","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q cos(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'cos(x)' on a canonical rational interval whose midpoint m satisfies |m| <= 1; every other expression refuses without downgrade. Shares the sin_rat producer (--op cos). v1.5.0 fragment extension. Inputs: expression: Must equal 'cos(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo); midpoint (lo+hi)/2 must satisfy |m| <= 1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_atan_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"f16e48c7a37e284e124fe20766c7db2b90b4eed8fb748c2efebc9ee7c4b80767","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q atan(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'atan(x)' on a canonical rational interval; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'atan(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_tanh_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"6f9b24d732cc6fc2b0ad9ef7d51fa8cd88f2a344b3152c54f288f6a25a8fe05a","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q tanh enclosure via the untrusted composite producer + Lean-proved checker. NO libm on the proof-decision path. tanh is not an engine grammar token: admits ONLY the literal composite expression '1-2/(exp(2*x)+1)' (= tanh(x) mathematically) on a canonical rational interval with |lo|,|hi| <= 20; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal '1-2/(exp(2*x)+1)' after whitespace normalization (the frozen tanh-defining composite).; input_lo: Interval lower bound as an integer or reduced rational; |lo| <= 20.; input_hi: Interval upper bound (canonical rational, hi >= lo); |hi| <= 20."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_exact","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"42319cf6d3e3f7a8da025e880b8dfc02eb2c6e3128f8b93c11f41545d8bf1d8d","status_classes":["exact","refused"],"supported_fragment":"Exact big-rational arithmetic (status=exact). NOT formal: computationally exact, outside the Lean certificate chain. Inputs: expression: Integers, decimals, + - * / ^ (integer exponents), parentheses. Everything else refuses."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_evaluate","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"5baa3a344309d714a8b66c9fb4a14a97c8182b3cfe1326faa2e9967840eee17c","status_classes":["estimated","refused"],"supported_fragment":"IEEE f64 expression evaluation (status=estimated). A plain number, honestly labeled: no bound, no proof. Inputs: expression: Full expression grammar incl. transcendental functions and constants."},{"assurance_classes":["checked"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_diff","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"605972a25cde65779e921b8a27b7f1a0c19d540f5330791ec0fb571cccf858ad","status_classes":["checked","refused"],"supported_fragment":"Symbolic d/dx with numeric self-verification (status=checked). Sampled agreement is a check, not a proof of identity. Inputs: expression: Expression in x; non-differentiable functions fail closed."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"6d05a705ff580a831f75cbcd2079fe88c3b5d9c858bc6b0c3182ec55aa27cd27","status_classes":["estimated","refused"],"supported_fragment":"Fixed-grid Simpson + Richardson error estimate (status=estimated). Grid-limited: NOT a bound. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; panels: Panel count (e.g. '200')."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_adaptive","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"174132e83bff6d18972cf5d88b072b12d7102cad8fdf05197165c64bfac4fea1","status_classes":["estimated","refused"],"supported_fragment":"Adaptive Simpson with refusal semantics (status=estimated). Refuses when unconverged; agreement is still not a bound. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; tolerance: Local tolerance (e.g. '1e-9')."},{"assurance_classes":["bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_bound","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"9932617903499a2ed2baa4ac213f061f422bd8f2e60bca5bf05225a9f9f788a0","status_classes":["bounded","refused"],"supported_fragment":"Certified interval enclosure of an integral (status=bounded). CONDITIONAL on the stated f64/libm rounding model; implementation campaign-tested, NOT mechanized. Never labeled formal. For a Lean-checked formal-bounded composed enclosure over the certified fragment, use jackal_integrate_bound_cert instead. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; tolerance: Max enclosure width (e.g. '1e-6')."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_solve","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"caf1f55ca8ad1fef2e0fb4f5f5bb600edb147f257427de650335500979c13501","status_classes":["estimated","refused"],"supported_fragment":"Bisection root with residual + first-order conditioning diagnostics (status=estimated). Inputs: expression: f(x) whose root is sought.; input_lo: Bracket lower bound (sign change required).; input_hi: Bracket upper bound."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"ea4ca54f74334d678c3daf9c6686fca186041d27bb2f02dabca21a7747e7d416","status_classes":["exact","refused"],"supported_fragment":"Canonical s-expression + SHA-256 of any parsed expression (status=exact). NOT formal: exact computation outside the Lean certificate chain; no exact-cert emitted. Inputs: expression: Any expression the engine grammar parses."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"199fd63f51398c6e883a407d8e2435e42903e9c76f0227d815f3456b3568d9bc","status_classes":["exact","refused"],"supported_fragment":"Dense Q[x] canonical form, degree <= 64 (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Polynomial expression in x within the poly fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_eq","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"76d9390f705758c6ec2d5fe77cd6a1391908f93ef218ebfd5111c067dc32a819","status_classes":["exact","refused"],"supported_fragment":"Decidable polynomial identity over Q[x] (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: lhs: Left polynomial expression in x.; rhs: Right polynomial expression in x."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_gcd","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"dfff2a285e732d52520ea6fe5efabdab5bd6d956c224f30d163ccbbdbd406a5c","status_classes":["exact","refused"],"supported_fragment":"Monic polynomial gcd over Q[x] via Euclid (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: lhs: Left polynomial expression in x.; rhs: Right polynomial expression in x."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_ratfunc_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"3d4c7d73d13aa88606e9e005b7731c19ac63f9fe559b38e6ff777f979afd3b40","status_classes":["exact","refused"],"supported_fragment":"Rational-function canonical form P/Q, gcd-reduced, monic denominator, explicit denominator-nonzero side condition (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Rational-function expression in x within the ratfunc fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_roots_isolate","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"ea98289e6b6319b7c0b3e6e9832e07ff4a9dd06be1d7862956c50df6e1785978","status_classes":["exact","refused"],"supported_fragment":"Sturm-sequence isolation of all distinct real roots (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Polynomial expression in x within the poly fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_alg_sign","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"b4ad3c632887bc8875f8334dea3391017d73f30fa4895d988062882e89c2c1a5","status_classes":["exact","refused"],"supported_fragment":"Exact sign of a Q[x] polynomial at a rational point (status=exact). NOT formal; no exact-cert emitted. Inputs: expression: Polynomial expression in x within the poly fragment.; point: Rational evaluation point (e.g. '3/2')."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_alg_cmp","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"bfea42d3f97e6f0403d11155d667dfec7000719e2aa3af67c8897989a9e2eee4","status_classes":["exact","refused"],"supported_fragment":"Order decision between two isolated real algebraic numbers (status=exact). NOT formal; no exact-cert emitted. Inputs: p: First defining polynomial in x.; a1: First isolating interval lower bound (rational).; b1: First isolating interval upper bound (rational).; q: Second defining polynomial in x.; a2: Second isolating interval lower bound (rational).; b2: Second isolating interval upper bound (rational)."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_xgcd","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"1c7fb606e43e71eeb4ab288c08ea4a6c89efd95beb3f802e084d5d3c1a3beaf6","status_classes":["exact","refused"],"supported_fragment":"Extended gcd with Bezout certificate (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: a: First integer.; b: Second integer."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_mod_pow","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"b3edc74b3901989b9248f8b89feaed2cc396e218abf9ccfca7ab53a99a9c7bc1","status_classes":["exact","refused"],"supported_fragment":"Modular exponentiation via square-and-multiply (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: base: Base integer.; exp: Nonnegative exponent integer.; mod: Modulus integer >= 1."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_mod_inv","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"d0826f19759afacd20d4a5f0d6704a52bce158c6950bb852a5e0774886a4abd7","status_classes":["exact","refused"],"supported_fragment":"Modular inverse with product certificate (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: a: Integer to invert.; m: Modulus integer >= 2; gcd(a, m) must be 1."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_crt","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"d44aebbbcb3b00ad0d192581533c5cfdb164e26431f3ed850406c8ecfa5044b4","status_classes":["exact","refused"],"supported_fragment":"Chinese remainder reconstruction over pairwise-coprime moduli, up to 16 pairs (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: args: Space-separated residue/modulus pairs: 'r1 m1 r2 m2 [...]' (e.g. '2 3 3 5 2 7')."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_divides","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"1191b2b4ce3a9a5c3a1dafb0917fad46ca9c3375c73f4ae59ff7a389d513adb4","status_classes":["exact","refused"],"supported_fragment":"Exact divisibility decision (status=exact). NOT formal; no exact-cert emitted. Inputs: a: Candidate divisor integer.; b: Dividend integer."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_prime_cert","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"3ff03881b24f8fd94db68b210874010e66ce0e3d32666d98a21c1bc40ccc5646","status_classes":["exact","refused"],"supported_fragment":"Pratt primality certificate or composite divisor witness, budgeted and fail-closed (status=exact; n <= 10^60, Pratt tree depth <= 64, nodes <= 512). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: n: Integer >= 2, at most 61 digits."},{"assurance_classes":["estimated","model-based","checked","bounded","formal-bounded","exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"claim-router","identities":[{"label":"claim_kernel","locator":"tools/claim_kernel.py","sha256":"77b0f85ad5fb7214f88898b60ea29ea9fd7be740c38b655388444e6e5181f348"},{"label":"claim_router","locator":"tools/claim_router.py","sha256":"02328cf177a0423bdc5cbca6ec0ea946bb0679bbd3dc6c24140d32598e575afb"},{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"},{"label":"claim_inference_registry","locator":"release/claim/inference_registry_v1.json","sha256":"c70b33d5aee8071b5125e6a5f8ffe5226fc22a137d920c17d9b3463968be13f0"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_claim","profiles":["core","formal","full"],"refusal_boundary":"Only jackal-claim-request-v1 and its closed step vocabulary are compiled. Policy, identity, schema, route, or assurance failures refuse; fallback is off by default and any caller-enabled fallback remains explicit in the route trace rather than silently changing assurance.","release_state":"v1.7.3","schema_sha256":"4d2703ff772433f39ac8b6555727e856685b0e5042b9c2cc8fcaa4402d6b9153","status_classes":["ok","refused"],"supported_fragment":"Compile a structured jackal-claim-request-v1 into a canonical, content-addressed jackal-claim-bundle-v1 evidence graph through the deterministic policy router. Routes through exact, current/archival range-family, Gaussian, request-bound composed-integral, machine, and unit lanes; emits a route trace naming candidates and refusal reasons; and refuses rather than silently downgrading (allow_fallback defaults false). The bundle is independently replayable via jackal_verify_bundle. Inputs: request: jackal-claim-request-v1 object: {schema, steps:[{id, op, ...}], root, policy?, nonce?, emitted_at_unix?, max_age_seconds?, expires_at_unix?}. Step ops: input, exact, enclose, gaussian, integrate_cert, machine, interval_add/sub/mul/div, threshold, decision, convert, and, model, passthrough, attach."},{"assurance_classes":["estimated","model-based","checked","bounded","formal-bounded","exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"claim-verifier","identities":[{"label":"claim_verifier","locator":"tools/claim_bundle_verify.py","sha256":"e0fcb9540c730bd9bb492b528ed42d29d49fc775b3aa0f9b831b6264fd68fd22"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"},{"label":"claim_inference_registry","locator":"release/claim/inference_registry_v1.json","sha256":"c70b33d5aee8071b5125e6a5f8ffe5226fc22a137d920c17d9b3463968be13f0"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_verify_bundle","profiles":["core","formal","full"],"refusal_boundary":"Only canonical bundles matching separately caller-pinned epoch, policy, root proposition, time, and nonce are replayed. Semantic, graph, freshness, evidence, checker, or pin ambiguity returns refused or indeterminate exactly as declared; it is never converted to success.","release_state":"v1.7.3","schema_sha256":"9e3acec17637a352bc88e3b08e8679a34f1efae3539fe1cce05646212be4cb5f","status_classes":["verified","refused","indeterminate"],"supported_fragment":"Independently replay a jackal-claim-bundle-v1 against caller-pinned expectations. The standalone dependency-free verifier recomputes every canonical byte and hash, revalidates the DAG, selects only the closed current/archival range, Gaussian, or current request-bound int-cert checker/proof tuple, re-runs embedded evidence, recomputes machine/unit mathematics, re-evaluates every inference rule and assurance-axis propagation, enforces consequence-class floors and policy, and recomputes the deterministic rendering. Returns verified | refused | indeterminate with exact reasons — never a generic green badge. Inputs: bundle: The jackal-claim-bundle-v1 object to replay.; expected_release_epoch: Caller-pinned epoch (e.g. 'v1.6.0'); never copied from the bundle.; expected_policy_sha256: Caller-pinned SHA-256 of the canonical policy bytes.; expected_root_proposition: Caller-pinned canonical root proposition IR object.; verification_time_unix: Caller-supplied verification time (unix seconds) for freshness/expiry checks.; expected_nonce: Caller nonce; the bundle root must bind exactly this nonce."},{"assurance_classes":["structural-exact"],"consequence_ceiling":"informational","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"structural-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_test_exists_checker","locator":"tools/test_exists_verify.py","sha256":"598cb99e1eb70c9410ca87345efee346f73e43aaf3625427dca17ea04231caea"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_test_exists","profiles":["full"],"refusal_boundary":"Only byte-exact source/citation structure described by the schema is accepted after independent file-byte recomputation. Path traversal, malformed symbols/hashes, missing text/declarations, or checker mismatch refuses; the result never asserts test execution or correctness.","release_state":"v1.7.3","schema_sha256":"9685ecf3bcf78a3a26916455cc528cdeac137420e8694447e2865b33890f9d46","status_classes":["structural-exact","refused"],"supported_fragment":"Domain pack jackal.programming.source, operation programming.source.test_exists.v1, routed through pack-route. States one byte-exact STRUCTURAL fact: a declaration-shaped occurrence of `symbol` exists at `declaration_line` in a file whose content hash is exactly `file_sha256`, and the file contains exactly `declaration_count` such occurrences. The engine validates the canonical FORM; the manifest-pinned independent checker tools/test_exists_verify.py then recomputes every claimed field from the real bytes on disk and only an ACCEPT verdict returns success, so a misstated hash, line or count refuses instead of minting a certificate. ASSURANCE ceiling exact; CONSEQUENCE ceiling informational, and the second does not rise with the first: a test-exists-cert is NEVER evidence that the code under test is correct, that the test executes, that it is collected by any runner, or that it asserts anything at all. NOT formal: no Lean checker and no theorem are involved. Do not cite this certificate in support of a correctness claim. Inputs: file_path: Repository-relative path token; absolute paths and parent traversal refuse `prog-path`.; file_sha256: Exactly 64 lowercase hex characters; the checker recomputes it from the file bytes.; symbol: Identifier of the declaration; a non-identifier refuses `prog-symbol`.; declaration_line: 1-based line of the declaration as a canonical positive integer.; declaration_count: Total declaration-shaped occurrences of `symbol` in the file; `0` refuses `prog-absent`."},{"assurance_classes":["structural-exact"],"consequence_ceiling":"informational","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"structural-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_test_exists_checker","locator":"tools/test_exists_verify.py","sha256":"598cb99e1eb70c9410ca87345efee346f73e43aaf3625427dca17ea04231caea"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_claim_cites_test","profiles":["full"],"refusal_boundary":"Only byte-exact source/citation structure described by the schema is accepted after independent file-byte recomputation. Path traversal, malformed symbols/hashes, missing text/declarations, or checker mismatch refuses; the result never asserts test execution or correctness.","release_state":"v1.7.3","schema_sha256":"69a533155bde04bfd5dedd43e9d63acd02f3e2773757936e9e1714458e20abd4","status_classes":["structural-exact","refused"],"supported_fragment":"Domain pack jackal.programming.source, operation programming.source.claim_cites_test.v1, routed through pack-route. Resolves a citation: `claim_text` occurs verbatim in the document at `doc_path`/`doc_sha256`, and `symbol` has a declaration-shaped occurrence in the cited test file at `test_path`/`test_sha256`. Resolution is all this establishes. It does NOT establish that the cited test covers, exercises or supports the claim — the cited test may check something entirely different, which is the exact defect this operation exists to bound rather than hide. The manifest-pinned tools/test_exists_verify.py re-runs over the certificate and only ACCEPT returns success, so a claim text absent from the document or a dangling citation refuses. ASSURANCE ceiling exact; CONSEQUENCE ceiling informational, and the second does not rise with the first. NOT formal: no Lean checker and no theorem are involved. Inputs: doc_path: Repository-relative path of the document making the claim.; doc_sha256: Exactly 64 lowercase hex characters for the document bytes.; claim_text: The claim sentence, verbatim, 1..2048 bytes; it must occur in the document.; test_path: Repository-relative path of the cited test file.; test_sha256: Exactly 64 lowercase hex characters for the cited test file bytes.; symbol: Identifier the citation resolves to inside the cited test file."},{"assurance_classes":["exact"],"consequence_ceiling":"decision-boundary","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"decision-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_decision_checker","locator":"tools/decision_verify.py","sha256":"f1ad7c9fbd4c1d899dbb4bebabbbeb97e97a56bd4b279ad7d8ec3722bf12e0f6"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_decision_rank","profiles":["full"],"refusal_boundary":"Only 2..6 schema-valid options under a caller-declared admissible numeric criterion are ranked. Invalid shape/sense/unit, value-judgment criteria, zero top margin, or checker mismatch refuses; caller values are not treated as measurements or confidence intervals.","release_state":"v1.7.3","schema_sha256":"843fe08464d40d97094eeb6424c0c29a3e2617172ba56262ca4122468a8bb92f","status_classes":["exact","refused"],"supported_fragment":"Domain pack jackal.decision.matrix, operation decision.matrix.rank.v1, routed through pack-route. Orders 2..6 labelled options by a caller-declared numeric criterion and emits a jackal-decision-cert-v1 naming the selected option, the runner-up and the exact margin; the manifest-pinned tools/decision_verify.py recomputes the whole ordering from the certificate's own option values and only ACCEPT returns success. Criterion admissibility is decided by the engine against a fixed word list, so a bare value judgment refuses `decision-value-judgment`; a top-two tie refuses `decision-margin-zero`. ASSURANCE ceiling exact; CONSEQUENCE ceiling decision-boundary. The arithmetic is exact and the choice of criterion is not: the declared criterion and the declared option values remain the caller's, this result is not a claim that the criterion is the right one, the values are not measurements, and the margin is not a confidence interval. For the closed-unit lane that additionally requires a declared unit, use jackal_decision_rank_v2. NOT formal: no Lean checker and no theorem are involved. Inputs: decision_id: Caller's identifier for this decision, bound into the certificate. Bytes are restricted to [A-Za-z0-9_]; anything else refuses `prog-symbol`.; criterion: The declared numeric criterion (e.g. 'latency_ms'); a value judgment refuses `decision-value-judgment`.; sense: Exactly 'min' or 'max'; anything else refuses `decision-sense-unknown`.; options: 2..6 whitespace-separated `label value` pairs, e.g. 'a 10 b 20 c 30'. Values are canonical integers. A label containing whitespace shifts the pairing and refuses `pack-args-shape`; it is never silently re-paired."},{"assurance_classes":["exact"],"consequence_ceiling":"decision-boundary","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"decision-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_decision_checker","locator":"tools/decision_verify.py","sha256":"f1ad7c9fbd4c1d899dbb4bebabbbeb97e97a56bd4b279ad7d8ec3722bf12e0f6"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_decision_rank_v2","profiles":["full"],"refusal_boundary":"Only 2..6 schema-valid options under a caller-declared admissible numeric criterion are ranked. Invalid shape/sense/unit, value-judgment criteria, zero top margin, or checker mismatch refuses; caller values are not treated as measurements or confidence intervals.","release_state":"v1.7.3","schema_sha256":"cdc8abba09426977a5319b52410204f21e2e1eb7b38a9de31de751fcb862e78a","status_classes":["exact","refused"],"supported_fragment":"Domain pack jackal.decision.matrix, operation decision.matrix.rank.v2, routed through pack-route. Same deterministic ordering as jackal_decision_rank, plus a REQUIRED declared unit drawn from a closed vocabulary: the 65 canonical ids of release/claim/unit_registry_v1.json excluding the dimensionless identity `one` (66 ids in the registry, `one` is not admitted here). Matching is exact-token and case-sensitive; an alias, a spelled-out name such as 'millisecond', a different case, or the dimensionless identity all refuse `decision-unit-unknown`, and an empty unit refuses `decision-unit-missing`. Emits jackal-decision-cert-v2, re-checked by the manifest-pinned tools/decision_verify.py; only ACCEPT returns success. ASSURANCE ceiling exact; CONSEQUENCE ceiling decision-boundary. Honest residual: a declared unit is NOT a measurement. The closed vocabulary forces the caller to name a dimension, and nothing more — a value-judgment criterion that survives the engine's word list is still accepted when a real unit is declared (`most_elegant` in `ms` ranks), and the values themselves remain caller-declared. NOT formal: no Lean checker and no theorem are involved. Inputs: decision_id: Caller's identifier for this decision, bound into the certificate. Bytes are restricted to [A-Za-z0-9_]; anything else refuses `prog-symbol`.; criterion: The declared numeric criterion; a value judgment refuses `decision-value-judgment` even with an admissible unit.; unit: One canonical unit id from release/claim/unit_registry_v1.json, excluding `one`. Exact token, case-sensitive: 'ms' is admitted, 'millisecond' and 'MS' refuse `decision-unit-unknown`.; sense: Exactly 'min' or 'max'; anything else refuses `decision-sense-unknown`.; options: 2..6 whitespace-separated `label value` pairs, e.g. 'a 10 b 20 c 30'. Values are canonical integers. A label containing whitespace shifts the pairing and refuses `pack-args-shape`; it is never silently re-paired."},{"assurance_classes":["verified-program-evidence"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"867f4bba40ce3f343d3f6a0be6ff35bc8135b08119e2506912d43dd1758a04e7"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_check_program","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"177cfcf9dfcd6bbc6e657eb83b88f04bfedaa0f28f81307077a776e2052df1e2","status_classes":["verified-program-evidence","refused"],"supported_fragment":"Run a caller-pinned Anubis compiler only as `build --evidence` in Safe mode, never execute the compiled artifact, then independently close and replay the resulting strict anubis.program-evidence.v3 package under inventory-safe-v1. Emits only verified-program-evidence or a named refusal. This profile checks producer-attested function/policy inventories but explicitly does not establish policy-construct totality, source-to-VC proof, SMT-to-CNF proof, source-native refinement, runtime behavior, or universal soundness. Inputs: source_path: Local regular non-symlink Anubis source path.; anubis_bin: Local regular non-symlink Anubis executable; caller-pinned and hashed before/after build.; expected_source_sha256: Caller-pinned exact source SHA-256.; expected_compiler_sha256: Caller-pinned approved Anubis executable SHA-256.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1; contracted-safe-v1 refuses.; nonce: Caller nonce bound into the receipt.; out_root: New local output root; existing paths refuse."},{"assurance_classes":["verified-program-evidence"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"867f4bba40ce3f343d3f6a0be6ff35bc8135b08119e2506912d43dd1758a04e7"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_verify_program","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"45c7aae87c329925f6bd6b9100efc7d099d70fcaeaba915ee59937f019e1153d","status_classes":["verified-program-evidence","refused"],"supported_fragment":"Independently verify caller-selected Anubis Safe source and evidence bytes under inventory-safe-v1: strict v3 roster, exact manifest closure, source/compiler/artifact/policy pins, producer-summary reconciliation, one-to-one solver/proof paths and counters, approved Z3 UNSAT replay, and independent RUP replay. Never executes the artifact and never claims independent policy-construct totality or source-native refinement. Inputs: source_path: Caller-selected regular non-symlink Anubis source path.; evidence_dir: Caller-selected strict anubis.program-evidence.v3 directory.; expected_source_sha256: Caller-pinned exact source SHA-256.; expected_compiler_sha256: Caller-pinned producer executable SHA-256.; expected_artifact_sha256: Caller-pinned sealed artifact SHA-256; artifact bytes are read but never executed.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1.; nonce: Caller nonce bound into the receipt."},{"assurance_classes":["verified-program-receipt"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"867f4bba40ce3f343d3f6a0be6ff35bc8135b08119e2506912d43dd1758a04e7"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_verify_program_receipt","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"6bb75d81aebf6f2b3b20900357204e9ef0858cdac412ea016868028cdd2a67d3","status_classes":["verified-program-receipt","refused"],"supported_fragment":"Recompute a jackal-anubis-program-receipt-v1 from caller-selected source/evidence bytes and independent caller pins, rejecting outer-digest-consistent semantic laundering. Success is only verified-program-receipt; it does not raise the underlying inventory-safe-v1 assurance ceiling. Inputs: receipt: Program receipt object to replay; its own pins are never trusted.; source_path: Caller-selected regular source path.; evidence_dir: Caller-selected evidence directory.; expected_source_sha256: Caller-pinned source SHA-256.; expected_compiler_sha256: Caller-pinned compiler SHA-256.; expected_artifact_sha256: Caller-pinned artifact SHA-256.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1.; nonce: Caller nonce; never copied from the receipt."}],"unique_tool_count":41} diff --git a/release/evidence/approved_z3.linux-aarch64 b/release/evidence/approved_z3.linux-aarch64 new file mode 100644 index 0000000..7bea904 --- /dev/null +++ b/release/evidence/approved_z3.linux-aarch64 @@ -0,0 +1 @@ +/home/sicarii/.local/share/JACKAL/z3/linux-aarch64/jackal_z3_v4154 b6fcd93b2ccec9aa848ac148c4d9b4270577ad046601f211784586eb9f0135c4 diff --git a/release/tools/repin_linux.py b/release/tools/repin_linux.py index 222d60f..01237d5 100755 --- a/release/tools/repin_linux.py +++ b/release/tools/repin_linux.py @@ -138,6 +138,12 @@ def host_evidence(base: str) -> Path | None: out.append(f"{label} {name} {archival_sha}") else: out.append(line) + # Omarchy edition: append the architecture-qualified approved Z3 anchor row + z3marker = ROOT / EVIDENCE_DIR / f"approved_z3.{tag}" + if z3marker.is_file(): + parts = z3marker.read_text().split() + if len(parts) >= 2 and len(parts[1]) == 64: + out.append(f"approved-z3-{tag} jackal_z3_v4154 {parts[1]}") missing = set(BINARY_ROWS) - seen_binary if missing: sys.exit(f"REPIN_LINUX_REFUSED detail=manifest lacked binary rows: {sorted(missing)}") diff --git a/tools/anubis_program_verify.py b/tools/anubis_program_verify.py index 9e25038..6a5dd90 100755 --- a/tools/anubis_program_verify.py +++ b/tools/anubis_program_verify.py @@ -19,6 +19,7 @@ import hashlib import json import os +import platform import re import subprocess import stat @@ -128,6 +129,43 @@ ) APPROVED_Z3_PATH = Path("/opt/homebrew/bin/z3") APPROVED_Z3_SHA256 = "ae6c8df33db9c9ae9a80b6044e77cd66529a141d8b25f0620f1e89b409594f48" + +# Architecture-qualified trust anchor extension (architect sign-off 2026-08-23): +# Linux aarch64 admits an independently double-built, byte-reproducible Z3 4.15.4 +# (NOT the guest's system 4.16.0). The Darwin anchor above is preserved exactly. +APPROVED_Z3_LINUX_AARCH64_SHA256 = "b6fcd93b2ccec9aa848ac148c4d9b4270577ad046601f211784586eb9f0135c4" +APPROVED_Z3_SEMVER = "4.15.4" + + +def _approved_z3_for_host() -> tuple[Path, str]: + """Return (path, expected_sha256) of the approved Z3 for THIS host, or refuse. + + Never consults caller PATH. Darwin keeps its exact pinned anchor. Linux + aarch64 resolves the package-shipped Z3 (sibling of this verifier) or a + dev marker naming an absolute path; both are pinned to the exact + double-build digest. No other host is admitted. + """ + system, machine = platform.system(), platform.machine() + if system == "Darwin": + return APPROVED_Z3_PATH, APPROVED_Z3_SHA256 + if system == "Linux" and machine == "aarch64": + here = Path(__file__).resolve().parent + # package ships the Z3 at the package root; the verifier is at + # /tools/ (or, in a flat layout, at /). Check both. + for shipped in (here / "jackal_z3_v4154", here.parent / "jackal_z3_v4154"): + if shipped.is_file(): + return shipped, APPROVED_Z3_LINUX_AARCH64_SHA256 + # dev/repo marker: /release/evidence/approved_z3. names an abspath + for marker in ( + here.parent / "release" / "evidence" / "approved_z3.linux-aarch64", + here / "evidence" / "approved_z3.linux-aarch64", + ): + if marker.is_file(): + parts = marker.read_text().split() + if parts: + return Path(parts[0]), APPROVED_Z3_LINUX_AARCH64_SHA256 + raise Refusal("z3-unavailable") + raise Refusal("z3-unsupported-host", f"{system}/{machine}") PROGRAM_POLICY_CANDIDATES = ( Path(__file__).resolve().parents[1] / "release/program/inventory_safe_v1.json", @@ -654,15 +692,34 @@ def verify_rup( def verify_smt_unsat(path: Path) -> None: + approved_path, approved_sha = _approved_z3_for_host() + # no symlink at the target boundary (ancestor symlinks are rejected by + # resolve(strict=True) diverging from the pre-resolution path component) + if approved_path.is_symlink(): + raise Refusal("z3-symlink") try: - z3_path = APPROVED_Z3_PATH.resolve(strict=True) + z3_path = approved_path.resolve(strict=True) except OSError: raise Refusal("z3-unavailable") from None - if not z3_path.is_file(): + if z3_path.is_symlink() or not z3_path.is_file(): raise Refusal("z3-unavailable") + info = z3_path.stat() + if info.st_uid != os.getuid(): + raise Refusal("z3-owner") + if info.st_mode & (stat.S_IWGRP | stat.S_IWOTH): + raise Refusal("z3-mode") before = sha_file(z3_path) - if before != APPROVED_Z3_SHA256: + if before != approved_sha: raise Refusal("z3-identity-mismatch") + # exact semantic version gate + try: + ver = subprocess.run([str(z3_path), "--version"], capture_output=True, text=True, timeout=30) + except (OSError, subprocess.TimeoutExpired) as exc: + raise Refusal("z3-replay-failed", str(exc)) from None + if APPROVED_Z3_SEMVER not in ver.stdout: + raise Refusal("z3-version-mismatch", ver.stdout.strip()[:60]) + if sha_file(z3_path) != before: + raise Refusal("z3-toctou") try: completed = subprocess.run( [str(z3_path), "-smt2", str(path)], @@ -672,6 +729,7 @@ def verify_smt_unsat(path: Path) -> None: ) except (OSError, subprocess.TimeoutExpired) as exc: raise Refusal("z3-replay-failed", str(exc)) from None + # single-snapshot identity: bytes must be unchanged across the whole check if sha_file(z3_path) != before: raise Refusal("z3-toctou") lines = [line.strip() for line in completed.stdout.splitlines() if line.strip()] From 227128f7a248389610d54a330929986a4407c683 Mon Sep 17 00:00:00 2001 From: sicarii Date: Mon, 24 Aug 2026 01:05:01 -0400 Subject: [PATCH 06/22] Add OMARCHY_BUILD.md: full native rebuild recipe for the Linux aarch64 stack The Omarchy edition's binaries (anubis, jackal-native, Lean checkers, archival checker, Z3 4.15.4, package) are all built from source and not committed. This captures the complete reproduction recipe, known-good digests, and the pending check-compiler trust-surface sign-off in one place so the stack is durable. Co-Authored-By: Claude Opus 4.8 --- OMARCHY_BUILD.md | 73 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 OMARCHY_BUILD.md diff --git a/OMARCHY_BUILD.md b/OMARCHY_BUILD.md new file mode 100644 index 0000000..f407271 --- /dev/null +++ b/OMARCHY_BUILD.md @@ -0,0 +1,73 @@ +# Omarchy JACKAL — full native rebuild recipe (Linux aarch64) + +Every binary in the Omarchy edition is built from source on this host; none are +committed (they are large and reproducible). This is the complete recipe to +rebuild the whole stack from a fresh clone. Times are approximate on 8 cores. + +Prerequisites (system): `pacman -S z3 cmake` (z3 is *supporting only*, not the +program-evidence anchor), `cargo`/`rustc` (stable), `elan` (Lean), `python3`. + +## 1. Anubis compiler (~2 min) + cd ~/Projects/anubis-lang + cargo build --release -p anubis --no-default-features # skip the Apple `prove` feature + install -m755 target/release/anubis ~/.local/bin/anubis + +## 2. Lean checkers (current) (~40 min incl. Mathlib cache) + cd ~/Projects/jackal/proofs/lean + export PATH="$HOME/.elan/bin:$PATH" + lake exe cache get # prebuilt Mathlib oleans — do NOT compile Mathlib + lake build jackal_cert_check jackal_gaussian_check jackal_int_cert_check jackal_parse_dump + # -> proofs/lean/.lake/build/bin/{jackal_cert_check,jackal_gaussian_check,jackal_int_cert_check} + +## 3. jackal-native (engine) (~1 min; needs Z3 for its contract obligations) + cd ~/Projects/jackal + ANUBIS_BIN=~/.local/bin/anubis anubis build jackal_calc.anb --out /tmp/jn + cp /tmp/jn/anubis_out ./jackal-native + +## 4. Archival v1.7.0 checker (native) (~40 min in a v1.7.0 worktree) + git worktree add /tmp/j170 v1.7.0 + cd /tmp/j170/proofs/lean && export PATH="$HOME/.elan/bin:$PATH" + lake exe cache get && lake build jackal_cert_check + mkdir -p ~/jackal-omarchy-archival + cp .lake/build/bin/jackal_cert_check ~/jackal-omarchy-archival/jackal_cert_check_v170 # expect sha d515cdc2 + git -C ~/Projects/jackal show v1.7.0:release/coverage/formal_coverage_inventory.json \ + > ~/jackal-omarchy-archival/formal_coverage_inventory_v170.json # expect sha 18ff7b1d + git worktree remove /tmp/j170 --force + +## 5. Approved Z3 4.15.4 (double-build, byte-reproducible) (~6 min) + # recipe: ~/omarchy-jackal-completion/z3build/build_recipe.sh (deterministic: + # SOURCE_DATE_EPOCH, -ffile-prefix-map, Release, static, --build-id=none) + URL=https://github.com/Z3Prover/z3/archive/refs/tags/z3-4.15.4.tar.gz # archive sha dae52625 + # build TWICE in isolated dirs; both MUST equal sha b6fcd93b (else STOP: not reproducible) + install -m700 /z3 ~/.local/share/JACKAL/z3/linux-aarch64/jackal_z3_v4154 + +## 6. Regenerate host evidence + manifest (seconds) + export PATH="$HOME/.elan/bin:$PATH" + # host-suffixed proof identities, compat floor, lean audit, archival identity/marker, + # approved_z3 marker — see the *.linux-aarch64* files under release/evidence, release/compat. + JACKAL_ANUBIS_COMPILER_PATH=~/.local/bin/anubis python3 -B release/tools/repin_linux.py --write + python3 -B tools/capability_inventory.py --write + python3 -B tools/capability_drift_gate.py --write-plugin-identity + +## 7. Build the package (~1 min) + JACKAL_ANUBIS_COMPILER_PATH=~/.local/bin/anubis JACKAL_DIST=~/jackal-dist-linux \ + JACKAL_ARCHIVAL_DIR=~/jackal-omarchy-archival \ + JACKAL_Z3_DIR=~/.local/share/JACKAL/z3/linux-aarch64 \ + sh release/build_package_linux.sh --build + # then update the linux-aarch64 pin block in plugins/jackel/scripts/provision_runtime.py + # with the printed tarball sha256/size + SHA256SUMS sha + extracted size. + +## 8. Install + /bin/sh plugins/jackel/scripts/launch_mcp.sh provision --tarball \ + ~/jackal-dist-linux/jackal-v1.7.3-linux-aarch64.tar.gz + omarchy-jackal doctor # FUNCTIONAL from live probes + +## Known-good digests + anubis compiler c6affa8c… jackal-native (rebuild) cert_check 89e4e42d… + gaussian_check 1f21c6b2… int_cert_check f2e26f50… v170 archival d515cdc2… + approved Z3 4.15.4 b6fcd93b… inventory-safe-v1 policy (frozen) 1b94350a… + +## Pending trust-surface sign-offs (do NOT self-authorize) + - jackal_anubis_check_program: needs an architect-designated Linux aarch64 anubis + CHECK COMPILER (version+sha256), double-built. See ~/omarchy-jackal-completion/ + evidence/I_check_compiler_finding.json. From 547c528c6148bc81402561954305a358f2c401e0 Mon Sep 17 00:00:00 2001 From: sicarii Date: Mon, 24 Aug 2026 07:36:12 -0400 Subject: [PATCH 07/22] omarchy: admit clean-source Linux/aarch64 check compiler (tool 41) Resolve the check-compiler sign-off for jackal_anubis_check_program on Linux/aarch64 via the architect's clean-source route, without reusing the historical macOS anchor (0d6a8f89) and without weakening inventory-safe-v1. - tools/anubis_program_verify.py: point the architecture-qualified check compiler anchor at the reproducible clean-source build 7cdafb30... (supersedes the pre-emitter d8c7d38b...). macOS anchor, both Z3 anchors, host-aware selection, and the frozen inventory-safe-v1 policy body (1b94350a...) are untouched. - release/evidence/approved_check_compiler.linux-aarch64: pin marker. - release/tools/repin_linux.py: append the approved-check-compiler- row. - release/build_package_linux.sh: ship the digest-checked check compiler and emit its manifest row. - release/MANIFEST{,.linux-aarch64}.sha256: rebind the verifier row to cafbd257... and the linux check-compiler row to 7cdafb30... - release/capability_inventory_v1.json: regenerate (verifier pin cafbd257...). - plugins/jackel/scripts/provision_runtime.py + PLUGIN_IDENTITY.sha256: repin the self-consistent Linux package (0b239bc7...). Verified end-to-end through the unmodified verifier and the real hermes plugin on a clean-install runtime: verified-program-evidence, 4 obligations independently RUP-replayed + approved-Z3-unsat; all negative controls fail closed; 41/41 tools present; drift gate + plugin identity + 12/12 adversarial A->B->A pass. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01KBajXqAr1zojERZGTTxY2n --- plugins/jackel/PLUGIN_IDENTITY.sha256 | 2 +- plugins/jackel/scripts/provision_runtime.py | 8 ++--- release/MANIFEST.linux-aarch64.sha256 | 3 +- release/MANIFEST.sha256 | 2 +- release/build_package_linux.sh | 14 ++++++++ release/capability_inventory_v1.json | 2 +- .../approved_check_compiler.linux-aarch64 | 1 + release/tools/repin_linux.py | 6 ++++ tools/anubis_program_verify.py | 33 ++++++++++++++++++- 9 files changed, 62 insertions(+), 9 deletions(-) create mode 100644 release/evidence/approved_check_compiler.linux-aarch64 diff --git a/plugins/jackel/PLUGIN_IDENTITY.sha256 b/plugins/jackel/PLUGIN_IDENTITY.sha256 index 7ce20fe..e2cf9cd 100644 --- a/plugins/jackel/PLUGIN_IDENTITY.sha256 +++ b/plugins/jackel/PLUGIN_IDENTITY.sha256 @@ -4,6 +4,6 @@ a165e6b00292a3768ad134562539dabf7874cf23bf9ac8f80e893f7970a63cdc .mcp.json b5916270588db1fbb68b4d520c5f5e9d0fabb84e26602f18ad0a2927a38cece9 mcp/server.py e4fb2996fc2a905a5101974ad6119e6c29fbc10cc8ca2f0223e18f89686dcdff scripts/launch_mcp.sh 878a9d94788a6c132fad151bbddebecb41c08615fe310278e586871fe8f9c44c scripts/launch_mcp.zsh -5308729c795255063f852967b3c2374ec4145ea42989dd669d2fcfa856324177 scripts/provision_runtime.py +c0c7662a455e2c2a37a704326d7f52b2113ab834bc9f3b38769983fcac55daa5 scripts/provision_runtime.py 60f6a068c5f6bd81a2ab80e8d9d873864aefdf7f6ae7c2db37fe6572b41f898f scripts/verify_plugin.py 63f726fbde9e4484424388ef5af68dce92d7f55a4af9354e7d812833f090c972 skills/jackel/SKILL.md diff --git a/plugins/jackel/scripts/provision_runtime.py b/plugins/jackel/scripts/provision_runtime.py index 71c4f5f..212234f 100644 --- a/plugins/jackel/scripts/provision_runtime.py +++ b/plugins/jackel/scripts/provision_runtime.py @@ -64,10 +64,10 @@ # upstream asset — install with `provision --tarball `. "asset": "jackal-v1.7.3-linux-aarch64.tar.gz", "url": None, - "package_size": 199147947, - "package_sha256": "17f917cac0866dbbf71bbdf1505a0efe479eb7604e807a1713acb96f6bb29989", - "extracted_size": 765433623, - "sha256sums_sha256": "ff40b2f37fa5d449e0f07ed604d5779d14f495aeb8707199b2e19ae67cb70972", + "package_size": 204082823, + "package_sha256": "0b239bc7a96d75537706ab1aebbc271150c663048f49711107ffe1b93f7d743d", + "extracted_size": 778795307, + "sha256sums_sha256": "bbbb7aa97368232580caa7914b00b577bc2601c41f38d4cd78b9a34178563671", "package_directory": "jackal-v1.7.3-linux-aarch64", }, # Gate declared for the planned bare-metal Linux x86_64 (iMac Pro). No pin diff --git a/release/MANIFEST.linux-aarch64.sha256 b/release/MANIFEST.linux-aarch64.sha256 index d38f691..0649005 100644 --- a/release/MANIFEST.linux-aarch64.sha256 +++ b/release/MANIFEST.linux-aarch64.sha256 @@ -43,8 +43,9 @@ domain_pack_registry domain_packs/registry_v1.json b71fb06d36cdee13e7fbf271a80df domain_pack_verifier tools/domain_pack_verify.py 53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b domain_pack_test_exists_checker tools/test_exists_verify.py 598cb99e1eb70c9410ca87345efee346f73e43aaf3625427dca17ea04231caea domain_pack_decision_checker tools/decision_verify.py f1ad7c9fbd4c1d899dbb4bebabbbeb97e97a56bd4b279ad7d8ec3722bf12e0f6 -anubis_program_verifier tools/anubis_program_verify.py 867f4bba40ce3f343d3f6a0be6ff35bc8135b08119e2506912d43dd1758a04e7 +anubis_program_verifier tools/anubis_program_verify.py cafbd25791225856c2914e9dc86b5dcd3e23d6cc0285b09800de34922f76d52e anubis_program_policy release/program/inventory_safe_v1.json 361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb claim_inference_registry release/claim/inference_registry_v1.json c70b33d5aee8071b5125e6a5f8ffe5226fc22a137d920c17d9b3463968be13f0 claim_unit_registry release/claim/unit_registry_v1.json d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c approved-z3-linux-aarch64 jackal_z3_v4154 b6fcd93b2ccec9aa848ac148c4d9b4270577ad046601f211784586eb9f0135c4 +approved-check-compiler-linux-aarch64 jackal_anubis_check_v1 7cdafb305f3b8df53e66e037433803d5154b4f5872758d9b15f7eeedc9670398 diff --git a/release/MANIFEST.sha256 b/release/MANIFEST.sha256 index b0609a7..1feae76 100644 --- a/release/MANIFEST.sha256 +++ b/release/MANIFEST.sha256 @@ -43,7 +43,7 @@ domain_pack_registry domain_packs/registry_v1.json b71fb06d36cdee13e7fbf271a80df domain_pack_verifier tools/domain_pack_verify.py 53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b domain_pack_test_exists_checker tools/test_exists_verify.py 598cb99e1eb70c9410ca87345efee346f73e43aaf3625427dca17ea04231caea domain_pack_decision_checker tools/decision_verify.py f1ad7c9fbd4c1d899dbb4bebabbbeb97e97a56bd4b279ad7d8ec3722bf12e0f6 -anubis_program_verifier tools/anubis_program_verify.py 867f4bba40ce3f343d3f6a0be6ff35bc8135b08119e2506912d43dd1758a04e7 +anubis_program_verifier tools/anubis_program_verify.py cafbd25791225856c2914e9dc86b5dcd3e23d6cc0285b09800de34922f76d52e anubis_program_policy release/program/inventory_safe_v1.json 361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb claim_inference_registry release/claim/inference_registry_v1.json c70b33d5aee8071b5125e6a5f8ffe5226fc22a137d920c17d9b3463968be13f0 claim_unit_registry release/claim/unit_registry_v1.json d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c diff --git a/release/build_package_linux.sh b/release/build_package_linux.sh index e27b8b8..72fbc38 100755 --- a/release/build_package_linux.sh +++ b/release/build_package_linux.sh @@ -359,6 +359,19 @@ APPROVED_Z3_SHA256="b6fcd93b2ccec9aa848ac148c4d9b4270577ad046601f211784586eb9f01 /bin/cp "$Z3DIR/jackal_z3_v4154" "$PKG/jackal_z3_v4154" /bin/chmod 0755 "$PKG/jackal_z3_v4154" +# Omarchy edition: ship the architecture-qualified approved CHECK compiler +# (native Linux aarch64 anubis, double-built from public source). Verified +# against the manifest-pinned identity. +CCDIR="${JACKAL_CC_DIR:?set JACKAL_CC_DIR to the approved native check compiler}" +require_regular "$CCDIR/jackal_anubis_check_v1" +APPROVED_CC_SHA256="7cdafb305f3b8df53e66e037433803d5154b4f5872758d9b15f7eeedc9670398" +[ "$(sha256 "$CCDIR/jackal_anubis_check_v1")" = "$APPROVED_CC_SHA256" ] || { + echo "PACKAGE_V173_REFUSED reason=approved-check-compiler-identity observed=$(sha256 "$CCDIR/jackal_anubis_check_v1")" >&2 + exit 4 +} +/bin/cp "$CCDIR/jackal_anubis_check_v1" "$PKG/jackal_anubis_check_v1" +/bin/chmod 0755 "$PKG/jackal_anubis_check_v1" + for relative in \ tests/release_validate.py \ tools/gaussian_certificate.py tools/gaussian_release.py \ @@ -737,6 +750,7 @@ domain_pack_verifier tools/domain_pack_verify.py $(sha256 "$PKG/tools/domain_pac domain_pack_test_exists_checker tools/test_exists_verify.py $(sha256 "$PKG/tools/test_exists_verify.py") domain_pack_decision_checker tools/decision_verify.py $(sha256 "$PKG/tools/decision_verify.py") anubis_program_verifier tools/anubis_program_verify.py $(sha256 "$PKG/tools/anubis_program_verify.py") +approved_check_compiler_linux_aarch64 jackal_anubis_check_v1 $(sha256 "$PKG/jackal_anubis_check_v1") anubis_program_policy program/inventory_safe_v1.json $(sha256 "$PKG/program/inventory_safe_v1.json") approved_z3_linux_aarch64 jackal_z3_v4154 $(sha256 "$PKG/jackal_z3_v4154") EOF diff --git a/release/capability_inventory_v1.json b/release/capability_inventory_v1.json index 9f1ed3f..bb85cbf 100644 --- a/release/capability_inventory_v1.json +++ b/release/capability_inventory_v1.json @@ -1 +1 @@ -{"catalog":{"path":"plugin/hermes/tools.json","sha256":"53c823f07db512b82e01a4f132ff43be426b4b227c436e8853c5144ae0504e87","version":"v1.7.3"},"inputs":[{"path":"tools/capability_inventory.py","sha256":"a966660ef94d7b788be9f92451a78e43b41e12ae2c4e942834c1703994c2ccc0"},{"path":"plugin/hermes/tools.json","sha256":"53c823f07db512b82e01a4f132ff43be426b4b227c436e8853c5144ae0504e87"},{"path":"plugin/hermes/profiles/core.json","sha256":"49f33ba23cca5ab940f1929604f61491bc914d092f291cda4fe4f06b37d042d3"},{"path":"plugin/hermes/profiles/formal.json","sha256":"9be2b3144486311d9ba7f1d41c5033eb8e2553e9d12b71d46e512401f57a084b"},{"path":"plugin/hermes/profiles/full.json","sha256":"0db937da01737bbc0341a591ecd23e55008d8ffc02368517c7d1e7da8b309dec"},{"path":"plugin/hermes/server.py","sha256":"4c42725d797ac78ed20d3e843e602b1c60c88bd13f74e06c65a6b4016b3b7daf"},{"path":"plugins/jackel/.codex-plugin/plugin.json","sha256":"49bbd046759b045add1caf1f19300431fe7d697b59bfd93b57daf1d7edb709ff"},{"path":"plugins/jackel/mcp/server.py","sha256":"b5916270588db1fbb68b4d520c5f5e9d0fabb84e26602f18ad0a2927a38cece9"},{"path":"release/MANIFEST.sha256","sha256":"63fdf1062a78dace5907af4c12a894c7ba73c1ed9e252e0cf475c121cead373b"},{"path":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"path":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"path":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"}],"release":{"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"state":"v1.7.3","statement":"Published release identity; the annotated v1.7.3 tag and GitHub release must bind these exact bytes.","version":"v1.7.3"},"schema":"jackal-capability-inventory-v1","status_vocabulary":["bounded","checked","estimated","exact","formal-bounded","indeterminate","model-based","ok","refused","structural-exact","verified","verified-program-evidence","verified-program-receipt"],"tool_count":41,"tools":[{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_range_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"826bed7e2645735d5d333040eaa8c28425df90b6e87f8dd6aa94df1cc40ace45","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded receipt with the certificate embedded (or refuse). Inputs: expression: Anubis expression in the single variable x, restricted to the certified fragment.; input_lo: Interval lower bound as an integer or reduced ℚ (e.g. '1', '2/3').; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-gaussian","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_gaussian_integral","profiles":["formal","full"],"refusal_boundary":"Only the exact catalog-declared Gaussian form and canonical rational bounds/tolerance are admitted. Any other form, failed enclosure, checker rejection, or pin/identity mismatch refuses without downgrade.","release_state":"v1.7.3","schema_sha256":"4a43f67d68610c9e7b13f8bc8195c6c3e9ea24493494eb5aca8e768d707adb13","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a zero-libm formal-bounded Gaussian integral receipt, rerun the pinned checker, or refuse without downgrade. Inputs: expression: Exact canonical exp(-A*(x-mu)^2) expression; all other expressions refuse.; input_lo: Integration lower bound as a canonical rational.; input_hi: Integration upper bound as a canonical rational.; tolerance: Maximum enclosure width as a positive canonical rational."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-int-cert","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_bound_cert","profiles":["formal","full"],"refusal_boundary":"Only the request-bound v1.7.2 composed-integral fragment and canonical bounds/tolerance are admitted. Request-unbound v1.7.0 evidence, unsupported syntax, failed subdivision, checker rejection, or identity mismatch refuses without using the weaker float lane.","release_state":"v1.7.3","schema_sha256":"1229ede1ee518a9b19d3a201268e598fac6fd52fd2eef1bb379f920d6093b9cd","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a request-bound certified composed definite-integral formal receipt (v1.7.2): the untrusted exact-rational producer mirrors the engine's adaptive subdivision, the pinned Lean-proved jackal_int_cert_check binds the exact raw expression/bounds/tolerance and re-checks the whole subdivision-tree certificate (theorem int_cert_sound), and the receipt is independently re-verified before returning. Request-unbound v1.7.0 receipts are revoked. Certified fragment: num/var/neg/add/sub/mul/div/pow(0..4096)/sin/cos/abs in x. Everything else refuses. The weaker float lane jackal_integrate_bound stays status=bounded and is NOT this tool. Inputs: expression: Integrand in the single variable x, restricted to the certified fragment (num/var/neg/add/sub/mul/div/pow/sin/cos/abs).; input_lo: Integration lower bound as an integer or reduced canonical rational (e.g. '0', '2/3').; input_hi: Integration upper bound as a canonical rational, strictly above input_lo.; tolerance: Maximum enclosure width as a positive canonical rational (e.g. '1/100')."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-receipt-registry","identities":[{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_verify_receipt","profiles":["core","formal","full"],"refusal_boundary":"Only closed-registry range/rational, Gaussian, and current request-bound int-cert receipts matching independent caller expectations are replayed. Unknown epochs/variants, copied rather than caller-pinned expectations, revoked int-cert evidence, or checker/pin mismatch refuses.","release_state":"v1.7.3","schema_sha256":"988b83705212769a01eb2e5f5b44322b5728d5fd86eef4f64f7a4a37e378fc1f","status_classes":["verified","refused"],"supported_fragment":"Re-run the matching pinned Lean-proved checker over an embedded certificate using a closed epoch/variant registry: current v1.7.2 range/rational and request-bound int_cert, replay-only v1.5.0 range/rational, or Gaussian v1.5.0. Request-unbound v1.7.0 int_cert receipts refuse. Inputs: receipt: A jackal-formal-receipt-v1 JSON document.; expected_release_epoch: Caller-authorized release epoch, not copied from the receipt.; expected_command: Caller-authorized operation: range-bound-cert or integrate.; expected_expression: Exact raw expression supplied by the caller.; expected_input_lo: Exact raw lower-bound token supplied by the caller.; expected_input_hi: Exact raw upper-bound token supplied by the caller.; expected_tolerance: Exact raw tolerance token; required for Gaussian and int_cert receipts and forbidden for range receipts."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_sqrt_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"bc611de421d812aa6d6d8772fb986c17bcde74d7fe70ea31ff22433335d67c6d","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q sqrt(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'sqrt(x)' on a canonical rational interval; every other expression refuses without downgrade. v1.4.0 fragment extension. Inputs: expression: Must equal 'sqrt(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational (e.g. '2', '1/4'); must be >= 0.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_exp_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"9cc7bee07eebc566a9e267ad1b30c10a73cb25c18090ed2f9a3e9ec48550b928","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q exp(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'exp(x)' on a canonical rational interval [lo, hi] (general-sign since v1.5.0); every other expression refuses without downgrade. v1.4.1 fragment extension. Inputs: expression: Must equal 'exp(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational; any sign (general-sign since v1.5.0).; input_hi: Interval upper bound (canonical rational, hi >= lo); the producer picks a Taylor degree with 2*hi <= n+1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_ln_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"16dfb2b64dc9e290e1c062eba898233b04b187f1b244f6cc06433c48d1b7da45","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q ln(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'ln(x)' on a canonical rational interval with lo > 0; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'ln(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational; must be > 0.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_sin_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"d578799057048871ff13eca207bda2f9564261fce975801904d8cb34370cc7fe","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q sin(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'sin(x)' on a canonical rational interval whose midpoint m satisfies |m| <= 1; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'sin(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo); midpoint (lo+hi)/2 must satisfy |m| <= 1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_cos_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"d0f575ac0dbfe5e64aede075ae30bb1a625f05963e772febca6ac180b29f062b","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q cos(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'cos(x)' on a canonical rational interval whose midpoint m satisfies |m| <= 1; every other expression refuses without downgrade. Shares the sin_rat producer (--op cos). v1.5.0 fragment extension. Inputs: expression: Must equal 'cos(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo); midpoint (lo+hi)/2 must satisfy |m| <= 1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_atan_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"f16e48c7a37e284e124fe20766c7db2b90b4eed8fb748c2efebc9ee7c4b80767","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q atan(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'atan(x)' on a canonical rational interval; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'atan(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_tanh_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"6f9b24d732cc6fc2b0ad9ef7d51fa8cd88f2a344b3152c54f288f6a25a8fe05a","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q tanh enclosure via the untrusted composite producer + Lean-proved checker. NO libm on the proof-decision path. tanh is not an engine grammar token: admits ONLY the literal composite expression '1-2/(exp(2*x)+1)' (= tanh(x) mathematically) on a canonical rational interval with |lo|,|hi| <= 20; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal '1-2/(exp(2*x)+1)' after whitespace normalization (the frozen tanh-defining composite).; input_lo: Interval lower bound as an integer or reduced rational; |lo| <= 20.; input_hi: Interval upper bound (canonical rational, hi >= lo); |hi| <= 20."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_exact","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"42319cf6d3e3f7a8da025e880b8dfc02eb2c6e3128f8b93c11f41545d8bf1d8d","status_classes":["exact","refused"],"supported_fragment":"Exact big-rational arithmetic (status=exact). NOT formal: computationally exact, outside the Lean certificate chain. Inputs: expression: Integers, decimals, + - * / ^ (integer exponents), parentheses. Everything else refuses."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_evaluate","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"5baa3a344309d714a8b66c9fb4a14a97c8182b3cfe1326faa2e9967840eee17c","status_classes":["estimated","refused"],"supported_fragment":"IEEE f64 expression evaluation (status=estimated). A plain number, honestly labeled: no bound, no proof. Inputs: expression: Full expression grammar incl. transcendental functions and constants."},{"assurance_classes":["checked"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_diff","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"605972a25cde65779e921b8a27b7f1a0c19d540f5330791ec0fb571cccf858ad","status_classes":["checked","refused"],"supported_fragment":"Symbolic d/dx with numeric self-verification (status=checked). Sampled agreement is a check, not a proof of identity. Inputs: expression: Expression in x; non-differentiable functions fail closed."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"6d05a705ff580a831f75cbcd2079fe88c3b5d9c858bc6b0c3182ec55aa27cd27","status_classes":["estimated","refused"],"supported_fragment":"Fixed-grid Simpson + Richardson error estimate (status=estimated). Grid-limited: NOT a bound. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; panels: Panel count (e.g. '200')."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_adaptive","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"174132e83bff6d18972cf5d88b072b12d7102cad8fdf05197165c64bfac4fea1","status_classes":["estimated","refused"],"supported_fragment":"Adaptive Simpson with refusal semantics (status=estimated). Refuses when unconverged; agreement is still not a bound. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; tolerance: Local tolerance (e.g. '1e-9')."},{"assurance_classes":["bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_bound","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"9932617903499a2ed2baa4ac213f061f422bd8f2e60bca5bf05225a9f9f788a0","status_classes":["bounded","refused"],"supported_fragment":"Certified interval enclosure of an integral (status=bounded). CONDITIONAL on the stated f64/libm rounding model; implementation campaign-tested, NOT mechanized. Never labeled formal. For a Lean-checked formal-bounded composed enclosure over the certified fragment, use jackal_integrate_bound_cert instead. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; tolerance: Max enclosure width (e.g. '1e-6')."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_solve","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"caf1f55ca8ad1fef2e0fb4f5f5bb600edb147f257427de650335500979c13501","status_classes":["estimated","refused"],"supported_fragment":"Bisection root with residual + first-order conditioning diagnostics (status=estimated). Inputs: expression: f(x) whose root is sought.; input_lo: Bracket lower bound (sign change required).; input_hi: Bracket upper bound."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"ea4ca54f74334d678c3daf9c6686fca186041d27bb2f02dabca21a7747e7d416","status_classes":["exact","refused"],"supported_fragment":"Canonical s-expression + SHA-256 of any parsed expression (status=exact). NOT formal: exact computation outside the Lean certificate chain; no exact-cert emitted. Inputs: expression: Any expression the engine grammar parses."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"199fd63f51398c6e883a407d8e2435e42903e9c76f0227d815f3456b3568d9bc","status_classes":["exact","refused"],"supported_fragment":"Dense Q[x] canonical form, degree <= 64 (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Polynomial expression in x within the poly fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_eq","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"76d9390f705758c6ec2d5fe77cd6a1391908f93ef218ebfd5111c067dc32a819","status_classes":["exact","refused"],"supported_fragment":"Decidable polynomial identity over Q[x] (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: lhs: Left polynomial expression in x.; rhs: Right polynomial expression in x."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_gcd","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"dfff2a285e732d52520ea6fe5efabdab5bd6d956c224f30d163ccbbdbd406a5c","status_classes":["exact","refused"],"supported_fragment":"Monic polynomial gcd over Q[x] via Euclid (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: lhs: Left polynomial expression in x.; rhs: Right polynomial expression in x."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_ratfunc_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"3d4c7d73d13aa88606e9e005b7731c19ac63f9fe559b38e6ff777f979afd3b40","status_classes":["exact","refused"],"supported_fragment":"Rational-function canonical form P/Q, gcd-reduced, monic denominator, explicit denominator-nonzero side condition (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Rational-function expression in x within the ratfunc fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_roots_isolate","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"ea98289e6b6319b7c0b3e6e9832e07ff4a9dd06be1d7862956c50df6e1785978","status_classes":["exact","refused"],"supported_fragment":"Sturm-sequence isolation of all distinct real roots (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Polynomial expression in x within the poly fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_alg_sign","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"b4ad3c632887bc8875f8334dea3391017d73f30fa4895d988062882e89c2c1a5","status_classes":["exact","refused"],"supported_fragment":"Exact sign of a Q[x] polynomial at a rational point (status=exact). NOT formal; no exact-cert emitted. Inputs: expression: Polynomial expression in x within the poly fragment.; point: Rational evaluation point (e.g. '3/2')."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_alg_cmp","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"bfea42d3f97e6f0403d11155d667dfec7000719e2aa3af67c8897989a9e2eee4","status_classes":["exact","refused"],"supported_fragment":"Order decision between two isolated real algebraic numbers (status=exact). NOT formal; no exact-cert emitted. Inputs: p: First defining polynomial in x.; a1: First isolating interval lower bound (rational).; b1: First isolating interval upper bound (rational).; q: Second defining polynomial in x.; a2: Second isolating interval lower bound (rational).; b2: Second isolating interval upper bound (rational)."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_xgcd","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"1c7fb606e43e71eeb4ab288c08ea4a6c89efd95beb3f802e084d5d3c1a3beaf6","status_classes":["exact","refused"],"supported_fragment":"Extended gcd with Bezout certificate (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: a: First integer.; b: Second integer."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_mod_pow","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"b3edc74b3901989b9248f8b89feaed2cc396e218abf9ccfca7ab53a99a9c7bc1","status_classes":["exact","refused"],"supported_fragment":"Modular exponentiation via square-and-multiply (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: base: Base integer.; exp: Nonnegative exponent integer.; mod: Modulus integer >= 1."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_mod_inv","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"d0826f19759afacd20d4a5f0d6704a52bce158c6950bb852a5e0774886a4abd7","status_classes":["exact","refused"],"supported_fragment":"Modular inverse with product certificate (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: a: Integer to invert.; m: Modulus integer >= 2; gcd(a, m) must be 1."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_crt","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"d44aebbbcb3b00ad0d192581533c5cfdb164e26431f3ed850406c8ecfa5044b4","status_classes":["exact","refused"],"supported_fragment":"Chinese remainder reconstruction over pairwise-coprime moduli, up to 16 pairs (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: args: Space-separated residue/modulus pairs: 'r1 m1 r2 m2 [...]' (e.g. '2 3 3 5 2 7')."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_divides","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"1191b2b4ce3a9a5c3a1dafb0917fad46ca9c3375c73f4ae59ff7a389d513adb4","status_classes":["exact","refused"],"supported_fragment":"Exact divisibility decision (status=exact). NOT formal; no exact-cert emitted. Inputs: a: Candidate divisor integer.; b: Dividend integer."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_prime_cert","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"3ff03881b24f8fd94db68b210874010e66ce0e3d32666d98a21c1bc40ccc5646","status_classes":["exact","refused"],"supported_fragment":"Pratt primality certificate or composite divisor witness, budgeted and fail-closed (status=exact; n <= 10^60, Pratt tree depth <= 64, nodes <= 512). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: n: Integer >= 2, at most 61 digits."},{"assurance_classes":["estimated","model-based","checked","bounded","formal-bounded","exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"claim-router","identities":[{"label":"claim_kernel","locator":"tools/claim_kernel.py","sha256":"77b0f85ad5fb7214f88898b60ea29ea9fd7be740c38b655388444e6e5181f348"},{"label":"claim_router","locator":"tools/claim_router.py","sha256":"02328cf177a0423bdc5cbca6ec0ea946bb0679bbd3dc6c24140d32598e575afb"},{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"},{"label":"claim_inference_registry","locator":"release/claim/inference_registry_v1.json","sha256":"c70b33d5aee8071b5125e6a5f8ffe5226fc22a137d920c17d9b3463968be13f0"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_claim","profiles":["core","formal","full"],"refusal_boundary":"Only jackal-claim-request-v1 and its closed step vocabulary are compiled. Policy, identity, schema, route, or assurance failures refuse; fallback is off by default and any caller-enabled fallback remains explicit in the route trace rather than silently changing assurance.","release_state":"v1.7.3","schema_sha256":"4d2703ff772433f39ac8b6555727e856685b0e5042b9c2cc8fcaa4402d6b9153","status_classes":["ok","refused"],"supported_fragment":"Compile a structured jackal-claim-request-v1 into a canonical, content-addressed jackal-claim-bundle-v1 evidence graph through the deterministic policy router. Routes through exact, current/archival range-family, Gaussian, request-bound composed-integral, machine, and unit lanes; emits a route trace naming candidates and refusal reasons; and refuses rather than silently downgrading (allow_fallback defaults false). The bundle is independently replayable via jackal_verify_bundle. Inputs: request: jackal-claim-request-v1 object: {schema, steps:[{id, op, ...}], root, policy?, nonce?, emitted_at_unix?, max_age_seconds?, expires_at_unix?}. Step ops: input, exact, enclose, gaussian, integrate_cert, machine, interval_add/sub/mul/div, threshold, decision, convert, and, model, passthrough, attach."},{"assurance_classes":["estimated","model-based","checked","bounded","formal-bounded","exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"claim-verifier","identities":[{"label":"claim_verifier","locator":"tools/claim_bundle_verify.py","sha256":"e0fcb9540c730bd9bb492b528ed42d29d49fc775b3aa0f9b831b6264fd68fd22"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"},{"label":"claim_inference_registry","locator":"release/claim/inference_registry_v1.json","sha256":"c70b33d5aee8071b5125e6a5f8ffe5226fc22a137d920c17d9b3463968be13f0"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_verify_bundle","profiles":["core","formal","full"],"refusal_boundary":"Only canonical bundles matching separately caller-pinned epoch, policy, root proposition, time, and nonce are replayed. Semantic, graph, freshness, evidence, checker, or pin ambiguity returns refused or indeterminate exactly as declared; it is never converted to success.","release_state":"v1.7.3","schema_sha256":"9e3acec17637a352bc88e3b08e8679a34f1efae3539fe1cce05646212be4cb5f","status_classes":["verified","refused","indeterminate"],"supported_fragment":"Independently replay a jackal-claim-bundle-v1 against caller-pinned expectations. The standalone dependency-free verifier recomputes every canonical byte and hash, revalidates the DAG, selects only the closed current/archival range, Gaussian, or current request-bound int-cert checker/proof tuple, re-runs embedded evidence, recomputes machine/unit mathematics, re-evaluates every inference rule and assurance-axis propagation, enforces consequence-class floors and policy, and recomputes the deterministic rendering. Returns verified | refused | indeterminate with exact reasons — never a generic green badge. Inputs: bundle: The jackal-claim-bundle-v1 object to replay.; expected_release_epoch: Caller-pinned epoch (e.g. 'v1.6.0'); never copied from the bundle.; expected_policy_sha256: Caller-pinned SHA-256 of the canonical policy bytes.; expected_root_proposition: Caller-pinned canonical root proposition IR object.; verification_time_unix: Caller-supplied verification time (unix seconds) for freshness/expiry checks.; expected_nonce: Caller nonce; the bundle root must bind exactly this nonce."},{"assurance_classes":["structural-exact"],"consequence_ceiling":"informational","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"structural-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_test_exists_checker","locator":"tools/test_exists_verify.py","sha256":"598cb99e1eb70c9410ca87345efee346f73e43aaf3625427dca17ea04231caea"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_test_exists","profiles":["full"],"refusal_boundary":"Only byte-exact source/citation structure described by the schema is accepted after independent file-byte recomputation. Path traversal, malformed symbols/hashes, missing text/declarations, or checker mismatch refuses; the result never asserts test execution or correctness.","release_state":"v1.7.3","schema_sha256":"9685ecf3bcf78a3a26916455cc528cdeac137420e8694447e2865b33890f9d46","status_classes":["structural-exact","refused"],"supported_fragment":"Domain pack jackal.programming.source, operation programming.source.test_exists.v1, routed through pack-route. States one byte-exact STRUCTURAL fact: a declaration-shaped occurrence of `symbol` exists at `declaration_line` in a file whose content hash is exactly `file_sha256`, and the file contains exactly `declaration_count` such occurrences. The engine validates the canonical FORM; the manifest-pinned independent checker tools/test_exists_verify.py then recomputes every claimed field from the real bytes on disk and only an ACCEPT verdict returns success, so a misstated hash, line or count refuses instead of minting a certificate. ASSURANCE ceiling exact; CONSEQUENCE ceiling informational, and the second does not rise with the first: a test-exists-cert is NEVER evidence that the code under test is correct, that the test executes, that it is collected by any runner, or that it asserts anything at all. NOT formal: no Lean checker and no theorem are involved. Do not cite this certificate in support of a correctness claim. Inputs: file_path: Repository-relative path token; absolute paths and parent traversal refuse `prog-path`.; file_sha256: Exactly 64 lowercase hex characters; the checker recomputes it from the file bytes.; symbol: Identifier of the declaration; a non-identifier refuses `prog-symbol`.; declaration_line: 1-based line of the declaration as a canonical positive integer.; declaration_count: Total declaration-shaped occurrences of `symbol` in the file; `0` refuses `prog-absent`."},{"assurance_classes":["structural-exact"],"consequence_ceiling":"informational","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"structural-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_test_exists_checker","locator":"tools/test_exists_verify.py","sha256":"598cb99e1eb70c9410ca87345efee346f73e43aaf3625427dca17ea04231caea"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_claim_cites_test","profiles":["full"],"refusal_boundary":"Only byte-exact source/citation structure described by the schema is accepted after independent file-byte recomputation. Path traversal, malformed symbols/hashes, missing text/declarations, or checker mismatch refuses; the result never asserts test execution or correctness.","release_state":"v1.7.3","schema_sha256":"69a533155bde04bfd5dedd43e9d63acd02f3e2773757936e9e1714458e20abd4","status_classes":["structural-exact","refused"],"supported_fragment":"Domain pack jackal.programming.source, operation programming.source.claim_cites_test.v1, routed through pack-route. Resolves a citation: `claim_text` occurs verbatim in the document at `doc_path`/`doc_sha256`, and `symbol` has a declaration-shaped occurrence in the cited test file at `test_path`/`test_sha256`. Resolution is all this establishes. It does NOT establish that the cited test covers, exercises or supports the claim — the cited test may check something entirely different, which is the exact defect this operation exists to bound rather than hide. The manifest-pinned tools/test_exists_verify.py re-runs over the certificate and only ACCEPT returns success, so a claim text absent from the document or a dangling citation refuses. ASSURANCE ceiling exact; CONSEQUENCE ceiling informational, and the second does not rise with the first. NOT formal: no Lean checker and no theorem are involved. Inputs: doc_path: Repository-relative path of the document making the claim.; doc_sha256: Exactly 64 lowercase hex characters for the document bytes.; claim_text: The claim sentence, verbatim, 1..2048 bytes; it must occur in the document.; test_path: Repository-relative path of the cited test file.; test_sha256: Exactly 64 lowercase hex characters for the cited test file bytes.; symbol: Identifier the citation resolves to inside the cited test file."},{"assurance_classes":["exact"],"consequence_ceiling":"decision-boundary","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"decision-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_decision_checker","locator":"tools/decision_verify.py","sha256":"f1ad7c9fbd4c1d899dbb4bebabbbeb97e97a56bd4b279ad7d8ec3722bf12e0f6"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_decision_rank","profiles":["full"],"refusal_boundary":"Only 2..6 schema-valid options under a caller-declared admissible numeric criterion are ranked. Invalid shape/sense/unit, value-judgment criteria, zero top margin, or checker mismatch refuses; caller values are not treated as measurements or confidence intervals.","release_state":"v1.7.3","schema_sha256":"843fe08464d40d97094eeb6424c0c29a3e2617172ba56262ca4122468a8bb92f","status_classes":["exact","refused"],"supported_fragment":"Domain pack jackal.decision.matrix, operation decision.matrix.rank.v1, routed through pack-route. Orders 2..6 labelled options by a caller-declared numeric criterion and emits a jackal-decision-cert-v1 naming the selected option, the runner-up and the exact margin; the manifest-pinned tools/decision_verify.py recomputes the whole ordering from the certificate's own option values and only ACCEPT returns success. Criterion admissibility is decided by the engine against a fixed word list, so a bare value judgment refuses `decision-value-judgment`; a top-two tie refuses `decision-margin-zero`. ASSURANCE ceiling exact; CONSEQUENCE ceiling decision-boundary. The arithmetic is exact and the choice of criterion is not: the declared criterion and the declared option values remain the caller's, this result is not a claim that the criterion is the right one, the values are not measurements, and the margin is not a confidence interval. For the closed-unit lane that additionally requires a declared unit, use jackal_decision_rank_v2. NOT formal: no Lean checker and no theorem are involved. Inputs: decision_id: Caller's identifier for this decision, bound into the certificate. Bytes are restricted to [A-Za-z0-9_]; anything else refuses `prog-symbol`.; criterion: The declared numeric criterion (e.g. 'latency_ms'); a value judgment refuses `decision-value-judgment`.; sense: Exactly 'min' or 'max'; anything else refuses `decision-sense-unknown`.; options: 2..6 whitespace-separated `label value` pairs, e.g. 'a 10 b 20 c 30'. Values are canonical integers. A label containing whitespace shifts the pairing and refuses `pack-args-shape`; it is never silently re-paired."},{"assurance_classes":["exact"],"consequence_ceiling":"decision-boundary","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"decision-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_decision_checker","locator":"tools/decision_verify.py","sha256":"f1ad7c9fbd4c1d899dbb4bebabbbeb97e97a56bd4b279ad7d8ec3722bf12e0f6"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_decision_rank_v2","profiles":["full"],"refusal_boundary":"Only 2..6 schema-valid options under a caller-declared admissible numeric criterion are ranked. Invalid shape/sense/unit, value-judgment criteria, zero top margin, or checker mismatch refuses; caller values are not treated as measurements or confidence intervals.","release_state":"v1.7.3","schema_sha256":"cdc8abba09426977a5319b52410204f21e2e1eb7b38a9de31de751fcb862e78a","status_classes":["exact","refused"],"supported_fragment":"Domain pack jackal.decision.matrix, operation decision.matrix.rank.v2, routed through pack-route. Same deterministic ordering as jackal_decision_rank, plus a REQUIRED declared unit drawn from a closed vocabulary: the 65 canonical ids of release/claim/unit_registry_v1.json excluding the dimensionless identity `one` (66 ids in the registry, `one` is not admitted here). Matching is exact-token and case-sensitive; an alias, a spelled-out name such as 'millisecond', a different case, or the dimensionless identity all refuse `decision-unit-unknown`, and an empty unit refuses `decision-unit-missing`. Emits jackal-decision-cert-v2, re-checked by the manifest-pinned tools/decision_verify.py; only ACCEPT returns success. ASSURANCE ceiling exact; CONSEQUENCE ceiling decision-boundary. Honest residual: a declared unit is NOT a measurement. The closed vocabulary forces the caller to name a dimension, and nothing more — a value-judgment criterion that survives the engine's word list is still accepted when a real unit is declared (`most_elegant` in `ms` ranks), and the values themselves remain caller-declared. NOT formal: no Lean checker and no theorem are involved. Inputs: decision_id: Caller's identifier for this decision, bound into the certificate. Bytes are restricted to [A-Za-z0-9_]; anything else refuses `prog-symbol`.; criterion: The declared numeric criterion; a value judgment refuses `decision-value-judgment` even with an admissible unit.; unit: One canonical unit id from release/claim/unit_registry_v1.json, excluding `one`. Exact token, case-sensitive: 'ms' is admitted, 'millisecond' and 'MS' refuse `decision-unit-unknown`.; sense: Exactly 'min' or 'max'; anything else refuses `decision-sense-unknown`.; options: 2..6 whitespace-separated `label value` pairs, e.g. 'a 10 b 20 c 30'. Values are canonical integers. A label containing whitespace shifts the pairing and refuses `pack-args-shape`; it is never silently re-paired."},{"assurance_classes":["verified-program-evidence"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"867f4bba40ce3f343d3f6a0be6ff35bc8135b08119e2506912d43dd1758a04e7"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_check_program","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"177cfcf9dfcd6bbc6e657eb83b88f04bfedaa0f28f81307077a776e2052df1e2","status_classes":["verified-program-evidence","refused"],"supported_fragment":"Run a caller-pinned Anubis compiler only as `build --evidence` in Safe mode, never execute the compiled artifact, then independently close and replay the resulting strict anubis.program-evidence.v3 package under inventory-safe-v1. Emits only verified-program-evidence or a named refusal. This profile checks producer-attested function/policy inventories but explicitly does not establish policy-construct totality, source-to-VC proof, SMT-to-CNF proof, source-native refinement, runtime behavior, or universal soundness. Inputs: source_path: Local regular non-symlink Anubis source path.; anubis_bin: Local regular non-symlink Anubis executable; caller-pinned and hashed before/after build.; expected_source_sha256: Caller-pinned exact source SHA-256.; expected_compiler_sha256: Caller-pinned approved Anubis executable SHA-256.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1; contracted-safe-v1 refuses.; nonce: Caller nonce bound into the receipt.; out_root: New local output root; existing paths refuse."},{"assurance_classes":["verified-program-evidence"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"867f4bba40ce3f343d3f6a0be6ff35bc8135b08119e2506912d43dd1758a04e7"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_verify_program","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"45c7aae87c329925f6bd6b9100efc7d099d70fcaeaba915ee59937f019e1153d","status_classes":["verified-program-evidence","refused"],"supported_fragment":"Independently verify caller-selected Anubis Safe source and evidence bytes under inventory-safe-v1: strict v3 roster, exact manifest closure, source/compiler/artifact/policy pins, producer-summary reconciliation, one-to-one solver/proof paths and counters, approved Z3 UNSAT replay, and independent RUP replay. Never executes the artifact and never claims independent policy-construct totality or source-native refinement. Inputs: source_path: Caller-selected regular non-symlink Anubis source path.; evidence_dir: Caller-selected strict anubis.program-evidence.v3 directory.; expected_source_sha256: Caller-pinned exact source SHA-256.; expected_compiler_sha256: Caller-pinned producer executable SHA-256.; expected_artifact_sha256: Caller-pinned sealed artifact SHA-256; artifact bytes are read but never executed.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1.; nonce: Caller nonce bound into the receipt."},{"assurance_classes":["verified-program-receipt"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"867f4bba40ce3f343d3f6a0be6ff35bc8135b08119e2506912d43dd1758a04e7"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_verify_program_receipt","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"6bb75d81aebf6f2b3b20900357204e9ef0858cdac412ea016868028cdd2a67d3","status_classes":["verified-program-receipt","refused"],"supported_fragment":"Recompute a jackal-anubis-program-receipt-v1 from caller-selected source/evidence bytes and independent caller pins, rejecting outer-digest-consistent semantic laundering. Success is only verified-program-receipt; it does not raise the underlying inventory-safe-v1 assurance ceiling. Inputs: receipt: Program receipt object to replay; its own pins are never trusted.; source_path: Caller-selected regular source path.; evidence_dir: Caller-selected evidence directory.; expected_source_sha256: Caller-pinned source SHA-256.; expected_compiler_sha256: Caller-pinned compiler SHA-256.; expected_artifact_sha256: Caller-pinned artifact SHA-256.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1.; nonce: Caller nonce; never copied from the receipt."}],"unique_tool_count":41} +{"catalog":{"path":"plugin/hermes/tools.json","sha256":"53c823f07db512b82e01a4f132ff43be426b4b227c436e8853c5144ae0504e87","version":"v1.7.3"},"inputs":[{"path":"tools/capability_inventory.py","sha256":"a966660ef94d7b788be9f92451a78e43b41e12ae2c4e942834c1703994c2ccc0"},{"path":"plugin/hermes/tools.json","sha256":"53c823f07db512b82e01a4f132ff43be426b4b227c436e8853c5144ae0504e87"},{"path":"plugin/hermes/profiles/core.json","sha256":"49f33ba23cca5ab940f1929604f61491bc914d092f291cda4fe4f06b37d042d3"},{"path":"plugin/hermes/profiles/formal.json","sha256":"9be2b3144486311d9ba7f1d41c5033eb8e2553e9d12b71d46e512401f57a084b"},{"path":"plugin/hermes/profiles/full.json","sha256":"0db937da01737bbc0341a591ecd23e55008d8ffc02368517c7d1e7da8b309dec"},{"path":"plugin/hermes/server.py","sha256":"4c42725d797ac78ed20d3e843e602b1c60c88bd13f74e06c65a6b4016b3b7daf"},{"path":"plugins/jackel/.codex-plugin/plugin.json","sha256":"49bbd046759b045add1caf1f19300431fe7d697b59bfd93b57daf1d7edb709ff"},{"path":"plugins/jackel/mcp/server.py","sha256":"b5916270588db1fbb68b4d520c5f5e9d0fabb84e26602f18ad0a2927a38cece9"},{"path":"release/MANIFEST.sha256","sha256":"3886588b938986f4f6cfe0c7884d35b8140639408e8e9116d962fb46c3876c51"},{"path":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"path":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"path":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"}],"release":{"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"state":"v1.7.3","statement":"Published release identity; the annotated v1.7.3 tag and GitHub release must bind these exact bytes.","version":"v1.7.3"},"schema":"jackal-capability-inventory-v1","status_vocabulary":["bounded","checked","estimated","exact","formal-bounded","indeterminate","model-based","ok","refused","structural-exact","verified","verified-program-evidence","verified-program-receipt"],"tool_count":41,"tools":[{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_range_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"826bed7e2645735d5d333040eaa8c28425df90b6e87f8dd6aa94df1cc40ace45","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded receipt with the certificate embedded (or refuse). Inputs: expression: Anubis expression in the single variable x, restricted to the certified fragment.; input_lo: Interval lower bound as an integer or reduced ℚ (e.g. '1', '2/3').; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-gaussian","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_gaussian_integral","profiles":["formal","full"],"refusal_boundary":"Only the exact catalog-declared Gaussian form and canonical rational bounds/tolerance are admitted. Any other form, failed enclosure, checker rejection, or pin/identity mismatch refuses without downgrade.","release_state":"v1.7.3","schema_sha256":"4a43f67d68610c9e7b13f8bc8195c6c3e9ea24493494eb5aca8e768d707adb13","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a zero-libm formal-bounded Gaussian integral receipt, rerun the pinned checker, or refuse without downgrade. Inputs: expression: Exact canonical exp(-A*(x-mu)^2) expression; all other expressions refuse.; input_lo: Integration lower bound as a canonical rational.; input_hi: Integration upper bound as a canonical rational.; tolerance: Maximum enclosure width as a positive canonical rational."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-int-cert","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_bound_cert","profiles":["formal","full"],"refusal_boundary":"Only the request-bound v1.7.2 composed-integral fragment and canonical bounds/tolerance are admitted. Request-unbound v1.7.0 evidence, unsupported syntax, failed subdivision, checker rejection, or identity mismatch refuses without using the weaker float lane.","release_state":"v1.7.3","schema_sha256":"1229ede1ee518a9b19d3a201268e598fac6fd52fd2eef1bb379f920d6093b9cd","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a request-bound certified composed definite-integral formal receipt (v1.7.2): the untrusted exact-rational producer mirrors the engine's adaptive subdivision, the pinned Lean-proved jackal_int_cert_check binds the exact raw expression/bounds/tolerance and re-checks the whole subdivision-tree certificate (theorem int_cert_sound), and the receipt is independently re-verified before returning. Request-unbound v1.7.0 receipts are revoked. Certified fragment: num/var/neg/add/sub/mul/div/pow(0..4096)/sin/cos/abs in x. Everything else refuses. The weaker float lane jackal_integrate_bound stays status=bounded and is NOT this tool. Inputs: expression: Integrand in the single variable x, restricted to the certified fragment (num/var/neg/add/sub/mul/div/pow/sin/cos/abs).; input_lo: Integration lower bound as an integer or reduced canonical rational (e.g. '0', '2/3').; input_hi: Integration upper bound as a canonical rational, strictly above input_lo.; tolerance: Maximum enclosure width as a positive canonical rational (e.g. '1/100')."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-receipt-registry","identities":[{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_verify_receipt","profiles":["core","formal","full"],"refusal_boundary":"Only closed-registry range/rational, Gaussian, and current request-bound int-cert receipts matching independent caller expectations are replayed. Unknown epochs/variants, copied rather than caller-pinned expectations, revoked int-cert evidence, or checker/pin mismatch refuses.","release_state":"v1.7.3","schema_sha256":"988b83705212769a01eb2e5f5b44322b5728d5fd86eef4f64f7a4a37e378fc1f","status_classes":["verified","refused"],"supported_fragment":"Re-run the matching pinned Lean-proved checker over an embedded certificate using a closed epoch/variant registry: current v1.7.2 range/rational and request-bound int_cert, replay-only v1.5.0 range/rational, or Gaussian v1.5.0. Request-unbound v1.7.0 int_cert receipts refuse. Inputs: receipt: A jackal-formal-receipt-v1 JSON document.; expected_release_epoch: Caller-authorized release epoch, not copied from the receipt.; expected_command: Caller-authorized operation: range-bound-cert or integrate.; expected_expression: Exact raw expression supplied by the caller.; expected_input_lo: Exact raw lower-bound token supplied by the caller.; expected_input_hi: Exact raw upper-bound token supplied by the caller.; expected_tolerance: Exact raw tolerance token; required for Gaussian and int_cert receipts and forbidden for range receipts."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_sqrt_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"bc611de421d812aa6d6d8772fb986c17bcde74d7fe70ea31ff22433335d67c6d","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q sqrt(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'sqrt(x)' on a canonical rational interval; every other expression refuses without downgrade. v1.4.0 fragment extension. Inputs: expression: Must equal 'sqrt(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational (e.g. '2', '1/4'); must be >= 0.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_exp_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"9cc7bee07eebc566a9e267ad1b30c10a73cb25c18090ed2f9a3e9ec48550b928","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q exp(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'exp(x)' on a canonical rational interval [lo, hi] (general-sign since v1.5.0); every other expression refuses without downgrade. v1.4.1 fragment extension. Inputs: expression: Must equal 'exp(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational; any sign (general-sign since v1.5.0).; input_hi: Interval upper bound (canonical rational, hi >= lo); the producer picks a Taylor degree with 2*hi <= n+1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_ln_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"16dfb2b64dc9e290e1c062eba898233b04b187f1b244f6cc06433c48d1b7da45","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q ln(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'ln(x)' on a canonical rational interval with lo > 0; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'ln(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational; must be > 0.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_sin_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"d578799057048871ff13eca207bda2f9564261fce975801904d8cb34370cc7fe","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q sin(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'sin(x)' on a canonical rational interval whose midpoint m satisfies |m| <= 1; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'sin(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo); midpoint (lo+hi)/2 must satisfy |m| <= 1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_cos_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"d0f575ac0dbfe5e64aede075ae30bb1a625f05963e772febca6ac180b29f062b","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q cos(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'cos(x)' on a canonical rational interval whose midpoint m satisfies |m| <= 1; every other expression refuses without downgrade. Shares the sin_rat producer (--op cos). v1.5.0 fragment extension. Inputs: expression: Must equal 'cos(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo); midpoint (lo+hi)/2 must satisfy |m| <= 1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_atan_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"f16e48c7a37e284e124fe20766c7db2b90b4eed8fb748c2efebc9ee7c4b80767","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q atan(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'atan(x)' on a canonical rational interval; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'atan(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_tanh_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"6f9b24d732cc6fc2b0ad9ef7d51fa8cd88f2a344b3152c54f288f6a25a8fe05a","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q tanh enclosure via the untrusted composite producer + Lean-proved checker. NO libm on the proof-decision path. tanh is not an engine grammar token: admits ONLY the literal composite expression '1-2/(exp(2*x)+1)' (= tanh(x) mathematically) on a canonical rational interval with |lo|,|hi| <= 20; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal '1-2/(exp(2*x)+1)' after whitespace normalization (the frozen tanh-defining composite).; input_lo: Interval lower bound as an integer or reduced rational; |lo| <= 20.; input_hi: Interval upper bound (canonical rational, hi >= lo); |hi| <= 20."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_exact","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"42319cf6d3e3f7a8da025e880b8dfc02eb2c6e3128f8b93c11f41545d8bf1d8d","status_classes":["exact","refused"],"supported_fragment":"Exact big-rational arithmetic (status=exact). NOT formal: computationally exact, outside the Lean certificate chain. Inputs: expression: Integers, decimals, + - * / ^ (integer exponents), parentheses. Everything else refuses."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_evaluate","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"5baa3a344309d714a8b66c9fb4a14a97c8182b3cfe1326faa2e9967840eee17c","status_classes":["estimated","refused"],"supported_fragment":"IEEE f64 expression evaluation (status=estimated). A plain number, honestly labeled: no bound, no proof. Inputs: expression: Full expression grammar incl. transcendental functions and constants."},{"assurance_classes":["checked"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_diff","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"605972a25cde65779e921b8a27b7f1a0c19d540f5330791ec0fb571cccf858ad","status_classes":["checked","refused"],"supported_fragment":"Symbolic d/dx with numeric self-verification (status=checked). Sampled agreement is a check, not a proof of identity. Inputs: expression: Expression in x; non-differentiable functions fail closed."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"6d05a705ff580a831f75cbcd2079fe88c3b5d9c858bc6b0c3182ec55aa27cd27","status_classes":["estimated","refused"],"supported_fragment":"Fixed-grid Simpson + Richardson error estimate (status=estimated). Grid-limited: NOT a bound. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; panels: Panel count (e.g. '200')."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_adaptive","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"174132e83bff6d18972cf5d88b072b12d7102cad8fdf05197165c64bfac4fea1","status_classes":["estimated","refused"],"supported_fragment":"Adaptive Simpson with refusal semantics (status=estimated). Refuses when unconverged; agreement is still not a bound. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; tolerance: Local tolerance (e.g. '1e-9')."},{"assurance_classes":["bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_bound","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"9932617903499a2ed2baa4ac213f061f422bd8f2e60bca5bf05225a9f9f788a0","status_classes":["bounded","refused"],"supported_fragment":"Certified interval enclosure of an integral (status=bounded). CONDITIONAL on the stated f64/libm rounding model; implementation campaign-tested, NOT mechanized. Never labeled formal. For a Lean-checked formal-bounded composed enclosure over the certified fragment, use jackal_integrate_bound_cert instead. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; tolerance: Max enclosure width (e.g. '1e-6')."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_solve","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"caf1f55ca8ad1fef2e0fb4f5f5bb600edb147f257427de650335500979c13501","status_classes":["estimated","refused"],"supported_fragment":"Bisection root with residual + first-order conditioning diagnostics (status=estimated). Inputs: expression: f(x) whose root is sought.; input_lo: Bracket lower bound (sign change required).; input_hi: Bracket upper bound."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"ea4ca54f74334d678c3daf9c6686fca186041d27bb2f02dabca21a7747e7d416","status_classes":["exact","refused"],"supported_fragment":"Canonical s-expression + SHA-256 of any parsed expression (status=exact). NOT formal: exact computation outside the Lean certificate chain; no exact-cert emitted. Inputs: expression: Any expression the engine grammar parses."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"199fd63f51398c6e883a407d8e2435e42903e9c76f0227d815f3456b3568d9bc","status_classes":["exact","refused"],"supported_fragment":"Dense Q[x] canonical form, degree <= 64 (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Polynomial expression in x within the poly fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_eq","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"76d9390f705758c6ec2d5fe77cd6a1391908f93ef218ebfd5111c067dc32a819","status_classes":["exact","refused"],"supported_fragment":"Decidable polynomial identity over Q[x] (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: lhs: Left polynomial expression in x.; rhs: Right polynomial expression in x."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_gcd","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"dfff2a285e732d52520ea6fe5efabdab5bd6d956c224f30d163ccbbdbd406a5c","status_classes":["exact","refused"],"supported_fragment":"Monic polynomial gcd over Q[x] via Euclid (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: lhs: Left polynomial expression in x.; rhs: Right polynomial expression in x."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_ratfunc_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"3d4c7d73d13aa88606e9e005b7731c19ac63f9fe559b38e6ff777f979afd3b40","status_classes":["exact","refused"],"supported_fragment":"Rational-function canonical form P/Q, gcd-reduced, monic denominator, explicit denominator-nonzero side condition (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Rational-function expression in x within the ratfunc fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_roots_isolate","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"ea98289e6b6319b7c0b3e6e9832e07ff4a9dd06be1d7862956c50df6e1785978","status_classes":["exact","refused"],"supported_fragment":"Sturm-sequence isolation of all distinct real roots (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Polynomial expression in x within the poly fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_alg_sign","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"b4ad3c632887bc8875f8334dea3391017d73f30fa4895d988062882e89c2c1a5","status_classes":["exact","refused"],"supported_fragment":"Exact sign of a Q[x] polynomial at a rational point (status=exact). NOT formal; no exact-cert emitted. Inputs: expression: Polynomial expression in x within the poly fragment.; point: Rational evaluation point (e.g. '3/2')."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_alg_cmp","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"bfea42d3f97e6f0403d11155d667dfec7000719e2aa3af67c8897989a9e2eee4","status_classes":["exact","refused"],"supported_fragment":"Order decision between two isolated real algebraic numbers (status=exact). NOT formal; no exact-cert emitted. Inputs: p: First defining polynomial in x.; a1: First isolating interval lower bound (rational).; b1: First isolating interval upper bound (rational).; q: Second defining polynomial in x.; a2: Second isolating interval lower bound (rational).; b2: Second isolating interval upper bound (rational)."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_xgcd","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"1c7fb606e43e71eeb4ab288c08ea4a6c89efd95beb3f802e084d5d3c1a3beaf6","status_classes":["exact","refused"],"supported_fragment":"Extended gcd with Bezout certificate (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: a: First integer.; b: Second integer."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_mod_pow","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"b3edc74b3901989b9248f8b89feaed2cc396e218abf9ccfca7ab53a99a9c7bc1","status_classes":["exact","refused"],"supported_fragment":"Modular exponentiation via square-and-multiply (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: base: Base integer.; exp: Nonnegative exponent integer.; mod: Modulus integer >= 1."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_mod_inv","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"d0826f19759afacd20d4a5f0d6704a52bce158c6950bb852a5e0774886a4abd7","status_classes":["exact","refused"],"supported_fragment":"Modular inverse with product certificate (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: a: Integer to invert.; m: Modulus integer >= 2; gcd(a, m) must be 1."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_crt","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"d44aebbbcb3b00ad0d192581533c5cfdb164e26431f3ed850406c8ecfa5044b4","status_classes":["exact","refused"],"supported_fragment":"Chinese remainder reconstruction over pairwise-coprime moduli, up to 16 pairs (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: args: Space-separated residue/modulus pairs: 'r1 m1 r2 m2 [...]' (e.g. '2 3 3 5 2 7')."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_divides","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"1191b2b4ce3a9a5c3a1dafb0917fad46ca9c3375c73f4ae59ff7a389d513adb4","status_classes":["exact","refused"],"supported_fragment":"Exact divisibility decision (status=exact). NOT formal; no exact-cert emitted. Inputs: a: Candidate divisor integer.; b: Dividend integer."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_prime_cert","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"3ff03881b24f8fd94db68b210874010e66ce0e3d32666d98a21c1bc40ccc5646","status_classes":["exact","refused"],"supported_fragment":"Pratt primality certificate or composite divisor witness, budgeted and fail-closed (status=exact; n <= 10^60, Pratt tree depth <= 64, nodes <= 512). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: n: Integer >= 2, at most 61 digits."},{"assurance_classes":["estimated","model-based","checked","bounded","formal-bounded","exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"claim-router","identities":[{"label":"claim_kernel","locator":"tools/claim_kernel.py","sha256":"77b0f85ad5fb7214f88898b60ea29ea9fd7be740c38b655388444e6e5181f348"},{"label":"claim_router","locator":"tools/claim_router.py","sha256":"02328cf177a0423bdc5cbca6ec0ea946bb0679bbd3dc6c24140d32598e575afb"},{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"},{"label":"claim_inference_registry","locator":"release/claim/inference_registry_v1.json","sha256":"c70b33d5aee8071b5125e6a5f8ffe5226fc22a137d920c17d9b3463968be13f0"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_claim","profiles":["core","formal","full"],"refusal_boundary":"Only jackal-claim-request-v1 and its closed step vocabulary are compiled. Policy, identity, schema, route, or assurance failures refuse; fallback is off by default and any caller-enabled fallback remains explicit in the route trace rather than silently changing assurance.","release_state":"v1.7.3","schema_sha256":"4d2703ff772433f39ac8b6555727e856685b0e5042b9c2cc8fcaa4402d6b9153","status_classes":["ok","refused"],"supported_fragment":"Compile a structured jackal-claim-request-v1 into a canonical, content-addressed jackal-claim-bundle-v1 evidence graph through the deterministic policy router. Routes through exact, current/archival range-family, Gaussian, request-bound composed-integral, machine, and unit lanes; emits a route trace naming candidates and refusal reasons; and refuses rather than silently downgrading (allow_fallback defaults false). The bundle is independently replayable via jackal_verify_bundle. Inputs: request: jackal-claim-request-v1 object: {schema, steps:[{id, op, ...}], root, policy?, nonce?, emitted_at_unix?, max_age_seconds?, expires_at_unix?}. Step ops: input, exact, enclose, gaussian, integrate_cert, machine, interval_add/sub/mul/div, threshold, decision, convert, and, model, passthrough, attach."},{"assurance_classes":["estimated","model-based","checked","bounded","formal-bounded","exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"claim-verifier","identities":[{"label":"claim_verifier","locator":"tools/claim_bundle_verify.py","sha256":"e0fcb9540c730bd9bb492b528ed42d29d49fc775b3aa0f9b831b6264fd68fd22"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"},{"label":"claim_inference_registry","locator":"release/claim/inference_registry_v1.json","sha256":"c70b33d5aee8071b5125e6a5f8ffe5226fc22a137d920c17d9b3463968be13f0"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_verify_bundle","profiles":["core","formal","full"],"refusal_boundary":"Only canonical bundles matching separately caller-pinned epoch, policy, root proposition, time, and nonce are replayed. Semantic, graph, freshness, evidence, checker, or pin ambiguity returns refused or indeterminate exactly as declared; it is never converted to success.","release_state":"v1.7.3","schema_sha256":"9e3acec17637a352bc88e3b08e8679a34f1efae3539fe1cce05646212be4cb5f","status_classes":["verified","refused","indeterminate"],"supported_fragment":"Independently replay a jackal-claim-bundle-v1 against caller-pinned expectations. The standalone dependency-free verifier recomputes every canonical byte and hash, revalidates the DAG, selects only the closed current/archival range, Gaussian, or current request-bound int-cert checker/proof tuple, re-runs embedded evidence, recomputes machine/unit mathematics, re-evaluates every inference rule and assurance-axis propagation, enforces consequence-class floors and policy, and recomputes the deterministic rendering. Returns verified | refused | indeterminate with exact reasons — never a generic green badge. Inputs: bundle: The jackal-claim-bundle-v1 object to replay.; expected_release_epoch: Caller-pinned epoch (e.g. 'v1.6.0'); never copied from the bundle.; expected_policy_sha256: Caller-pinned SHA-256 of the canonical policy bytes.; expected_root_proposition: Caller-pinned canonical root proposition IR object.; verification_time_unix: Caller-supplied verification time (unix seconds) for freshness/expiry checks.; expected_nonce: Caller nonce; the bundle root must bind exactly this nonce."},{"assurance_classes":["structural-exact"],"consequence_ceiling":"informational","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"structural-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_test_exists_checker","locator":"tools/test_exists_verify.py","sha256":"598cb99e1eb70c9410ca87345efee346f73e43aaf3625427dca17ea04231caea"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_test_exists","profiles":["full"],"refusal_boundary":"Only byte-exact source/citation structure described by the schema is accepted after independent file-byte recomputation. Path traversal, malformed symbols/hashes, missing text/declarations, or checker mismatch refuses; the result never asserts test execution or correctness.","release_state":"v1.7.3","schema_sha256":"9685ecf3bcf78a3a26916455cc528cdeac137420e8694447e2865b33890f9d46","status_classes":["structural-exact","refused"],"supported_fragment":"Domain pack jackal.programming.source, operation programming.source.test_exists.v1, routed through pack-route. States one byte-exact STRUCTURAL fact: a declaration-shaped occurrence of `symbol` exists at `declaration_line` in a file whose content hash is exactly `file_sha256`, and the file contains exactly `declaration_count` such occurrences. The engine validates the canonical FORM; the manifest-pinned independent checker tools/test_exists_verify.py then recomputes every claimed field from the real bytes on disk and only an ACCEPT verdict returns success, so a misstated hash, line or count refuses instead of minting a certificate. ASSURANCE ceiling exact; CONSEQUENCE ceiling informational, and the second does not rise with the first: a test-exists-cert is NEVER evidence that the code under test is correct, that the test executes, that it is collected by any runner, or that it asserts anything at all. NOT formal: no Lean checker and no theorem are involved. Do not cite this certificate in support of a correctness claim. Inputs: file_path: Repository-relative path token; absolute paths and parent traversal refuse `prog-path`.; file_sha256: Exactly 64 lowercase hex characters; the checker recomputes it from the file bytes.; symbol: Identifier of the declaration; a non-identifier refuses `prog-symbol`.; declaration_line: 1-based line of the declaration as a canonical positive integer.; declaration_count: Total declaration-shaped occurrences of `symbol` in the file; `0` refuses `prog-absent`."},{"assurance_classes":["structural-exact"],"consequence_ceiling":"informational","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"structural-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_test_exists_checker","locator":"tools/test_exists_verify.py","sha256":"598cb99e1eb70c9410ca87345efee346f73e43aaf3625427dca17ea04231caea"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_claim_cites_test","profiles":["full"],"refusal_boundary":"Only byte-exact source/citation structure described by the schema is accepted after independent file-byte recomputation. Path traversal, malformed symbols/hashes, missing text/declarations, or checker mismatch refuses; the result never asserts test execution or correctness.","release_state":"v1.7.3","schema_sha256":"69a533155bde04bfd5dedd43e9d63acd02f3e2773757936e9e1714458e20abd4","status_classes":["structural-exact","refused"],"supported_fragment":"Domain pack jackal.programming.source, operation programming.source.claim_cites_test.v1, routed through pack-route. Resolves a citation: `claim_text` occurs verbatim in the document at `doc_path`/`doc_sha256`, and `symbol` has a declaration-shaped occurrence in the cited test file at `test_path`/`test_sha256`. Resolution is all this establishes. It does NOT establish that the cited test covers, exercises or supports the claim — the cited test may check something entirely different, which is the exact defect this operation exists to bound rather than hide. The manifest-pinned tools/test_exists_verify.py re-runs over the certificate and only ACCEPT returns success, so a claim text absent from the document or a dangling citation refuses. ASSURANCE ceiling exact; CONSEQUENCE ceiling informational, and the second does not rise with the first. NOT formal: no Lean checker and no theorem are involved. Inputs: doc_path: Repository-relative path of the document making the claim.; doc_sha256: Exactly 64 lowercase hex characters for the document bytes.; claim_text: The claim sentence, verbatim, 1..2048 bytes; it must occur in the document.; test_path: Repository-relative path of the cited test file.; test_sha256: Exactly 64 lowercase hex characters for the cited test file bytes.; symbol: Identifier the citation resolves to inside the cited test file."},{"assurance_classes":["exact"],"consequence_ceiling":"decision-boundary","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"decision-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_decision_checker","locator":"tools/decision_verify.py","sha256":"f1ad7c9fbd4c1d899dbb4bebabbbeb97e97a56bd4b279ad7d8ec3722bf12e0f6"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_decision_rank","profiles":["full"],"refusal_boundary":"Only 2..6 schema-valid options under a caller-declared admissible numeric criterion are ranked. Invalid shape/sense/unit, value-judgment criteria, zero top margin, or checker mismatch refuses; caller values are not treated as measurements or confidence intervals.","release_state":"v1.7.3","schema_sha256":"843fe08464d40d97094eeb6424c0c29a3e2617172ba56262ca4122468a8bb92f","status_classes":["exact","refused"],"supported_fragment":"Domain pack jackal.decision.matrix, operation decision.matrix.rank.v1, routed through pack-route. Orders 2..6 labelled options by a caller-declared numeric criterion and emits a jackal-decision-cert-v1 naming the selected option, the runner-up and the exact margin; the manifest-pinned tools/decision_verify.py recomputes the whole ordering from the certificate's own option values and only ACCEPT returns success. Criterion admissibility is decided by the engine against a fixed word list, so a bare value judgment refuses `decision-value-judgment`; a top-two tie refuses `decision-margin-zero`. ASSURANCE ceiling exact; CONSEQUENCE ceiling decision-boundary. The arithmetic is exact and the choice of criterion is not: the declared criterion and the declared option values remain the caller's, this result is not a claim that the criterion is the right one, the values are not measurements, and the margin is not a confidence interval. For the closed-unit lane that additionally requires a declared unit, use jackal_decision_rank_v2. NOT formal: no Lean checker and no theorem are involved. Inputs: decision_id: Caller's identifier for this decision, bound into the certificate. Bytes are restricted to [A-Za-z0-9_]; anything else refuses `prog-symbol`.; criterion: The declared numeric criterion (e.g. 'latency_ms'); a value judgment refuses `decision-value-judgment`.; sense: Exactly 'min' or 'max'; anything else refuses `decision-sense-unknown`.; options: 2..6 whitespace-separated `label value` pairs, e.g. 'a 10 b 20 c 30'. Values are canonical integers. A label containing whitespace shifts the pairing and refuses `pack-args-shape`; it is never silently re-paired."},{"assurance_classes":["exact"],"consequence_ceiling":"decision-boundary","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"decision-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_decision_checker","locator":"tools/decision_verify.py","sha256":"f1ad7c9fbd4c1d899dbb4bebabbbeb97e97a56bd4b279ad7d8ec3722bf12e0f6"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_decision_rank_v2","profiles":["full"],"refusal_boundary":"Only 2..6 schema-valid options under a caller-declared admissible numeric criterion are ranked. Invalid shape/sense/unit, value-judgment criteria, zero top margin, or checker mismatch refuses; caller values are not treated as measurements or confidence intervals.","release_state":"v1.7.3","schema_sha256":"cdc8abba09426977a5319b52410204f21e2e1eb7b38a9de31de751fcb862e78a","status_classes":["exact","refused"],"supported_fragment":"Domain pack jackal.decision.matrix, operation decision.matrix.rank.v2, routed through pack-route. Same deterministic ordering as jackal_decision_rank, plus a REQUIRED declared unit drawn from a closed vocabulary: the 65 canonical ids of release/claim/unit_registry_v1.json excluding the dimensionless identity `one` (66 ids in the registry, `one` is not admitted here). Matching is exact-token and case-sensitive; an alias, a spelled-out name such as 'millisecond', a different case, or the dimensionless identity all refuse `decision-unit-unknown`, and an empty unit refuses `decision-unit-missing`. Emits jackal-decision-cert-v2, re-checked by the manifest-pinned tools/decision_verify.py; only ACCEPT returns success. ASSURANCE ceiling exact; CONSEQUENCE ceiling decision-boundary. Honest residual: a declared unit is NOT a measurement. The closed vocabulary forces the caller to name a dimension, and nothing more — a value-judgment criterion that survives the engine's word list is still accepted when a real unit is declared (`most_elegant` in `ms` ranks), and the values themselves remain caller-declared. NOT formal: no Lean checker and no theorem are involved. Inputs: decision_id: Caller's identifier for this decision, bound into the certificate. Bytes are restricted to [A-Za-z0-9_]; anything else refuses `prog-symbol`.; criterion: The declared numeric criterion; a value judgment refuses `decision-value-judgment` even with an admissible unit.; unit: One canonical unit id from release/claim/unit_registry_v1.json, excluding `one`. Exact token, case-sensitive: 'ms' is admitted, 'millisecond' and 'MS' refuse `decision-unit-unknown`.; sense: Exactly 'min' or 'max'; anything else refuses `decision-sense-unknown`.; options: 2..6 whitespace-separated `label value` pairs, e.g. 'a 10 b 20 c 30'. Values are canonical integers. A label containing whitespace shifts the pairing and refuses `pack-args-shape`; it is never silently re-paired."},{"assurance_classes":["verified-program-evidence"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"cafbd25791225856c2914e9dc86b5dcd3e23d6cc0285b09800de34922f76d52e"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_check_program","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"177cfcf9dfcd6bbc6e657eb83b88f04bfedaa0f28f81307077a776e2052df1e2","status_classes":["verified-program-evidence","refused"],"supported_fragment":"Run a caller-pinned Anubis compiler only as `build --evidence` in Safe mode, never execute the compiled artifact, then independently close and replay the resulting strict anubis.program-evidence.v3 package under inventory-safe-v1. Emits only verified-program-evidence or a named refusal. This profile checks producer-attested function/policy inventories but explicitly does not establish policy-construct totality, source-to-VC proof, SMT-to-CNF proof, source-native refinement, runtime behavior, or universal soundness. Inputs: source_path: Local regular non-symlink Anubis source path.; anubis_bin: Local regular non-symlink Anubis executable; caller-pinned and hashed before/after build.; expected_source_sha256: Caller-pinned exact source SHA-256.; expected_compiler_sha256: Caller-pinned approved Anubis executable SHA-256.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1; contracted-safe-v1 refuses.; nonce: Caller nonce bound into the receipt.; out_root: New local output root; existing paths refuse."},{"assurance_classes":["verified-program-evidence"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"cafbd25791225856c2914e9dc86b5dcd3e23d6cc0285b09800de34922f76d52e"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_verify_program","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"45c7aae87c329925f6bd6b9100efc7d099d70fcaeaba915ee59937f019e1153d","status_classes":["verified-program-evidence","refused"],"supported_fragment":"Independently verify caller-selected Anubis Safe source and evidence bytes under inventory-safe-v1: strict v3 roster, exact manifest closure, source/compiler/artifact/policy pins, producer-summary reconciliation, one-to-one solver/proof paths and counters, approved Z3 UNSAT replay, and independent RUP replay. Never executes the artifact and never claims independent policy-construct totality or source-native refinement. Inputs: source_path: Caller-selected regular non-symlink Anubis source path.; evidence_dir: Caller-selected strict anubis.program-evidence.v3 directory.; expected_source_sha256: Caller-pinned exact source SHA-256.; expected_compiler_sha256: Caller-pinned producer executable SHA-256.; expected_artifact_sha256: Caller-pinned sealed artifact SHA-256; artifact bytes are read but never executed.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1.; nonce: Caller nonce bound into the receipt."},{"assurance_classes":["verified-program-receipt"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"cafbd25791225856c2914e9dc86b5dcd3e23d6cc0285b09800de34922f76d52e"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_verify_program_receipt","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"6bb75d81aebf6f2b3b20900357204e9ef0858cdac412ea016868028cdd2a67d3","status_classes":["verified-program-receipt","refused"],"supported_fragment":"Recompute a jackal-anubis-program-receipt-v1 from caller-selected source/evidence bytes and independent caller pins, rejecting outer-digest-consistent semantic laundering. Success is only verified-program-receipt; it does not raise the underlying inventory-safe-v1 assurance ceiling. Inputs: receipt: Program receipt object to replay; its own pins are never trusted.; source_path: Caller-selected regular source path.; evidence_dir: Caller-selected evidence directory.; expected_source_sha256: Caller-pinned source SHA-256.; expected_compiler_sha256: Caller-pinned compiler SHA-256.; expected_artifact_sha256: Caller-pinned artifact SHA-256.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1.; nonce: Caller nonce; never copied from the receipt."}],"unique_tool_count":41} diff --git a/release/evidence/approved_check_compiler.linux-aarch64 b/release/evidence/approved_check_compiler.linux-aarch64 new file mode 100644 index 0000000..eeb0bcf --- /dev/null +++ b/release/evidence/approved_check_compiler.linux-aarch64 @@ -0,0 +1 @@ +/home/sicarii/.local/share/JACKAL/anubis-check/linux-aarch64/jackal_anubis_check_v1 7cdafb305f3b8df53e66e037433803d5154b4f5872758d9b15f7eeedc9670398 diff --git a/release/tools/repin_linux.py b/release/tools/repin_linux.py index 01237d5..bd575c3 100755 --- a/release/tools/repin_linux.py +++ b/release/tools/repin_linux.py @@ -144,6 +144,12 @@ def host_evidence(base: str) -> Path | None: parts = z3marker.read_text().split() if len(parts) >= 2 and len(parts[1]) == 64: out.append(f"approved-z3-{tag} jackal_z3_v4154 {parts[1]}") + # Omarchy edition: append the architecture-qualified approved CHECK-compiler row + ccmarker = ROOT / EVIDENCE_DIR / f"approved_check_compiler.{tag}" + if ccmarker.is_file(): + parts = ccmarker.read_text().split() + if len(parts) >= 2 and len(parts[1]) == 64: + out.append(f"approved-check-compiler-{tag} jackal_anubis_check_v1 {parts[1]}") missing = set(BINARY_ROWS) - seen_binary if missing: sys.exit(f"REPIN_LINUX_REFUSED detail=manifest lacked binary rows: {sorted(missing)}") diff --git a/tools/anubis_program_verify.py b/tools/anubis_program_verify.py index 6a5dd90..e117b6e 100755 --- a/tools/anubis_program_verify.py +++ b/tools/anubis_program_verify.py @@ -127,6 +127,25 @@ APPROVED_CHECK_COMPILER_SHA256 = ( "0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6" ) +# Architecture-qualified CHECK-compiler anchor (architect sign-off 2026-08-24). +# A NEW clean-source Linux aarch64 anubis, independently double-built byte-identical +# from public anubis-lang (commit e34d0c8) -- NOT the historical macOS 0d6a8f89 and +# NOT the guest's ambient bytes. The Darwin declaration above stays exact in the +# FROZEN inventory-safe-v1 policy body; only the runtime selection below is host-aware. +APPROVED_CHECK_COMPILER_LINUX_AARCH64_SHA256 = ( + "7cdafb305f3b8df53e66e037433803d5154b4f5872758d9b15f7eeedc9670398" +) + + +def _approved_check_compiler_sha256_for_host() -> str: + """The approved check-compiler digest for THIS host, or refuse. Never a + PATH-only, version-only, or 'any anubis on this machine' rule.""" + system, machine = platform.system(), platform.machine() + if system == "Darwin": + return APPROVED_CHECK_COMPILER_SHA256 + if system == "Linux" and machine == "aarch64": + return APPROVED_CHECK_COMPILER_LINUX_AARCH64_SHA256 + raise Refusal("check-compiler-unsupported-host", f"{system}/{machine}") APPROVED_Z3_PATH = Path("/opt/homebrew/bin/z3") APPROVED_Z3_SHA256 = "ae6c8df33db9c9ae9a80b6044e77cd66529a141d8b25f0620f1e89b409594f48" @@ -1330,8 +1349,20 @@ def check_program(args: argparse.Namespace) -> dict[str, Any]: raise Refusal("verification-time-invalid") if sha_file(source) != expected_source: raise Refusal("source-pin-mismatch") - if expected_compiler != APPROVED_CHECK_COMPILER_SHA256: + if expected_compiler != _approved_check_compiler_sha256_for_host(): raise Refusal("compiler-not-approved", expected_compiler) + # no symlink at the compiler boundary; safe owner/mode. Exact bytes + TOCTOU + # are then enforced by pinned_executable_snapshot against expected_compiler. + if compiler.is_symlink(): + raise Refusal("compiler-symlink") + try: + _compiler_info = compiler.resolve(strict=True).stat() + except OSError: + raise Refusal("compiler-unavailable") from None + if _compiler_info.st_uid != os.getuid(): + raise Refusal("compiler-owner") + if _compiler_info.st_mode & (stat.S_IWGRP | stat.S_IWOTH): + raise Refusal("compiler-mode") out_root = Path(args.out_root) if out_root.exists() or out_root.is_symlink(): raise Refusal("output-exists", str(out_root)) From 1f1fd28c6cbd78fba49cf7b0210fb375548dad1b Mon Sep 17 00:00:00 2001 From: sicarii Date: Mon, 24 Aug 2026 07:56:56 -0400 Subject: [PATCH 08/22] omarchy: host-aware runtime tree pin so the MCP server starts on Linux/aarch64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The MCP server validated the installed runtime tree against the module-level SHA256SUMS_SHA256 constant, which is the macOS release value. On Linux/aarch64 the runtime's SHA256SUMS is the host tree, so both startup checks refused ("pinned runtime validation refused", then "private runtime snapshot creation refused") and the server never started. Resolve it the same way the metadata check already resolves the package sha: expose sha256sums_sha256 from effective_release_pins() (host-aware) and use it in both server startup calls (validate_runtime + create_runtime_snapshot) instead of the macOS module constant. macOS behaviour is unchanged — its host pin equals the module constant. Verified: `claude mcp list` -> jackal ✔ Connected; initialize + tools/list over a persistent pipe returns all 41 tools; tools/call round-trips. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01KBajXqAr1zojERZGTTxY2n --- plugins/jackel/PLUGIN_IDENTITY.sha256 | 4 ++-- plugins/jackel/mcp/server.py | 4 ++-- plugins/jackel/scripts/provision_runtime.py | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/plugins/jackel/PLUGIN_IDENTITY.sha256 b/plugins/jackel/PLUGIN_IDENTITY.sha256 index e2cf9cd..7f3bcbc 100644 --- a/plugins/jackel/PLUGIN_IDENTITY.sha256 +++ b/plugins/jackel/PLUGIN_IDENTITY.sha256 @@ -1,9 +1,9 @@ 49bbd046759b045add1caf1f19300431fe7d697b59bfd93b57daf1d7edb709ff .codex-plugin/plugin.json a165e6b00292a3768ad134562539dabf7874cf23bf9ac8f80e893f7970a63cdc .mcp.json 13da0c677be5eb6161c21415fc280cbc07af9263f0356ebab77e715f0ef600d7 README.md -b5916270588db1fbb68b4d520c5f5e9d0fabb84e26602f18ad0a2927a38cece9 mcp/server.py +5ae164132f21a8dfd19a5ab0c679ccd3ccfc6e2c35ce4a6a6d2968cd550bc07a mcp/server.py e4fb2996fc2a905a5101974ad6119e6c29fbc10cc8ca2f0223e18f89686dcdff scripts/launch_mcp.sh 878a9d94788a6c132fad151bbddebecb41c08615fe310278e586871fe8f9c44c scripts/launch_mcp.zsh -c0c7662a455e2c2a37a704326d7f52b2113ab834bc9f3b38769983fcac55daa5 scripts/provision_runtime.py +b1cbd346b7f2a8c7708e5459c413bfb06e12238597fe4c09315a6210adbdc322 scripts/provision_runtime.py 60f6a068c5f6bd81a2ab80e8d9d873864aefdf7f6ae7c2db37fe6572b41f898f scripts/verify_plugin.py 63f726fbde9e4484424388ef5af68dce92d7f55a4af9354e7d812833f090c972 skills/jackel/SKILL.md diff --git a/plugins/jackel/mcp/server.py b/plugins/jackel/mcp/server.py index 86b83dd..c53484c 100644 --- a/plugins/jackel/mcp/server.py +++ b/plugins/jackel/mcp/server.py @@ -1537,7 +1537,7 @@ def build_production_server( runtime, timeout=provisioner.SELFTEST_TIMEOUT, output_limit=provisioner.SELFTEST_OUTPUT_LIMIT, - expected_tree_sha256=provisioner.SHA256SUMS_SHA256, + expected_tree_sha256=provisioner.effective_release_pins()["sha256sums_sha256"], ) except Exception as error: raise StartupError("pinned runtime validation refused") from error @@ -1548,7 +1548,7 @@ def build_production_server( runtime, timeout=provisioner.SELFTEST_TIMEOUT, output_limit=provisioner.SELFTEST_OUTPUT_LIMIT, - expected_tree_sha256=provisioner.SHA256SUMS_SHA256, + expected_tree_sha256=provisioner.effective_release_pins()["sha256sums_sha256"], ) snapshot_value = getattr(snapshot_owner, "root", None) snapshot = _canonical_absolute_directory( diff --git a/plugins/jackel/scripts/provision_runtime.py b/plugins/jackel/scripts/provision_runtime.py index 212234f..f12fced 100644 --- a/plugins/jackel/scripts/provision_runtime.py +++ b/plugins/jackel/scripts/provision_runtime.py @@ -168,11 +168,13 @@ def effective_release_pins(system: str | None = None, machine: str | None = None "epoch": EPOCH, "asset": ASSET, "package_size": PACKAGE_SIZE, "package_sha256": PACKAGE_SHA256, "package_directory": PACKAGE_DIRECTORY, + "sha256sums_sha256": SHA256SUMS_SHA256, } return { "epoch": EPOCH, "asset": pin["asset"], "package_size": pin["package_size"], "package_sha256": pin["package_sha256"], "package_directory": pin["package_directory"], + "sha256sums_sha256": pin["sha256sums_sha256"], } From 9a8dfc68f3a3c8120f702a37cf3881d2c6384943 Mon Sep 17 00:00:00 2001 From: sicarii Date: Mon, 24 Aug 2026 08:28:44 -0400 Subject: [PATCH 09/22] =?UTF-8?q?omarchy:=20architect=20sign-off=20?= =?UTF-8?q?=E2=80=94=20designate=20the=20Linux/aarch64=20Anubis=20check=20?= =?UTF-8?q?compiler?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Record the architect's sign-off designating the clean-source Linux/aarch64 Anubis check compiler (7cdafb30...) as the approved check compiler for jackal_anubis_check_program on Linux/aarch64. Unlike the historical macOS candidate (0d6a8f89, "caller-pinned candidate; architect sign-off required", source irrecoverable), this is a committed clean-source, reproducibly double-built (byte-identical), architecture-qualified identity verified end-to-end through the unmodified frozen verifier and the real plugin. Scope is Linux/aarch64 only: the macOS candidate is not reused and the inventory-safe-v1 policy body stays byte-frozen (1b94350a). macOS and both Z3 anchors are untouched. Standalone authority evidence (mirrors the macOS dogfood record; not manifest-pinned). Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01KBajXqAr1zojERZGTTxY2n --- ...ubis_program_dogfood_linux_aarch64_v1.json | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 release/evidence/anubis_program_dogfood_linux_aarch64_v1.json diff --git a/release/evidence/anubis_program_dogfood_linux_aarch64_v1.json b/release/evidence/anubis_program_dogfood_linux_aarch64_v1.json new file mode 100644 index 0000000..9163139 --- /dev/null +++ b/release/evidence/anubis_program_dogfood_linux_aarch64_v1.json @@ -0,0 +1,87 @@ +{ + "schema": "anubis-program-dogfood-linux-aarch64-v1", + "application": "OMARCHY JACKAL native check-compiler designation", + "designation": "architect sign-off", + "signed_off": { + "authority": "architect", + "by": "khephri.labs@proton.me", + "date_utc": "2026-08-24", + "statement": "The clean-source Linux/aarch64 Anubis check compiler is designated the approved check compiler for jackal_anubis_check_program on Linux/aarch64.", + "scope": "Linux/aarch64 only. Does NOT reuse or supersede the historical macOS candidate 0d6a8f89 (whose exact source is irrecoverable); does NOT weaken the frozen inventory-safe-v1 policy body." + }, + "compiler": { + "authority": "architect signed-off; clean-source Linux/aarch64 designation (2026-08-24)", + "binary_sha256": "7cdafb305f3b8df53e66e037433803d5154b4f5872758d9b15f7eeedc9670398", + "supersedes_pre_emitter_candidate_sha256": "d8c7d38b6d376ee46ecf97817852b40c122df4711a561ec1c33ffa546816abff", + "clean_source": { + "repo": "github.com/AnubisQuantumCipher/anubis-lang", + "local_branch": "omarchy/program-evidence-v3-emitter", + "commit": "6aa6fd92d4fea1af5cd532767890e00cf918d4af", + "change": "Added emit_program_evidence_v3() + canonical_json() to compiler/src/evidence/mod.rs (sealed into MANIFEST.sha256); emits anubis.program-evidence.v3 assembled from the sealed bundle files; recomputes function/obligation digests with a canonical JSON byte-matching Python json.dumps(sort_keys,separators,ensure_ascii=False). Committed clean source, NOT an uncommitted worktree diff." + }, + "reproducible_double_build": { + "recipe": "SOURCE_DATE_EPOCH=1700000000 LC_ALL=C TZ=UTC CARGO_INCREMENTAL=0 remap-path-prefix -Cdebuginfo=0 ; cargo build --release -p anubis --no-default-features --locked", + "build1_sha256": "7cdafb305f3b8df53e66e037433803d5154b4f5872758d9b15f7eeedc9670398", + "build2_sha256": "7cdafb305f3b8df53e66e037433803d5154b4f5872758d9b15f7eeedc9670398", + "byte_identical": true + } + }, + "verifier": { + "authority": "unmodified frozen contract; architecture-qualified host-aware anchor only", + "tool": "tools/anubis_program_verify.py", + "sha256": "cafbd25791225856c2914e9dc86b5dcd3e23d6cc0285b09800de34922f76d52e", + "linux_aarch64_anchor_sha256": "7cdafb305f3b8df53e66e037433803d5154b4f5872758d9b15f7eeedc9670398", + "program_policy_sha256": "1b94350a6d23e9d76a917f05f0a53ae9e0ccf861bc6aee71342967ce1dccb090", + "program_policy_file_sha256": "361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb" + }, + "package": { + "alignment_state": "aligned-41-tool-linux-aarch64", + "basename": "jackal-v1.7.3-linux-aarch64.tar.gz", + "bytes": 204082823, + "sha256": "0b239bc7a96d75537706ab1aebbc271150c663048f49711107ffe1b93f7d743d", + "sha256sums_root": "bbbb7aa97368232580caa7914b00b577bc2601c41f38d4cd78b9a34178563671", + "file_count": 108, + "shipped_check_compiler_sha256": "7cdafb305f3b8df53e66e037433803d5154b4f5872758d9b15f7eeedc9670398", + "shipped_capability_inventory_sha256": "e7bbdce00d6a6de9d562ed39025855c00d0281e2f9a5fa148594bd04051a4678", + "double_build_cmp_exit": 0 + }, + "observed": { + "sample_source": "examples/showcase/verified_loop.anb", + "repo_cli": "verified-program-evidence", + "package_plugin": "verified-program-evidence", + "proofs_verified": 4, + "proof_steps": 4, + "policy_function_count": 2, + "policy_consumer_count": 6, + "independent_replay": "each obligation independently RUP-replayed by the verifier + replayed unsat by architecture-approved Z3 4.15.4 (b6fcd93b...)", + "negative_controls": { + "wrong_compiler": "refused:compiler-not-approved", + "source_tamper": "refused:source-pin-mismatch", + "policy_tamper": "refused:policy-pin-mismatch", + "compiler_sha_lie": "refused:compiler-not-approved" + } + }, + "compat_floor_rationale": { + "file": "release/compat/v173_floor.json", + "approved_check_compiler_sha256": "0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6", + "approved_z3_sha256": "ae6c8df33db9c9ae9a80b6044e77cd66529a141d8b25f0620f1e89b409594f48", + "note": "The compatibility floor is a FROZEN macOS baseline reference and is left unchanged by this designation. It names macOS values for BOTH the check compiler and Z3 by design; it is not a per-host live pin. Per-host approval is enforced by the host-aware anchors in tools/anubis_program_verify.py (Linux/aarch64 check compiler 7cdafb30..., Linux Z3 b6fcd93b...), which is what jackal_anubis_check_program actually gates on. The capability inventory's approved_program_compiler dependency points at this floor value as a baseline reference, not as a claim about the running host's compiler." + }, + "preserved_sentinels": { + "macos_check_anchor_sha256": "0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6", + "macos_z3_anchor_sha256": "ae6c8df33db9c9ae9a80b6044e77cd66529a141d8b25f0620f1e89b409594f48", + "linux_z3_anchor_sha256": "b6fcd93b2ccec9aa848ac148c4d9b4270577ad046601f211784586eb9f0135c4", + "host_aware_selection": "Darwin -> macOS anchor; Linux/aarch64 -> Linux anchor; other -> refuse", + "inventory_safe_v1_body_byte_frozen": true + }, + "non_claims": [ + "no-source-to-vc-proof", + "no-smt-to-cnf-proof", + "no-source-native-refinement", + "no-universal-language-soundness", + "policy-semantics-producer-attested", + "runtime-not-observed", + "derived-confinement-is-not-os-enforcement", + "policy-construct-totality-not-established" + ] +} From b072a4cc5633551a55da10f3490484376bab227f Mon Sep 17 00:00:00 2001 From: sicarii Date: Mon, 24 Aug 2026 09:01:58 -0400 Subject: [PATCH 10/22] omarchy: reconcile tool-41 check-compiler sign-off to RESOLVED The architect sign-off for jackal_anubis_check_program on Linux/aarch64 was granted+recorded 2026-08-24 (SIGNOFF_linux_aarch64.json, verifier anchor 7cdafb30, VERDICT.txt/STATUS.json=ARCHITECT_SIGNED_OFF) and independently re-verified today (verified-program-evidence, 4 proofs, receipt 81d6477e). The 'Pending trust-surface sign-offs' section was stale; mark it RESOLVED. Product verdict stays _V111_PENDING (gated on the future sealed 49-tool package, not this round). No verifier acceptance broadened; anchors untouched. Co-Authored-By: Claude Opus 5 (1M context) --- OMARCHY_BUILD.md | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/OMARCHY_BUILD.md b/OMARCHY_BUILD.md index f407271..deed61b 100644 --- a/OMARCHY_BUILD.md +++ b/OMARCHY_BUILD.md @@ -67,7 +67,19 @@ program-evidence anchor), `cargo`/`rustc` (stable), `elan` (Lean), `python3`. gaussian_check 1f21c6b2… int_cert_check f2e26f50… v170 archival d515cdc2… approved Z3 4.15.4 b6fcd93b… inventory-safe-v1 policy (frozen) 1b94350a… -## Pending trust-surface sign-offs (do NOT self-authorize) - - jackal_anubis_check_program: needs an architect-designated Linux aarch64 anubis - CHECK COMPILER (version+sha256), double-built. See ~/omarchy-jackal-completion/ - evidence/I_check_compiler_finding.json. +## Trust-surface sign-offs + - jackal_anubis_check_program: RESOLVED 2026-08-24 — architect (khephri.labs@proton.me) + designated the clean-source Linux/aarch64 anubis CHECK COMPILER sha256 + 7cdafb30… (double-built byte-identical, from anubis-lang commit 6aa6fd92, + recipe §1). Scope: Linux/aarch64 only; macOS 0d6a8f89 not reused; + inventory-safe-v1 policy body byte-frozen (1b94350a). Verifier anchor is + host-aware (Darwin=0d6a8f89 preserved). Independently re-verified 2026-08-24 + (verified-program-evidence, 4 proofs, receipt 81d6477e…). Records: + release/evidence/anubis_program_dogfood_linux_aarch64_v1.json and + ~/omarchy-jackal-completion/evidence/compiler/SIGNOFF_linux_aarch64.json; + finding ~/omarchy-jackal-completion/evidence/I_check_compiler_finding.json + = RESOLVED_ARCHITECT_SIGNED_OFF. + - Note: the overall product verdict stays _V111_PENDING — gated on the FUTURE + sealed 49-tool package (AWAITING_SEALED_V111_PACKAGE), NOT on this + check-compiler round, which is independently resolved. Linux x86_64 + execution remains gate-declared/unobserved (separate item). From 1025212483ea9c9549634d8f6bd60d3ec4a9b291 Mon Sep 17 00:00:00 2001 From: sicarii Date: Mon, 24 Aug 2026 09:19:15 -0400 Subject: [PATCH 11/22] =?UTF-8?q?omarchy:=20pre-push=20hardening=20?= =?UTF-8?q?=E2=80=94=20align=20tests=20+=20inventory=20with=20host-aware?= =?UTF-8?q?=20changes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adversarial pre-push review (multi-agent) + emitter stress-test across the real program space surfaced test/inventory drift from this cycle's host-aware and re-pin changes. No production behaviour changes here; the signed-off check compiler (7cdafb30) is untouched. - release/capability_inventory_v1.json: regenerate to pick up the host-aware mcp/server.py sha (the drift gate + `capability_inventory --check` now pass). - tests/codex_plugin/test_mcp_adapter.py: the two fake provisioners now expose sha256sums_sha256 from effective_release_pins(), matching the real host-aware contract the server startup path now uses (validate_runtime + create_runtime_snapshot). Fixes 4 errors + 1 failure. - tests/codex_plugin/test_runtime_provisioner.py: update the host-guard tests to the actually-supported set (Darwin/arm64, Linux/aarch64, and the Linux/x86_64 declared gate with a None pin), still refusing genuinely foreign hosts. The old "darwin-only" assertions predated the Linux host support already on this branch. - tests/anubis_program_verifier_test.py: the dangling-out_root check test now patches the host-aware anchor helper (_approved_check_compiler_sha256_for_host) so it passes on Linux/aarch64, where the macOS constant is not consulted. Verified: full tests/codex_plugin suite (235) green on Linux; capability inventory --check + drift gate green; emitter stress-tested across 10 real programs (0 canonical-id mismatches at up to 46 functions; every refusal a legitimate fail-safe contract/budget boundary); emitter analysis output is byte-deterministic (only the native artifact sha varies, a pre-existing codegen property, faithfully recorded). Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01KBajXqAr1zojERZGTTxY2n --- release/capability_inventory_v1.json | 2 +- tests/anubis_program_verifier_test.py | 4 ++++ tests/codex_plugin/test_mcp_adapter.py | 3 +++ .../codex_plugin/test_runtime_provisioner.py | 19 +++++++++++++------ 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/release/capability_inventory_v1.json b/release/capability_inventory_v1.json index bb85cbf..1f89f20 100644 --- a/release/capability_inventory_v1.json +++ b/release/capability_inventory_v1.json @@ -1 +1 @@ -{"catalog":{"path":"plugin/hermes/tools.json","sha256":"53c823f07db512b82e01a4f132ff43be426b4b227c436e8853c5144ae0504e87","version":"v1.7.3"},"inputs":[{"path":"tools/capability_inventory.py","sha256":"a966660ef94d7b788be9f92451a78e43b41e12ae2c4e942834c1703994c2ccc0"},{"path":"plugin/hermes/tools.json","sha256":"53c823f07db512b82e01a4f132ff43be426b4b227c436e8853c5144ae0504e87"},{"path":"plugin/hermes/profiles/core.json","sha256":"49f33ba23cca5ab940f1929604f61491bc914d092f291cda4fe4f06b37d042d3"},{"path":"plugin/hermes/profiles/formal.json","sha256":"9be2b3144486311d9ba7f1d41c5033eb8e2553e9d12b71d46e512401f57a084b"},{"path":"plugin/hermes/profiles/full.json","sha256":"0db937da01737bbc0341a591ecd23e55008d8ffc02368517c7d1e7da8b309dec"},{"path":"plugin/hermes/server.py","sha256":"4c42725d797ac78ed20d3e843e602b1c60c88bd13f74e06c65a6b4016b3b7daf"},{"path":"plugins/jackel/.codex-plugin/plugin.json","sha256":"49bbd046759b045add1caf1f19300431fe7d697b59bfd93b57daf1d7edb709ff"},{"path":"plugins/jackel/mcp/server.py","sha256":"b5916270588db1fbb68b4d520c5f5e9d0fabb84e26602f18ad0a2927a38cece9"},{"path":"release/MANIFEST.sha256","sha256":"3886588b938986f4f6cfe0c7884d35b8140639408e8e9116d962fb46c3876c51"},{"path":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"path":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"path":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"}],"release":{"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"state":"v1.7.3","statement":"Published release identity; the annotated v1.7.3 tag and GitHub release must bind these exact bytes.","version":"v1.7.3"},"schema":"jackal-capability-inventory-v1","status_vocabulary":["bounded","checked","estimated","exact","formal-bounded","indeterminate","model-based","ok","refused","structural-exact","verified","verified-program-evidence","verified-program-receipt"],"tool_count":41,"tools":[{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_range_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"826bed7e2645735d5d333040eaa8c28425df90b6e87f8dd6aa94df1cc40ace45","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded receipt with the certificate embedded (or refuse). Inputs: expression: Anubis expression in the single variable x, restricted to the certified fragment.; input_lo: Interval lower bound as an integer or reduced ℚ (e.g. '1', '2/3').; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-gaussian","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_gaussian_integral","profiles":["formal","full"],"refusal_boundary":"Only the exact catalog-declared Gaussian form and canonical rational bounds/tolerance are admitted. Any other form, failed enclosure, checker rejection, or pin/identity mismatch refuses without downgrade.","release_state":"v1.7.3","schema_sha256":"4a43f67d68610c9e7b13f8bc8195c6c3e9ea24493494eb5aca8e768d707adb13","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a zero-libm formal-bounded Gaussian integral receipt, rerun the pinned checker, or refuse without downgrade. Inputs: expression: Exact canonical exp(-A*(x-mu)^2) expression; all other expressions refuse.; input_lo: Integration lower bound as a canonical rational.; input_hi: Integration upper bound as a canonical rational.; tolerance: Maximum enclosure width as a positive canonical rational."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-int-cert","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_bound_cert","profiles":["formal","full"],"refusal_boundary":"Only the request-bound v1.7.2 composed-integral fragment and canonical bounds/tolerance are admitted. Request-unbound v1.7.0 evidence, unsupported syntax, failed subdivision, checker rejection, or identity mismatch refuses without using the weaker float lane.","release_state":"v1.7.3","schema_sha256":"1229ede1ee518a9b19d3a201268e598fac6fd52fd2eef1bb379f920d6093b9cd","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a request-bound certified composed definite-integral formal receipt (v1.7.2): the untrusted exact-rational producer mirrors the engine's adaptive subdivision, the pinned Lean-proved jackal_int_cert_check binds the exact raw expression/bounds/tolerance and re-checks the whole subdivision-tree certificate (theorem int_cert_sound), and the receipt is independently re-verified before returning. Request-unbound v1.7.0 receipts are revoked. Certified fragment: num/var/neg/add/sub/mul/div/pow(0..4096)/sin/cos/abs in x. Everything else refuses. The weaker float lane jackal_integrate_bound stays status=bounded and is NOT this tool. Inputs: expression: Integrand in the single variable x, restricted to the certified fragment (num/var/neg/add/sub/mul/div/pow/sin/cos/abs).; input_lo: Integration lower bound as an integer or reduced canonical rational (e.g. '0', '2/3').; input_hi: Integration upper bound as a canonical rational, strictly above input_lo.; tolerance: Maximum enclosure width as a positive canonical rational (e.g. '1/100')."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-receipt-registry","identities":[{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_verify_receipt","profiles":["core","formal","full"],"refusal_boundary":"Only closed-registry range/rational, Gaussian, and current request-bound int-cert receipts matching independent caller expectations are replayed. Unknown epochs/variants, copied rather than caller-pinned expectations, revoked int-cert evidence, or checker/pin mismatch refuses.","release_state":"v1.7.3","schema_sha256":"988b83705212769a01eb2e5f5b44322b5728d5fd86eef4f64f7a4a37e378fc1f","status_classes":["verified","refused"],"supported_fragment":"Re-run the matching pinned Lean-proved checker over an embedded certificate using a closed epoch/variant registry: current v1.7.2 range/rational and request-bound int_cert, replay-only v1.5.0 range/rational, or Gaussian v1.5.0. Request-unbound v1.7.0 int_cert receipts refuse. Inputs: receipt: A jackal-formal-receipt-v1 JSON document.; expected_release_epoch: Caller-authorized release epoch, not copied from the receipt.; expected_command: Caller-authorized operation: range-bound-cert or integrate.; expected_expression: Exact raw expression supplied by the caller.; expected_input_lo: Exact raw lower-bound token supplied by the caller.; expected_input_hi: Exact raw upper-bound token supplied by the caller.; expected_tolerance: Exact raw tolerance token; required for Gaussian and int_cert receipts and forbidden for range receipts."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_sqrt_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"bc611de421d812aa6d6d8772fb986c17bcde74d7fe70ea31ff22433335d67c6d","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q sqrt(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'sqrt(x)' on a canonical rational interval; every other expression refuses without downgrade. v1.4.0 fragment extension. Inputs: expression: Must equal 'sqrt(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational (e.g. '2', '1/4'); must be >= 0.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_exp_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"9cc7bee07eebc566a9e267ad1b30c10a73cb25c18090ed2f9a3e9ec48550b928","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q exp(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'exp(x)' on a canonical rational interval [lo, hi] (general-sign since v1.5.0); every other expression refuses without downgrade. v1.4.1 fragment extension. Inputs: expression: Must equal 'exp(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational; any sign (general-sign since v1.5.0).; input_hi: Interval upper bound (canonical rational, hi >= lo); the producer picks a Taylor degree with 2*hi <= n+1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_ln_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"16dfb2b64dc9e290e1c062eba898233b04b187f1b244f6cc06433c48d1b7da45","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q ln(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'ln(x)' on a canonical rational interval with lo > 0; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'ln(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational; must be > 0.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_sin_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"d578799057048871ff13eca207bda2f9564261fce975801904d8cb34370cc7fe","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q sin(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'sin(x)' on a canonical rational interval whose midpoint m satisfies |m| <= 1; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'sin(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo); midpoint (lo+hi)/2 must satisfy |m| <= 1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_cos_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"d0f575ac0dbfe5e64aede075ae30bb1a625f05963e772febca6ac180b29f062b","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q cos(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'cos(x)' on a canonical rational interval whose midpoint m satisfies |m| <= 1; every other expression refuses without downgrade. Shares the sin_rat producer (--op cos). v1.5.0 fragment extension. Inputs: expression: Must equal 'cos(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo); midpoint (lo+hi)/2 must satisfy |m| <= 1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_atan_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"f16e48c7a37e284e124fe20766c7db2b90b4eed8fb748c2efebc9ee7c4b80767","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q atan(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'atan(x)' on a canonical rational interval; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'atan(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_tanh_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"6f9b24d732cc6fc2b0ad9ef7d51fa8cd88f2a344b3152c54f288f6a25a8fe05a","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q tanh enclosure via the untrusted composite producer + Lean-proved checker. NO libm on the proof-decision path. tanh is not an engine grammar token: admits ONLY the literal composite expression '1-2/(exp(2*x)+1)' (= tanh(x) mathematically) on a canonical rational interval with |lo|,|hi| <= 20; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal '1-2/(exp(2*x)+1)' after whitespace normalization (the frozen tanh-defining composite).; input_lo: Interval lower bound as an integer or reduced rational; |lo| <= 20.; input_hi: Interval upper bound (canonical rational, hi >= lo); |hi| <= 20."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_exact","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"42319cf6d3e3f7a8da025e880b8dfc02eb2c6e3128f8b93c11f41545d8bf1d8d","status_classes":["exact","refused"],"supported_fragment":"Exact big-rational arithmetic (status=exact). NOT formal: computationally exact, outside the Lean certificate chain. Inputs: expression: Integers, decimals, + - * / ^ (integer exponents), parentheses. Everything else refuses."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_evaluate","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"5baa3a344309d714a8b66c9fb4a14a97c8182b3cfe1326faa2e9967840eee17c","status_classes":["estimated","refused"],"supported_fragment":"IEEE f64 expression evaluation (status=estimated). A plain number, honestly labeled: no bound, no proof. Inputs: expression: Full expression grammar incl. transcendental functions and constants."},{"assurance_classes":["checked"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_diff","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"605972a25cde65779e921b8a27b7f1a0c19d540f5330791ec0fb571cccf858ad","status_classes":["checked","refused"],"supported_fragment":"Symbolic d/dx with numeric self-verification (status=checked). Sampled agreement is a check, not a proof of identity. Inputs: expression: Expression in x; non-differentiable functions fail closed."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"6d05a705ff580a831f75cbcd2079fe88c3b5d9c858bc6b0c3182ec55aa27cd27","status_classes":["estimated","refused"],"supported_fragment":"Fixed-grid Simpson + Richardson error estimate (status=estimated). Grid-limited: NOT a bound. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; panels: Panel count (e.g. '200')."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_adaptive","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"174132e83bff6d18972cf5d88b072b12d7102cad8fdf05197165c64bfac4fea1","status_classes":["estimated","refused"],"supported_fragment":"Adaptive Simpson with refusal semantics (status=estimated). Refuses when unconverged; agreement is still not a bound. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; tolerance: Local tolerance (e.g. '1e-9')."},{"assurance_classes":["bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_bound","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"9932617903499a2ed2baa4ac213f061f422bd8f2e60bca5bf05225a9f9f788a0","status_classes":["bounded","refused"],"supported_fragment":"Certified interval enclosure of an integral (status=bounded). CONDITIONAL on the stated f64/libm rounding model; implementation campaign-tested, NOT mechanized. Never labeled formal. For a Lean-checked formal-bounded composed enclosure over the certified fragment, use jackal_integrate_bound_cert instead. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; tolerance: Max enclosure width (e.g. '1e-6')."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_solve","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"caf1f55ca8ad1fef2e0fb4f5f5bb600edb147f257427de650335500979c13501","status_classes":["estimated","refused"],"supported_fragment":"Bisection root with residual + first-order conditioning diagnostics (status=estimated). Inputs: expression: f(x) whose root is sought.; input_lo: Bracket lower bound (sign change required).; input_hi: Bracket upper bound."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"ea4ca54f74334d678c3daf9c6686fca186041d27bb2f02dabca21a7747e7d416","status_classes":["exact","refused"],"supported_fragment":"Canonical s-expression + SHA-256 of any parsed expression (status=exact). NOT formal: exact computation outside the Lean certificate chain; no exact-cert emitted. Inputs: expression: Any expression the engine grammar parses."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"199fd63f51398c6e883a407d8e2435e42903e9c76f0227d815f3456b3568d9bc","status_classes":["exact","refused"],"supported_fragment":"Dense Q[x] canonical form, degree <= 64 (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Polynomial expression in x within the poly fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_eq","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"76d9390f705758c6ec2d5fe77cd6a1391908f93ef218ebfd5111c067dc32a819","status_classes":["exact","refused"],"supported_fragment":"Decidable polynomial identity over Q[x] (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: lhs: Left polynomial expression in x.; rhs: Right polynomial expression in x."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_gcd","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"dfff2a285e732d52520ea6fe5efabdab5bd6d956c224f30d163ccbbdbd406a5c","status_classes":["exact","refused"],"supported_fragment":"Monic polynomial gcd over Q[x] via Euclid (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: lhs: Left polynomial expression in x.; rhs: Right polynomial expression in x."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_ratfunc_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"3d4c7d73d13aa88606e9e005b7731c19ac63f9fe559b38e6ff777f979afd3b40","status_classes":["exact","refused"],"supported_fragment":"Rational-function canonical form P/Q, gcd-reduced, monic denominator, explicit denominator-nonzero side condition (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Rational-function expression in x within the ratfunc fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_roots_isolate","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"ea98289e6b6319b7c0b3e6e9832e07ff4a9dd06be1d7862956c50df6e1785978","status_classes":["exact","refused"],"supported_fragment":"Sturm-sequence isolation of all distinct real roots (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Polynomial expression in x within the poly fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_alg_sign","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"b4ad3c632887bc8875f8334dea3391017d73f30fa4895d988062882e89c2c1a5","status_classes":["exact","refused"],"supported_fragment":"Exact sign of a Q[x] polynomial at a rational point (status=exact). NOT formal; no exact-cert emitted. Inputs: expression: Polynomial expression in x within the poly fragment.; point: Rational evaluation point (e.g. '3/2')."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_alg_cmp","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"bfea42d3f97e6f0403d11155d667dfec7000719e2aa3af67c8897989a9e2eee4","status_classes":["exact","refused"],"supported_fragment":"Order decision between two isolated real algebraic numbers (status=exact). NOT formal; no exact-cert emitted. Inputs: p: First defining polynomial in x.; a1: First isolating interval lower bound (rational).; b1: First isolating interval upper bound (rational).; q: Second defining polynomial in x.; a2: Second isolating interval lower bound (rational).; b2: Second isolating interval upper bound (rational)."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_xgcd","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"1c7fb606e43e71eeb4ab288c08ea4a6c89efd95beb3f802e084d5d3c1a3beaf6","status_classes":["exact","refused"],"supported_fragment":"Extended gcd with Bezout certificate (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: a: First integer.; b: Second integer."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_mod_pow","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"b3edc74b3901989b9248f8b89feaed2cc396e218abf9ccfca7ab53a99a9c7bc1","status_classes":["exact","refused"],"supported_fragment":"Modular exponentiation via square-and-multiply (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: base: Base integer.; exp: Nonnegative exponent integer.; mod: Modulus integer >= 1."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_mod_inv","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"d0826f19759afacd20d4a5f0d6704a52bce158c6950bb852a5e0774886a4abd7","status_classes":["exact","refused"],"supported_fragment":"Modular inverse with product certificate (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: a: Integer to invert.; m: Modulus integer >= 2; gcd(a, m) must be 1."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_crt","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"d44aebbbcb3b00ad0d192581533c5cfdb164e26431f3ed850406c8ecfa5044b4","status_classes":["exact","refused"],"supported_fragment":"Chinese remainder reconstruction over pairwise-coprime moduli, up to 16 pairs (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: args: Space-separated residue/modulus pairs: 'r1 m1 r2 m2 [...]' (e.g. '2 3 3 5 2 7')."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_divides","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"1191b2b4ce3a9a5c3a1dafb0917fad46ca9c3375c73f4ae59ff7a389d513adb4","status_classes":["exact","refused"],"supported_fragment":"Exact divisibility decision (status=exact). NOT formal; no exact-cert emitted. Inputs: a: Candidate divisor integer.; b: Dividend integer."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_prime_cert","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"3ff03881b24f8fd94db68b210874010e66ce0e3d32666d98a21c1bc40ccc5646","status_classes":["exact","refused"],"supported_fragment":"Pratt primality certificate or composite divisor witness, budgeted and fail-closed (status=exact; n <= 10^60, Pratt tree depth <= 64, nodes <= 512). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: n: Integer >= 2, at most 61 digits."},{"assurance_classes":["estimated","model-based","checked","bounded","formal-bounded","exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"claim-router","identities":[{"label":"claim_kernel","locator":"tools/claim_kernel.py","sha256":"77b0f85ad5fb7214f88898b60ea29ea9fd7be740c38b655388444e6e5181f348"},{"label":"claim_router","locator":"tools/claim_router.py","sha256":"02328cf177a0423bdc5cbca6ec0ea946bb0679bbd3dc6c24140d32598e575afb"},{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"},{"label":"claim_inference_registry","locator":"release/claim/inference_registry_v1.json","sha256":"c70b33d5aee8071b5125e6a5f8ffe5226fc22a137d920c17d9b3463968be13f0"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_claim","profiles":["core","formal","full"],"refusal_boundary":"Only jackal-claim-request-v1 and its closed step vocabulary are compiled. Policy, identity, schema, route, or assurance failures refuse; fallback is off by default and any caller-enabled fallback remains explicit in the route trace rather than silently changing assurance.","release_state":"v1.7.3","schema_sha256":"4d2703ff772433f39ac8b6555727e856685b0e5042b9c2cc8fcaa4402d6b9153","status_classes":["ok","refused"],"supported_fragment":"Compile a structured jackal-claim-request-v1 into a canonical, content-addressed jackal-claim-bundle-v1 evidence graph through the deterministic policy router. Routes through exact, current/archival range-family, Gaussian, request-bound composed-integral, machine, and unit lanes; emits a route trace naming candidates and refusal reasons; and refuses rather than silently downgrading (allow_fallback defaults false). The bundle is independently replayable via jackal_verify_bundle. Inputs: request: jackal-claim-request-v1 object: {schema, steps:[{id, op, ...}], root, policy?, nonce?, emitted_at_unix?, max_age_seconds?, expires_at_unix?}. Step ops: input, exact, enclose, gaussian, integrate_cert, machine, interval_add/sub/mul/div, threshold, decision, convert, and, model, passthrough, attach."},{"assurance_classes":["estimated","model-based","checked","bounded","formal-bounded","exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"claim-verifier","identities":[{"label":"claim_verifier","locator":"tools/claim_bundle_verify.py","sha256":"e0fcb9540c730bd9bb492b528ed42d29d49fc775b3aa0f9b831b6264fd68fd22"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"},{"label":"claim_inference_registry","locator":"release/claim/inference_registry_v1.json","sha256":"c70b33d5aee8071b5125e6a5f8ffe5226fc22a137d920c17d9b3463968be13f0"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_verify_bundle","profiles":["core","formal","full"],"refusal_boundary":"Only canonical bundles matching separately caller-pinned epoch, policy, root proposition, time, and nonce are replayed. Semantic, graph, freshness, evidence, checker, or pin ambiguity returns refused or indeterminate exactly as declared; it is never converted to success.","release_state":"v1.7.3","schema_sha256":"9e3acec17637a352bc88e3b08e8679a34f1efae3539fe1cce05646212be4cb5f","status_classes":["verified","refused","indeterminate"],"supported_fragment":"Independently replay a jackal-claim-bundle-v1 against caller-pinned expectations. The standalone dependency-free verifier recomputes every canonical byte and hash, revalidates the DAG, selects only the closed current/archival range, Gaussian, or current request-bound int-cert checker/proof tuple, re-runs embedded evidence, recomputes machine/unit mathematics, re-evaluates every inference rule and assurance-axis propagation, enforces consequence-class floors and policy, and recomputes the deterministic rendering. Returns verified | refused | indeterminate with exact reasons — never a generic green badge. Inputs: bundle: The jackal-claim-bundle-v1 object to replay.; expected_release_epoch: Caller-pinned epoch (e.g. 'v1.6.0'); never copied from the bundle.; expected_policy_sha256: Caller-pinned SHA-256 of the canonical policy bytes.; expected_root_proposition: Caller-pinned canonical root proposition IR object.; verification_time_unix: Caller-supplied verification time (unix seconds) for freshness/expiry checks.; expected_nonce: Caller nonce; the bundle root must bind exactly this nonce."},{"assurance_classes":["structural-exact"],"consequence_ceiling":"informational","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"structural-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_test_exists_checker","locator":"tools/test_exists_verify.py","sha256":"598cb99e1eb70c9410ca87345efee346f73e43aaf3625427dca17ea04231caea"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_test_exists","profiles":["full"],"refusal_boundary":"Only byte-exact source/citation structure described by the schema is accepted after independent file-byte recomputation. Path traversal, malformed symbols/hashes, missing text/declarations, or checker mismatch refuses; the result never asserts test execution or correctness.","release_state":"v1.7.3","schema_sha256":"9685ecf3bcf78a3a26916455cc528cdeac137420e8694447e2865b33890f9d46","status_classes":["structural-exact","refused"],"supported_fragment":"Domain pack jackal.programming.source, operation programming.source.test_exists.v1, routed through pack-route. States one byte-exact STRUCTURAL fact: a declaration-shaped occurrence of `symbol` exists at `declaration_line` in a file whose content hash is exactly `file_sha256`, and the file contains exactly `declaration_count` such occurrences. The engine validates the canonical FORM; the manifest-pinned independent checker tools/test_exists_verify.py then recomputes every claimed field from the real bytes on disk and only an ACCEPT verdict returns success, so a misstated hash, line or count refuses instead of minting a certificate. ASSURANCE ceiling exact; CONSEQUENCE ceiling informational, and the second does not rise with the first: a test-exists-cert is NEVER evidence that the code under test is correct, that the test executes, that it is collected by any runner, or that it asserts anything at all. NOT formal: no Lean checker and no theorem are involved. Do not cite this certificate in support of a correctness claim. Inputs: file_path: Repository-relative path token; absolute paths and parent traversal refuse `prog-path`.; file_sha256: Exactly 64 lowercase hex characters; the checker recomputes it from the file bytes.; symbol: Identifier of the declaration; a non-identifier refuses `prog-symbol`.; declaration_line: 1-based line of the declaration as a canonical positive integer.; declaration_count: Total declaration-shaped occurrences of `symbol` in the file; `0` refuses `prog-absent`."},{"assurance_classes":["structural-exact"],"consequence_ceiling":"informational","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"structural-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_test_exists_checker","locator":"tools/test_exists_verify.py","sha256":"598cb99e1eb70c9410ca87345efee346f73e43aaf3625427dca17ea04231caea"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_claim_cites_test","profiles":["full"],"refusal_boundary":"Only byte-exact source/citation structure described by the schema is accepted after independent file-byte recomputation. Path traversal, malformed symbols/hashes, missing text/declarations, or checker mismatch refuses; the result never asserts test execution or correctness.","release_state":"v1.7.3","schema_sha256":"69a533155bde04bfd5dedd43e9d63acd02f3e2773757936e9e1714458e20abd4","status_classes":["structural-exact","refused"],"supported_fragment":"Domain pack jackal.programming.source, operation programming.source.claim_cites_test.v1, routed through pack-route. Resolves a citation: `claim_text` occurs verbatim in the document at `doc_path`/`doc_sha256`, and `symbol` has a declaration-shaped occurrence in the cited test file at `test_path`/`test_sha256`. Resolution is all this establishes. It does NOT establish that the cited test covers, exercises or supports the claim — the cited test may check something entirely different, which is the exact defect this operation exists to bound rather than hide. The manifest-pinned tools/test_exists_verify.py re-runs over the certificate and only ACCEPT returns success, so a claim text absent from the document or a dangling citation refuses. ASSURANCE ceiling exact; CONSEQUENCE ceiling informational, and the second does not rise with the first. NOT formal: no Lean checker and no theorem are involved. Inputs: doc_path: Repository-relative path of the document making the claim.; doc_sha256: Exactly 64 lowercase hex characters for the document bytes.; claim_text: The claim sentence, verbatim, 1..2048 bytes; it must occur in the document.; test_path: Repository-relative path of the cited test file.; test_sha256: Exactly 64 lowercase hex characters for the cited test file bytes.; symbol: Identifier the citation resolves to inside the cited test file."},{"assurance_classes":["exact"],"consequence_ceiling":"decision-boundary","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"decision-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_decision_checker","locator":"tools/decision_verify.py","sha256":"f1ad7c9fbd4c1d899dbb4bebabbbeb97e97a56bd4b279ad7d8ec3722bf12e0f6"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_decision_rank","profiles":["full"],"refusal_boundary":"Only 2..6 schema-valid options under a caller-declared admissible numeric criterion are ranked. Invalid shape/sense/unit, value-judgment criteria, zero top margin, or checker mismatch refuses; caller values are not treated as measurements or confidence intervals.","release_state":"v1.7.3","schema_sha256":"843fe08464d40d97094eeb6424c0c29a3e2617172ba56262ca4122468a8bb92f","status_classes":["exact","refused"],"supported_fragment":"Domain pack jackal.decision.matrix, operation decision.matrix.rank.v1, routed through pack-route. Orders 2..6 labelled options by a caller-declared numeric criterion and emits a jackal-decision-cert-v1 naming the selected option, the runner-up and the exact margin; the manifest-pinned tools/decision_verify.py recomputes the whole ordering from the certificate's own option values and only ACCEPT returns success. Criterion admissibility is decided by the engine against a fixed word list, so a bare value judgment refuses `decision-value-judgment`; a top-two tie refuses `decision-margin-zero`. ASSURANCE ceiling exact; CONSEQUENCE ceiling decision-boundary. The arithmetic is exact and the choice of criterion is not: the declared criterion and the declared option values remain the caller's, this result is not a claim that the criterion is the right one, the values are not measurements, and the margin is not a confidence interval. For the closed-unit lane that additionally requires a declared unit, use jackal_decision_rank_v2. NOT formal: no Lean checker and no theorem are involved. Inputs: decision_id: Caller's identifier for this decision, bound into the certificate. Bytes are restricted to [A-Za-z0-9_]; anything else refuses `prog-symbol`.; criterion: The declared numeric criterion (e.g. 'latency_ms'); a value judgment refuses `decision-value-judgment`.; sense: Exactly 'min' or 'max'; anything else refuses `decision-sense-unknown`.; options: 2..6 whitespace-separated `label value` pairs, e.g. 'a 10 b 20 c 30'. Values are canonical integers. A label containing whitespace shifts the pairing and refuses `pack-args-shape`; it is never silently re-paired."},{"assurance_classes":["exact"],"consequence_ceiling":"decision-boundary","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"decision-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_decision_checker","locator":"tools/decision_verify.py","sha256":"f1ad7c9fbd4c1d899dbb4bebabbbeb97e97a56bd4b279ad7d8ec3722bf12e0f6"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_decision_rank_v2","profiles":["full"],"refusal_boundary":"Only 2..6 schema-valid options under a caller-declared admissible numeric criterion are ranked. Invalid shape/sense/unit, value-judgment criteria, zero top margin, or checker mismatch refuses; caller values are not treated as measurements or confidence intervals.","release_state":"v1.7.3","schema_sha256":"cdc8abba09426977a5319b52410204f21e2e1eb7b38a9de31de751fcb862e78a","status_classes":["exact","refused"],"supported_fragment":"Domain pack jackal.decision.matrix, operation decision.matrix.rank.v2, routed through pack-route. Same deterministic ordering as jackal_decision_rank, plus a REQUIRED declared unit drawn from a closed vocabulary: the 65 canonical ids of release/claim/unit_registry_v1.json excluding the dimensionless identity `one` (66 ids in the registry, `one` is not admitted here). Matching is exact-token and case-sensitive; an alias, a spelled-out name such as 'millisecond', a different case, or the dimensionless identity all refuse `decision-unit-unknown`, and an empty unit refuses `decision-unit-missing`. Emits jackal-decision-cert-v2, re-checked by the manifest-pinned tools/decision_verify.py; only ACCEPT returns success. ASSURANCE ceiling exact; CONSEQUENCE ceiling decision-boundary. Honest residual: a declared unit is NOT a measurement. The closed vocabulary forces the caller to name a dimension, and nothing more — a value-judgment criterion that survives the engine's word list is still accepted when a real unit is declared (`most_elegant` in `ms` ranks), and the values themselves remain caller-declared. NOT formal: no Lean checker and no theorem are involved. Inputs: decision_id: Caller's identifier for this decision, bound into the certificate. Bytes are restricted to [A-Za-z0-9_]; anything else refuses `prog-symbol`.; criterion: The declared numeric criterion; a value judgment refuses `decision-value-judgment` even with an admissible unit.; unit: One canonical unit id from release/claim/unit_registry_v1.json, excluding `one`. Exact token, case-sensitive: 'ms' is admitted, 'millisecond' and 'MS' refuse `decision-unit-unknown`.; sense: Exactly 'min' or 'max'; anything else refuses `decision-sense-unknown`.; options: 2..6 whitespace-separated `label value` pairs, e.g. 'a 10 b 20 c 30'. Values are canonical integers. A label containing whitespace shifts the pairing and refuses `pack-args-shape`; it is never silently re-paired."},{"assurance_classes":["verified-program-evidence"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"cafbd25791225856c2914e9dc86b5dcd3e23d6cc0285b09800de34922f76d52e"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_check_program","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"177cfcf9dfcd6bbc6e657eb83b88f04bfedaa0f28f81307077a776e2052df1e2","status_classes":["verified-program-evidence","refused"],"supported_fragment":"Run a caller-pinned Anubis compiler only as `build --evidence` in Safe mode, never execute the compiled artifact, then independently close and replay the resulting strict anubis.program-evidence.v3 package under inventory-safe-v1. Emits only verified-program-evidence or a named refusal. This profile checks producer-attested function/policy inventories but explicitly does not establish policy-construct totality, source-to-VC proof, SMT-to-CNF proof, source-native refinement, runtime behavior, or universal soundness. Inputs: source_path: Local regular non-symlink Anubis source path.; anubis_bin: Local regular non-symlink Anubis executable; caller-pinned and hashed before/after build.; expected_source_sha256: Caller-pinned exact source SHA-256.; expected_compiler_sha256: Caller-pinned approved Anubis executable SHA-256.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1; contracted-safe-v1 refuses.; nonce: Caller nonce bound into the receipt.; out_root: New local output root; existing paths refuse."},{"assurance_classes":["verified-program-evidence"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"cafbd25791225856c2914e9dc86b5dcd3e23d6cc0285b09800de34922f76d52e"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_verify_program","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"45c7aae87c329925f6bd6b9100efc7d099d70fcaeaba915ee59937f019e1153d","status_classes":["verified-program-evidence","refused"],"supported_fragment":"Independently verify caller-selected Anubis Safe source and evidence bytes under inventory-safe-v1: strict v3 roster, exact manifest closure, source/compiler/artifact/policy pins, producer-summary reconciliation, one-to-one solver/proof paths and counters, approved Z3 UNSAT replay, and independent RUP replay. Never executes the artifact and never claims independent policy-construct totality or source-native refinement. Inputs: source_path: Caller-selected regular non-symlink Anubis source path.; evidence_dir: Caller-selected strict anubis.program-evidence.v3 directory.; expected_source_sha256: Caller-pinned exact source SHA-256.; expected_compiler_sha256: Caller-pinned producer executable SHA-256.; expected_artifact_sha256: Caller-pinned sealed artifact SHA-256; artifact bytes are read but never executed.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1.; nonce: Caller nonce bound into the receipt."},{"assurance_classes":["verified-program-receipt"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"cafbd25791225856c2914e9dc86b5dcd3e23d6cc0285b09800de34922f76d52e"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_verify_program_receipt","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"6bb75d81aebf6f2b3b20900357204e9ef0858cdac412ea016868028cdd2a67d3","status_classes":["verified-program-receipt","refused"],"supported_fragment":"Recompute a jackal-anubis-program-receipt-v1 from caller-selected source/evidence bytes and independent caller pins, rejecting outer-digest-consistent semantic laundering. Success is only verified-program-receipt; it does not raise the underlying inventory-safe-v1 assurance ceiling. Inputs: receipt: Program receipt object to replay; its own pins are never trusted.; source_path: Caller-selected regular source path.; evidence_dir: Caller-selected evidence directory.; expected_source_sha256: Caller-pinned source SHA-256.; expected_compiler_sha256: Caller-pinned compiler SHA-256.; expected_artifact_sha256: Caller-pinned artifact SHA-256.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1.; nonce: Caller nonce; never copied from the receipt."}],"unique_tool_count":41} +{"catalog":{"path":"plugin/hermes/tools.json","sha256":"53c823f07db512b82e01a4f132ff43be426b4b227c436e8853c5144ae0504e87","version":"v1.7.3"},"inputs":[{"path":"tools/capability_inventory.py","sha256":"a966660ef94d7b788be9f92451a78e43b41e12ae2c4e942834c1703994c2ccc0"},{"path":"plugin/hermes/tools.json","sha256":"53c823f07db512b82e01a4f132ff43be426b4b227c436e8853c5144ae0504e87"},{"path":"plugin/hermes/profiles/core.json","sha256":"49f33ba23cca5ab940f1929604f61491bc914d092f291cda4fe4f06b37d042d3"},{"path":"plugin/hermes/profiles/formal.json","sha256":"9be2b3144486311d9ba7f1d41c5033eb8e2553e9d12b71d46e512401f57a084b"},{"path":"plugin/hermes/profiles/full.json","sha256":"0db937da01737bbc0341a591ecd23e55008d8ffc02368517c7d1e7da8b309dec"},{"path":"plugin/hermes/server.py","sha256":"4c42725d797ac78ed20d3e843e602b1c60c88bd13f74e06c65a6b4016b3b7daf"},{"path":"plugins/jackel/.codex-plugin/plugin.json","sha256":"49bbd046759b045add1caf1f19300431fe7d697b59bfd93b57daf1d7edb709ff"},{"path":"plugins/jackel/mcp/server.py","sha256":"5ae164132f21a8dfd19a5ab0c679ccd3ccfc6e2c35ce4a6a6d2968cd550bc07a"},{"path":"release/MANIFEST.sha256","sha256":"3886588b938986f4f6cfe0c7884d35b8140639408e8e9116d962fb46c3876c51"},{"path":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"path":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"path":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"}],"release":{"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"state":"v1.7.3","statement":"Published release identity; the annotated v1.7.3 tag and GitHub release must bind these exact bytes.","version":"v1.7.3"},"schema":"jackal-capability-inventory-v1","status_vocabulary":["bounded","checked","estimated","exact","formal-bounded","indeterminate","model-based","ok","refused","structural-exact","verified","verified-program-evidence","verified-program-receipt"],"tool_count":41,"tools":[{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_range_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"826bed7e2645735d5d333040eaa8c28425df90b6e87f8dd6aa94df1cc40ace45","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded receipt with the certificate embedded (or refuse). Inputs: expression: Anubis expression in the single variable x, restricted to the certified fragment.; input_lo: Interval lower bound as an integer or reduced ℚ (e.g. '1', '2/3').; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-gaussian","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_gaussian_integral","profiles":["formal","full"],"refusal_boundary":"Only the exact catalog-declared Gaussian form and canonical rational bounds/tolerance are admitted. Any other form, failed enclosure, checker rejection, or pin/identity mismatch refuses without downgrade.","release_state":"v1.7.3","schema_sha256":"4a43f67d68610c9e7b13f8bc8195c6c3e9ea24493494eb5aca8e768d707adb13","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a zero-libm formal-bounded Gaussian integral receipt, rerun the pinned checker, or refuse without downgrade. Inputs: expression: Exact canonical exp(-A*(x-mu)^2) expression; all other expressions refuse.; input_lo: Integration lower bound as a canonical rational.; input_hi: Integration upper bound as a canonical rational.; tolerance: Maximum enclosure width as a positive canonical rational."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-int-cert","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_bound_cert","profiles":["formal","full"],"refusal_boundary":"Only the request-bound v1.7.2 composed-integral fragment and canonical bounds/tolerance are admitted. Request-unbound v1.7.0 evidence, unsupported syntax, failed subdivision, checker rejection, or identity mismatch refuses without using the weaker float lane.","release_state":"v1.7.3","schema_sha256":"1229ede1ee518a9b19d3a201268e598fac6fd52fd2eef1bb379f920d6093b9cd","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a request-bound certified composed definite-integral formal receipt (v1.7.2): the untrusted exact-rational producer mirrors the engine's adaptive subdivision, the pinned Lean-proved jackal_int_cert_check binds the exact raw expression/bounds/tolerance and re-checks the whole subdivision-tree certificate (theorem int_cert_sound), and the receipt is independently re-verified before returning. Request-unbound v1.7.0 receipts are revoked. Certified fragment: num/var/neg/add/sub/mul/div/pow(0..4096)/sin/cos/abs in x. Everything else refuses. The weaker float lane jackal_integrate_bound stays status=bounded and is NOT this tool. Inputs: expression: Integrand in the single variable x, restricted to the certified fragment (num/var/neg/add/sub/mul/div/pow/sin/cos/abs).; input_lo: Integration lower bound as an integer or reduced canonical rational (e.g. '0', '2/3').; input_hi: Integration upper bound as a canonical rational, strictly above input_lo.; tolerance: Maximum enclosure width as a positive canonical rational (e.g. '1/100')."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-receipt-registry","identities":[{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_verify_receipt","profiles":["core","formal","full"],"refusal_boundary":"Only closed-registry range/rational, Gaussian, and current request-bound int-cert receipts matching independent caller expectations are replayed. Unknown epochs/variants, copied rather than caller-pinned expectations, revoked int-cert evidence, or checker/pin mismatch refuses.","release_state":"v1.7.3","schema_sha256":"988b83705212769a01eb2e5f5b44322b5728d5fd86eef4f64f7a4a37e378fc1f","status_classes":["verified","refused"],"supported_fragment":"Re-run the matching pinned Lean-proved checker over an embedded certificate using a closed epoch/variant registry: current v1.7.2 range/rational and request-bound int_cert, replay-only v1.5.0 range/rational, or Gaussian v1.5.0. Request-unbound v1.7.0 int_cert receipts refuse. Inputs: receipt: A jackal-formal-receipt-v1 JSON document.; expected_release_epoch: Caller-authorized release epoch, not copied from the receipt.; expected_command: Caller-authorized operation: range-bound-cert or integrate.; expected_expression: Exact raw expression supplied by the caller.; expected_input_lo: Exact raw lower-bound token supplied by the caller.; expected_input_hi: Exact raw upper-bound token supplied by the caller.; expected_tolerance: Exact raw tolerance token; required for Gaussian and int_cert receipts and forbidden for range receipts."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_sqrt_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"bc611de421d812aa6d6d8772fb986c17bcde74d7fe70ea31ff22433335d67c6d","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q sqrt(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'sqrt(x)' on a canonical rational interval; every other expression refuses without downgrade. v1.4.0 fragment extension. Inputs: expression: Must equal 'sqrt(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational (e.g. '2', '1/4'); must be >= 0.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_exp_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"9cc7bee07eebc566a9e267ad1b30c10a73cb25c18090ed2f9a3e9ec48550b928","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q exp(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'exp(x)' on a canonical rational interval [lo, hi] (general-sign since v1.5.0); every other expression refuses without downgrade. v1.4.1 fragment extension. Inputs: expression: Must equal 'exp(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational; any sign (general-sign since v1.5.0).; input_hi: Interval upper bound (canonical rational, hi >= lo); the producer picks a Taylor degree with 2*hi <= n+1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_ln_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"16dfb2b64dc9e290e1c062eba898233b04b187f1b244f6cc06433c48d1b7da45","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q ln(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'ln(x)' on a canonical rational interval with lo > 0; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'ln(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational; must be > 0.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_sin_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"d578799057048871ff13eca207bda2f9564261fce975801904d8cb34370cc7fe","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q sin(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'sin(x)' on a canonical rational interval whose midpoint m satisfies |m| <= 1; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'sin(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo); midpoint (lo+hi)/2 must satisfy |m| <= 1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_cos_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"d0f575ac0dbfe5e64aede075ae30bb1a625f05963e772febca6ac180b29f062b","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q cos(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'cos(x)' on a canonical rational interval whose midpoint m satisfies |m| <= 1; every other expression refuses without downgrade. Shares the sin_rat producer (--op cos). v1.5.0 fragment extension. Inputs: expression: Must equal 'cos(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo); midpoint (lo+hi)/2 must satisfy |m| <= 1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_atan_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"f16e48c7a37e284e124fe20766c7db2b90b4eed8fb748c2efebc9ee7c4b80767","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q atan(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'atan(x)' on a canonical rational interval; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'atan(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_tanh_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"6f9b24d732cc6fc2b0ad9ef7d51fa8cd88f2a344b3152c54f288f6a25a8fe05a","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q tanh enclosure via the untrusted composite producer + Lean-proved checker. NO libm on the proof-decision path. tanh is not an engine grammar token: admits ONLY the literal composite expression '1-2/(exp(2*x)+1)' (= tanh(x) mathematically) on a canonical rational interval with |lo|,|hi| <= 20; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal '1-2/(exp(2*x)+1)' after whitespace normalization (the frozen tanh-defining composite).; input_lo: Interval lower bound as an integer or reduced rational; |lo| <= 20.; input_hi: Interval upper bound (canonical rational, hi >= lo); |hi| <= 20."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_exact","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"42319cf6d3e3f7a8da025e880b8dfc02eb2c6e3128f8b93c11f41545d8bf1d8d","status_classes":["exact","refused"],"supported_fragment":"Exact big-rational arithmetic (status=exact). NOT formal: computationally exact, outside the Lean certificate chain. Inputs: expression: Integers, decimals, + - * / ^ (integer exponents), parentheses. Everything else refuses."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_evaluate","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"5baa3a344309d714a8b66c9fb4a14a97c8182b3cfe1326faa2e9967840eee17c","status_classes":["estimated","refused"],"supported_fragment":"IEEE f64 expression evaluation (status=estimated). A plain number, honestly labeled: no bound, no proof. Inputs: expression: Full expression grammar incl. transcendental functions and constants."},{"assurance_classes":["checked"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_diff","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"605972a25cde65779e921b8a27b7f1a0c19d540f5330791ec0fb571cccf858ad","status_classes":["checked","refused"],"supported_fragment":"Symbolic d/dx with numeric self-verification (status=checked). Sampled agreement is a check, not a proof of identity. Inputs: expression: Expression in x; non-differentiable functions fail closed."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"6d05a705ff580a831f75cbcd2079fe88c3b5d9c858bc6b0c3182ec55aa27cd27","status_classes":["estimated","refused"],"supported_fragment":"Fixed-grid Simpson + Richardson error estimate (status=estimated). Grid-limited: NOT a bound. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; panels: Panel count (e.g. '200')."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_adaptive","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"174132e83bff6d18972cf5d88b072b12d7102cad8fdf05197165c64bfac4fea1","status_classes":["estimated","refused"],"supported_fragment":"Adaptive Simpson with refusal semantics (status=estimated). Refuses when unconverged; agreement is still not a bound. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; tolerance: Local tolerance (e.g. '1e-9')."},{"assurance_classes":["bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_bound","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"9932617903499a2ed2baa4ac213f061f422bd8f2e60bca5bf05225a9f9f788a0","status_classes":["bounded","refused"],"supported_fragment":"Certified interval enclosure of an integral (status=bounded). CONDITIONAL on the stated f64/libm rounding model; implementation campaign-tested, NOT mechanized. Never labeled formal. For a Lean-checked formal-bounded composed enclosure over the certified fragment, use jackal_integrate_bound_cert instead. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; tolerance: Max enclosure width (e.g. '1e-6')."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_solve","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"caf1f55ca8ad1fef2e0fb4f5f5bb600edb147f257427de650335500979c13501","status_classes":["estimated","refused"],"supported_fragment":"Bisection root with residual + first-order conditioning diagnostics (status=estimated). Inputs: expression: f(x) whose root is sought.; input_lo: Bracket lower bound (sign change required).; input_hi: Bracket upper bound."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"ea4ca54f74334d678c3daf9c6686fca186041d27bb2f02dabca21a7747e7d416","status_classes":["exact","refused"],"supported_fragment":"Canonical s-expression + SHA-256 of any parsed expression (status=exact). NOT formal: exact computation outside the Lean certificate chain; no exact-cert emitted. Inputs: expression: Any expression the engine grammar parses."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"199fd63f51398c6e883a407d8e2435e42903e9c76f0227d815f3456b3568d9bc","status_classes":["exact","refused"],"supported_fragment":"Dense Q[x] canonical form, degree <= 64 (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Polynomial expression in x within the poly fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_eq","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"76d9390f705758c6ec2d5fe77cd6a1391908f93ef218ebfd5111c067dc32a819","status_classes":["exact","refused"],"supported_fragment":"Decidable polynomial identity over Q[x] (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: lhs: Left polynomial expression in x.; rhs: Right polynomial expression in x."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_gcd","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"dfff2a285e732d52520ea6fe5efabdab5bd6d956c224f30d163ccbbdbd406a5c","status_classes":["exact","refused"],"supported_fragment":"Monic polynomial gcd over Q[x] via Euclid (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: lhs: Left polynomial expression in x.; rhs: Right polynomial expression in x."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_ratfunc_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"3d4c7d73d13aa88606e9e005b7731c19ac63f9fe559b38e6ff777f979afd3b40","status_classes":["exact","refused"],"supported_fragment":"Rational-function canonical form P/Q, gcd-reduced, monic denominator, explicit denominator-nonzero side condition (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Rational-function expression in x within the ratfunc fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_roots_isolate","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"ea98289e6b6319b7c0b3e6e9832e07ff4a9dd06be1d7862956c50df6e1785978","status_classes":["exact","refused"],"supported_fragment":"Sturm-sequence isolation of all distinct real roots (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Polynomial expression in x within the poly fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_alg_sign","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"b4ad3c632887bc8875f8334dea3391017d73f30fa4895d988062882e89c2c1a5","status_classes":["exact","refused"],"supported_fragment":"Exact sign of a Q[x] polynomial at a rational point (status=exact). NOT formal; no exact-cert emitted. Inputs: expression: Polynomial expression in x within the poly fragment.; point: Rational evaluation point (e.g. '3/2')."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_alg_cmp","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"bfea42d3f97e6f0403d11155d667dfec7000719e2aa3af67c8897989a9e2eee4","status_classes":["exact","refused"],"supported_fragment":"Order decision between two isolated real algebraic numbers (status=exact). NOT formal; no exact-cert emitted. Inputs: p: First defining polynomial in x.; a1: First isolating interval lower bound (rational).; b1: First isolating interval upper bound (rational).; q: Second defining polynomial in x.; a2: Second isolating interval lower bound (rational).; b2: Second isolating interval upper bound (rational)."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_xgcd","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"1c7fb606e43e71eeb4ab288c08ea4a6c89efd95beb3f802e084d5d3c1a3beaf6","status_classes":["exact","refused"],"supported_fragment":"Extended gcd with Bezout certificate (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: a: First integer.; b: Second integer."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_mod_pow","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"b3edc74b3901989b9248f8b89feaed2cc396e218abf9ccfca7ab53a99a9c7bc1","status_classes":["exact","refused"],"supported_fragment":"Modular exponentiation via square-and-multiply (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: base: Base integer.; exp: Nonnegative exponent integer.; mod: Modulus integer >= 1."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_mod_inv","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"d0826f19759afacd20d4a5f0d6704a52bce158c6950bb852a5e0774886a4abd7","status_classes":["exact","refused"],"supported_fragment":"Modular inverse with product certificate (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: a: Integer to invert.; m: Modulus integer >= 2; gcd(a, m) must be 1."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_crt","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"d44aebbbcb3b00ad0d192581533c5cfdb164e26431f3ed850406c8ecfa5044b4","status_classes":["exact","refused"],"supported_fragment":"Chinese remainder reconstruction over pairwise-coprime moduli, up to 16 pairs (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: args: Space-separated residue/modulus pairs: 'r1 m1 r2 m2 [...]' (e.g. '2 3 3 5 2 7')."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_divides","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"1191b2b4ce3a9a5c3a1dafb0917fad46ca9c3375c73f4ae59ff7a389d513adb4","status_classes":["exact","refused"],"supported_fragment":"Exact divisibility decision (status=exact). NOT formal; no exact-cert emitted. Inputs: a: Candidate divisor integer.; b: Dividend integer."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_prime_cert","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"3ff03881b24f8fd94db68b210874010e66ce0e3d32666d98a21c1bc40ccc5646","status_classes":["exact","refused"],"supported_fragment":"Pratt primality certificate or composite divisor witness, budgeted and fail-closed (status=exact; n <= 10^60, Pratt tree depth <= 64, nodes <= 512). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: n: Integer >= 2, at most 61 digits."},{"assurance_classes":["estimated","model-based","checked","bounded","formal-bounded","exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"claim-router","identities":[{"label":"claim_kernel","locator":"tools/claim_kernel.py","sha256":"77b0f85ad5fb7214f88898b60ea29ea9fd7be740c38b655388444e6e5181f348"},{"label":"claim_router","locator":"tools/claim_router.py","sha256":"02328cf177a0423bdc5cbca6ec0ea946bb0679bbd3dc6c24140d32598e575afb"},{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"},{"label":"claim_inference_registry","locator":"release/claim/inference_registry_v1.json","sha256":"c70b33d5aee8071b5125e6a5f8ffe5226fc22a137d920c17d9b3463968be13f0"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_claim","profiles":["core","formal","full"],"refusal_boundary":"Only jackal-claim-request-v1 and its closed step vocabulary are compiled. Policy, identity, schema, route, or assurance failures refuse; fallback is off by default and any caller-enabled fallback remains explicit in the route trace rather than silently changing assurance.","release_state":"v1.7.3","schema_sha256":"4d2703ff772433f39ac8b6555727e856685b0e5042b9c2cc8fcaa4402d6b9153","status_classes":["ok","refused"],"supported_fragment":"Compile a structured jackal-claim-request-v1 into a canonical, content-addressed jackal-claim-bundle-v1 evidence graph through the deterministic policy router. Routes through exact, current/archival range-family, Gaussian, request-bound composed-integral, machine, and unit lanes; emits a route trace naming candidates and refusal reasons; and refuses rather than silently downgrading (allow_fallback defaults false). The bundle is independently replayable via jackal_verify_bundle. Inputs: request: jackal-claim-request-v1 object: {schema, steps:[{id, op, ...}], root, policy?, nonce?, emitted_at_unix?, max_age_seconds?, expires_at_unix?}. Step ops: input, exact, enclose, gaussian, integrate_cert, machine, interval_add/sub/mul/div, threshold, decision, convert, and, model, passthrough, attach."},{"assurance_classes":["estimated","model-based","checked","bounded","formal-bounded","exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"claim-verifier","identities":[{"label":"claim_verifier","locator":"tools/claim_bundle_verify.py","sha256":"e0fcb9540c730bd9bb492b528ed42d29d49fc775b3aa0f9b831b6264fd68fd22"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"},{"label":"claim_inference_registry","locator":"release/claim/inference_registry_v1.json","sha256":"c70b33d5aee8071b5125e6a5f8ffe5226fc22a137d920c17d9b3463968be13f0"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_verify_bundle","profiles":["core","formal","full"],"refusal_boundary":"Only canonical bundles matching separately caller-pinned epoch, policy, root proposition, time, and nonce are replayed. Semantic, graph, freshness, evidence, checker, or pin ambiguity returns refused or indeterminate exactly as declared; it is never converted to success.","release_state":"v1.7.3","schema_sha256":"9e3acec17637a352bc88e3b08e8679a34f1efae3539fe1cce05646212be4cb5f","status_classes":["verified","refused","indeterminate"],"supported_fragment":"Independently replay a jackal-claim-bundle-v1 against caller-pinned expectations. The standalone dependency-free verifier recomputes every canonical byte and hash, revalidates the DAG, selects only the closed current/archival range, Gaussian, or current request-bound int-cert checker/proof tuple, re-runs embedded evidence, recomputes machine/unit mathematics, re-evaluates every inference rule and assurance-axis propagation, enforces consequence-class floors and policy, and recomputes the deterministic rendering. Returns verified | refused | indeterminate with exact reasons — never a generic green badge. Inputs: bundle: The jackal-claim-bundle-v1 object to replay.; expected_release_epoch: Caller-pinned epoch (e.g. 'v1.6.0'); never copied from the bundle.; expected_policy_sha256: Caller-pinned SHA-256 of the canonical policy bytes.; expected_root_proposition: Caller-pinned canonical root proposition IR object.; verification_time_unix: Caller-supplied verification time (unix seconds) for freshness/expiry checks.; expected_nonce: Caller nonce; the bundle root must bind exactly this nonce."},{"assurance_classes":["structural-exact"],"consequence_ceiling":"informational","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"structural-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_test_exists_checker","locator":"tools/test_exists_verify.py","sha256":"598cb99e1eb70c9410ca87345efee346f73e43aaf3625427dca17ea04231caea"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_test_exists","profiles":["full"],"refusal_boundary":"Only byte-exact source/citation structure described by the schema is accepted after independent file-byte recomputation. Path traversal, malformed symbols/hashes, missing text/declarations, or checker mismatch refuses; the result never asserts test execution or correctness.","release_state":"v1.7.3","schema_sha256":"9685ecf3bcf78a3a26916455cc528cdeac137420e8694447e2865b33890f9d46","status_classes":["structural-exact","refused"],"supported_fragment":"Domain pack jackal.programming.source, operation programming.source.test_exists.v1, routed through pack-route. States one byte-exact STRUCTURAL fact: a declaration-shaped occurrence of `symbol` exists at `declaration_line` in a file whose content hash is exactly `file_sha256`, and the file contains exactly `declaration_count` such occurrences. The engine validates the canonical FORM; the manifest-pinned independent checker tools/test_exists_verify.py then recomputes every claimed field from the real bytes on disk and only an ACCEPT verdict returns success, so a misstated hash, line or count refuses instead of minting a certificate. ASSURANCE ceiling exact; CONSEQUENCE ceiling informational, and the second does not rise with the first: a test-exists-cert is NEVER evidence that the code under test is correct, that the test executes, that it is collected by any runner, or that it asserts anything at all. NOT formal: no Lean checker and no theorem are involved. Do not cite this certificate in support of a correctness claim. Inputs: file_path: Repository-relative path token; absolute paths and parent traversal refuse `prog-path`.; file_sha256: Exactly 64 lowercase hex characters; the checker recomputes it from the file bytes.; symbol: Identifier of the declaration; a non-identifier refuses `prog-symbol`.; declaration_line: 1-based line of the declaration as a canonical positive integer.; declaration_count: Total declaration-shaped occurrences of `symbol` in the file; `0` refuses `prog-absent`."},{"assurance_classes":["structural-exact"],"consequence_ceiling":"informational","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"structural-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_test_exists_checker","locator":"tools/test_exists_verify.py","sha256":"598cb99e1eb70c9410ca87345efee346f73e43aaf3625427dca17ea04231caea"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_claim_cites_test","profiles":["full"],"refusal_boundary":"Only byte-exact source/citation structure described by the schema is accepted after independent file-byte recomputation. Path traversal, malformed symbols/hashes, missing text/declarations, or checker mismatch refuses; the result never asserts test execution or correctness.","release_state":"v1.7.3","schema_sha256":"69a533155bde04bfd5dedd43e9d63acd02f3e2773757936e9e1714458e20abd4","status_classes":["structural-exact","refused"],"supported_fragment":"Domain pack jackal.programming.source, operation programming.source.claim_cites_test.v1, routed through pack-route. Resolves a citation: `claim_text` occurs verbatim in the document at `doc_path`/`doc_sha256`, and `symbol` has a declaration-shaped occurrence in the cited test file at `test_path`/`test_sha256`. Resolution is all this establishes. It does NOT establish that the cited test covers, exercises or supports the claim — the cited test may check something entirely different, which is the exact defect this operation exists to bound rather than hide. The manifest-pinned tools/test_exists_verify.py re-runs over the certificate and only ACCEPT returns success, so a claim text absent from the document or a dangling citation refuses. ASSURANCE ceiling exact; CONSEQUENCE ceiling informational, and the second does not rise with the first. NOT formal: no Lean checker and no theorem are involved. Inputs: doc_path: Repository-relative path of the document making the claim.; doc_sha256: Exactly 64 lowercase hex characters for the document bytes.; claim_text: The claim sentence, verbatim, 1..2048 bytes; it must occur in the document.; test_path: Repository-relative path of the cited test file.; test_sha256: Exactly 64 lowercase hex characters for the cited test file bytes.; symbol: Identifier the citation resolves to inside the cited test file."},{"assurance_classes":["exact"],"consequence_ceiling":"decision-boundary","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"decision-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_decision_checker","locator":"tools/decision_verify.py","sha256":"f1ad7c9fbd4c1d899dbb4bebabbbeb97e97a56bd4b279ad7d8ec3722bf12e0f6"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_decision_rank","profiles":["full"],"refusal_boundary":"Only 2..6 schema-valid options under a caller-declared admissible numeric criterion are ranked. Invalid shape/sense/unit, value-judgment criteria, zero top margin, or checker mismatch refuses; caller values are not treated as measurements or confidence intervals.","release_state":"v1.7.3","schema_sha256":"843fe08464d40d97094eeb6424c0c29a3e2617172ba56262ca4122468a8bb92f","status_classes":["exact","refused"],"supported_fragment":"Domain pack jackal.decision.matrix, operation decision.matrix.rank.v1, routed through pack-route. Orders 2..6 labelled options by a caller-declared numeric criterion and emits a jackal-decision-cert-v1 naming the selected option, the runner-up and the exact margin; the manifest-pinned tools/decision_verify.py recomputes the whole ordering from the certificate's own option values and only ACCEPT returns success. Criterion admissibility is decided by the engine against a fixed word list, so a bare value judgment refuses `decision-value-judgment`; a top-two tie refuses `decision-margin-zero`. ASSURANCE ceiling exact; CONSEQUENCE ceiling decision-boundary. The arithmetic is exact and the choice of criterion is not: the declared criterion and the declared option values remain the caller's, this result is not a claim that the criterion is the right one, the values are not measurements, and the margin is not a confidence interval. For the closed-unit lane that additionally requires a declared unit, use jackal_decision_rank_v2. NOT formal: no Lean checker and no theorem are involved. Inputs: decision_id: Caller's identifier for this decision, bound into the certificate. Bytes are restricted to [A-Za-z0-9_]; anything else refuses `prog-symbol`.; criterion: The declared numeric criterion (e.g. 'latency_ms'); a value judgment refuses `decision-value-judgment`.; sense: Exactly 'min' or 'max'; anything else refuses `decision-sense-unknown`.; options: 2..6 whitespace-separated `label value` pairs, e.g. 'a 10 b 20 c 30'. Values are canonical integers. A label containing whitespace shifts the pairing and refuses `pack-args-shape`; it is never silently re-paired."},{"assurance_classes":["exact"],"consequence_ceiling":"decision-boundary","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"decision-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_decision_checker","locator":"tools/decision_verify.py","sha256":"f1ad7c9fbd4c1d899dbb4bebabbbeb97e97a56bd4b279ad7d8ec3722bf12e0f6"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_decision_rank_v2","profiles":["full"],"refusal_boundary":"Only 2..6 schema-valid options under a caller-declared admissible numeric criterion are ranked. Invalid shape/sense/unit, value-judgment criteria, zero top margin, or checker mismatch refuses; caller values are not treated as measurements or confidence intervals.","release_state":"v1.7.3","schema_sha256":"cdc8abba09426977a5319b52410204f21e2e1eb7b38a9de31de751fcb862e78a","status_classes":["exact","refused"],"supported_fragment":"Domain pack jackal.decision.matrix, operation decision.matrix.rank.v2, routed through pack-route. Same deterministic ordering as jackal_decision_rank, plus a REQUIRED declared unit drawn from a closed vocabulary: the 65 canonical ids of release/claim/unit_registry_v1.json excluding the dimensionless identity `one` (66 ids in the registry, `one` is not admitted here). Matching is exact-token and case-sensitive; an alias, a spelled-out name such as 'millisecond', a different case, or the dimensionless identity all refuse `decision-unit-unknown`, and an empty unit refuses `decision-unit-missing`. Emits jackal-decision-cert-v2, re-checked by the manifest-pinned tools/decision_verify.py; only ACCEPT returns success. ASSURANCE ceiling exact; CONSEQUENCE ceiling decision-boundary. Honest residual: a declared unit is NOT a measurement. The closed vocabulary forces the caller to name a dimension, and nothing more — a value-judgment criterion that survives the engine's word list is still accepted when a real unit is declared (`most_elegant` in `ms` ranks), and the values themselves remain caller-declared. NOT formal: no Lean checker and no theorem are involved. Inputs: decision_id: Caller's identifier for this decision, bound into the certificate. Bytes are restricted to [A-Za-z0-9_]; anything else refuses `prog-symbol`.; criterion: The declared numeric criterion; a value judgment refuses `decision-value-judgment` even with an admissible unit.; unit: One canonical unit id from release/claim/unit_registry_v1.json, excluding `one`. Exact token, case-sensitive: 'ms' is admitted, 'millisecond' and 'MS' refuse `decision-unit-unknown`.; sense: Exactly 'min' or 'max'; anything else refuses `decision-sense-unknown`.; options: 2..6 whitespace-separated `label value` pairs, e.g. 'a 10 b 20 c 30'. Values are canonical integers. A label containing whitespace shifts the pairing and refuses `pack-args-shape`; it is never silently re-paired."},{"assurance_classes":["verified-program-evidence"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"cafbd25791225856c2914e9dc86b5dcd3e23d6cc0285b09800de34922f76d52e"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_check_program","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"177cfcf9dfcd6bbc6e657eb83b88f04bfedaa0f28f81307077a776e2052df1e2","status_classes":["verified-program-evidence","refused"],"supported_fragment":"Run a caller-pinned Anubis compiler only as `build --evidence` in Safe mode, never execute the compiled artifact, then independently close and replay the resulting strict anubis.program-evidence.v3 package under inventory-safe-v1. Emits only verified-program-evidence or a named refusal. This profile checks producer-attested function/policy inventories but explicitly does not establish policy-construct totality, source-to-VC proof, SMT-to-CNF proof, source-native refinement, runtime behavior, or universal soundness. Inputs: source_path: Local regular non-symlink Anubis source path.; anubis_bin: Local regular non-symlink Anubis executable; caller-pinned and hashed before/after build.; expected_source_sha256: Caller-pinned exact source SHA-256.; expected_compiler_sha256: Caller-pinned approved Anubis executable SHA-256.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1; contracted-safe-v1 refuses.; nonce: Caller nonce bound into the receipt.; out_root: New local output root; existing paths refuse."},{"assurance_classes":["verified-program-evidence"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"cafbd25791225856c2914e9dc86b5dcd3e23d6cc0285b09800de34922f76d52e"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_verify_program","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"45c7aae87c329925f6bd6b9100efc7d099d70fcaeaba915ee59937f019e1153d","status_classes":["verified-program-evidence","refused"],"supported_fragment":"Independently verify caller-selected Anubis Safe source and evidence bytes under inventory-safe-v1: strict v3 roster, exact manifest closure, source/compiler/artifact/policy pins, producer-summary reconciliation, one-to-one solver/proof paths and counters, approved Z3 UNSAT replay, and independent RUP replay. Never executes the artifact and never claims independent policy-construct totality or source-native refinement. Inputs: source_path: Caller-selected regular non-symlink Anubis source path.; evidence_dir: Caller-selected strict anubis.program-evidence.v3 directory.; expected_source_sha256: Caller-pinned exact source SHA-256.; expected_compiler_sha256: Caller-pinned producer executable SHA-256.; expected_artifact_sha256: Caller-pinned sealed artifact SHA-256; artifact bytes are read but never executed.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1.; nonce: Caller nonce bound into the receipt."},{"assurance_classes":["verified-program-receipt"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"cafbd25791225856c2914e9dc86b5dcd3e23d6cc0285b09800de34922f76d52e"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_verify_program_receipt","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"6bb75d81aebf6f2b3b20900357204e9ef0858cdac412ea016868028cdd2a67d3","status_classes":["verified-program-receipt","refused"],"supported_fragment":"Recompute a jackal-anubis-program-receipt-v1 from caller-selected source/evidence bytes and independent caller pins, rejecting outer-digest-consistent semantic laundering. Success is only verified-program-receipt; it does not raise the underlying inventory-safe-v1 assurance ceiling. Inputs: receipt: Program receipt object to replay; its own pins are never trusted.; source_path: Caller-selected regular source path.; evidence_dir: Caller-selected evidence directory.; expected_source_sha256: Caller-pinned source SHA-256.; expected_compiler_sha256: Caller-pinned compiler SHA-256.; expected_artifact_sha256: Caller-pinned artifact SHA-256.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1.; nonce: Caller nonce; never copied from the receipt."}],"unique_tool_count":41} diff --git a/tests/anubis_program_verifier_test.py b/tests/anubis_program_verifier_test.py index b2d50e9..3bf4e8c 100755 --- a/tests/anubis_program_verifier_test.py +++ b/tests/anubis_program_verifier_test.py @@ -538,6 +538,10 @@ def test_check_program_refuses_dangling_out_root_symlink(self) -> None: verifier = importlib.util.module_from_spec(spec) spec.loader.exec_module(verifier) verifier.APPROVED_CHECK_COMPILER_SHA256 = {compiler_sha!r} + # Host-agnostic: check_program resolves the anchor via the host + # helper, so patch it directly (the macOS constant above is not + # consulted on a Linux/aarch64 host). + verifier._approved_check_compiler_sha256_for_host = lambda: {compiler_sha!r} arguments = argparse.Namespace( source={str(source)!r}, anubis_bin={str(compiler)!r}, diff --git a/tests/codex_plugin/test_mcp_adapter.py b/tests/codex_plugin/test_mcp_adapter.py index abdbfc5..849448f 100644 --- a/tests/codex_plugin/test_mcp_adapter.py +++ b/tests/codex_plugin/test_mcp_adapter.py @@ -1892,6 +1892,8 @@ def setUp(self): "package_sha256": "21c7ede586f30a58772f321f7dbb36ab66213e199785489f99133710ac56096e", "package_directory": "jackal-v1.7.0-macos-arm64", + "sha256sums_sha256": + "f1f794ccd2ba331e6188840cfc089180cdcd744f23c1880f8364a81b230c1a28", }, default_locator_path=lambda: self.root / "locator.json", validate_host=mock.Mock(return_value=None), @@ -2177,6 +2179,7 @@ def test_calls_remain_bound_to_snapshot_after_original_launcher_backend_and_aba_ "epoch": "v1.7.0", "asset": "fixture.tar.gz", "package_size": 123, "package_sha256": "c" * 64, "package_directory": "fixture", + "sha256sums_sha256": hashlib.sha256(checksums).hexdigest(), }, SELFTEST_TIMEOUT=2.0, SELFTEST_OUTPUT_LIMIT=65536, validate_host=mock.Mock(return_value=None), diff --git a/tests/codex_plugin/test_runtime_provisioner.py b/tests/codex_plugin/test_runtime_provisioner.py index 4523c97..78c58c0 100644 --- a/tests/codex_plugin/test_runtime_provisioner.py +++ b/tests/codex_plugin/test_runtime_provisioner.py @@ -139,10 +139,15 @@ def write_runtime_fixture(self, root, *, files=None): ) return files - def test_validate_host_accepts_only_darwin_arm64(self): - provisioner.validate_host("Darwin", "arm64") - for system, machine in (("Linux", "arm64"), ("Darwin", "x86_64"), ("Linux", "x86_64")): - with self.subTest(system=system, machine=machine), self.assertRaises(provisioner.ProvisionError): + def test_validate_host_accepts_supported_hosts_and_refuses_others(self): + # Darwin/arm64 and the Linux/aarch64 Omarchy port are supported; Linux/x86_64 + # is a declared host gate (its release pin is None, so provisioning still + # refuses without a published asset). Genuinely foreign hosts must refuse. + for system, machine in (("Darwin", "arm64"), ("Linux", "aarch64"), ("Linux", "x86_64")): + with self.subTest(accept=(system, machine)): + provisioner.validate_host(system, machine) + for system, machine in (("Linux", "arm64"), ("Darwin", "x86_64"), ("Darwin", "aarch64"), ("Windows", "AMD64")): + with self.subTest(refuse=(system, machine)), self.assertRaises(provisioner.ProvisionError): provisioner.validate_host(system, machine) def test_runtime_subprocess_environment_is_minimal_and_preserves_only_jackal_home(self): @@ -1598,13 +1603,15 @@ def test_cli_parse_failure_is_one_bounded_line_without_system_exit(self): class HostPortabilityTests(unittest.TestCase): """The host guard admits exactly the hosts whose primitives are implemented.""" - def test_resolve_host_admits_both_supported_hosts(self): + def test_resolve_host_admits_supported_hosts(self): self.assertEqual(provisioner.resolve_host("Darwin", "arm64"), "macos-arm64") self.assertEqual(provisioner.resolve_host("Linux", "aarch64"), "linux-aarch64") + self.assertEqual(provisioner.resolve_host("Linux", "x86_64"), "linux-x86_64") def test_resolve_host_refuses_near_misses_without_guessing(self): + # Linux/x86_64 is a recognized host tag (declared gate); the near-misses + # below are foreign hosts resolve_host must refuse rather than guess. for system, machine in ( - ("Linux", "x86_64"), ("Darwin", "x86_64"), ("Linux", "arm64"), ("Darwin", "aarch64"), From 59206a363c23b296af66f89f5e02fa38f9b8ab97 Mon Sep 17 00:00:00 2001 From: sicarii Date: Mon, 24 Aug 2026 10:17:58 -0400 Subject: [PATCH 12/22] =?UTF-8?q?omarchy:=20architect=20sign-off=20?= =?UTF-8?q?=E2=80=94=20adopt=20doctor-honest=20Linux/aarch64=20check=20com?= =?UTF-8?q?piler=206c3ae920?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Owner (khephri.labs@proton.me) authorized adopting the host-honesty fix into the signed check compiler. Re-pins the SOURCE-OF-TRUTH trust surface from 7cdafb30 to 6c3ae920 (= anubis-lang 0ad40aaf: 6aa6fd92 v3-emitter + host-honest `anubis doctor`, main.rs only), double-built byte-identical, proven a drop-in (program-evidence for verified_loop.anb is byte-identical to 7cdafb30 after scrubbing volatile fields). Re-pinned (host-aware; Darwin 0d6a8f89 + Z3 anchors + inventory-safe-v1 body 1b94350a untouched): - tools/anubis_program_verify.py APPROVED_CHECK_COMPILER_LINUX_AARCH64_SHA256 - release/evidence/approved_check_compiler.linux-aarch64 (marker) - release/MANIFEST.linux-aarch64.sha256 (approved-check-compiler row via repin_linux) - release/build_package_linux.sh APPROVED_CC_SHA256 (next package build) - release/evidence/anubis_program_dogfood_linux_aarch64_v1.json (designation; the v1.7.3 tarball's shipped_check_compiler stays 7cdafb30 — honest as-shipped) - OMARCHY_BUILD.md Incidental: repin_linux also rebound MANIFEST `compiler_pin` c6affa8c -> 2704f083, the now-doctor-honest language anubis at ~/.local/bin/anubis (jackal-native re-builds with it at V111). Consistent with adopting the doctor-honest toolchain. Verification (this box): direct frozen verifier -> verified-program-evidence, 4 proofs (receipt 46c7b357) for 6c3ae920; REFUSES 7cdafb30 (compiler-not-approved). Gate-green: 235/235 codex_plugin tests (1 skip), plugin_identity=verified, CAPABILITY_DRIFT_PASS, repin_linux --check MATCH. Deployment: source-ahead-of-deployment by design. The provisioned v1.7.3 runtime + MCP surface + hermes bundle still verify the deployed 7cdafb30 and re-provision to 6c3ae920 at the V111 repackage (which regenerates the hermes bundle identity). Not pushed. Co-Authored-By: Claude Opus 5 (1M context) --- OMARCHY_BUILD.md | 5 +++-- release/MANIFEST.linux-aarch64.sha256 | 4 ++-- release/build_package_linux.sh | 2 +- ...ubis_program_dogfood_linux_aarch64_v1.json | 22 +++++++++++-------- .../approved_check_compiler.linux-aarch64 | 2 +- tools/anubis_program_verify.py | 2 +- 6 files changed, 21 insertions(+), 16 deletions(-) diff --git a/OMARCHY_BUILD.md b/OMARCHY_BUILD.md index deed61b..656f614 100644 --- a/OMARCHY_BUILD.md +++ b/OMARCHY_BUILD.md @@ -70,11 +70,12 @@ program-evidence anchor), `cargo`/`rustc` (stable), `elan` (Lean), `python3`. ## Trust-surface sign-offs - jackal_anubis_check_program: RESOLVED 2026-08-24 — architect (khephri.labs@proton.me) designated the clean-source Linux/aarch64 anubis CHECK COMPILER sha256 - 7cdafb30… (double-built byte-identical, from anubis-lang commit 6aa6fd92, + 6c3ae920… (double-built byte-identical, from anubis-lang commit 0ad40aaf = + 6aa6fd92 + host-honest doctor; supersedes 7cdafb30 which lacked the doctor fix, recipe §1). Scope: Linux/aarch64 only; macOS 0d6a8f89 not reused; inventory-safe-v1 policy body byte-frozen (1b94350a). Verifier anchor is host-aware (Darwin=0d6a8f89 preserved). Independently re-verified 2026-08-24 - (verified-program-evidence, 4 proofs, receipt 81d6477e…). Records: + (verified-program-evidence, 4 proofs, receipt 46c7b357… (D2)). Records: release/evidence/anubis_program_dogfood_linux_aarch64_v1.json and ~/omarchy-jackal-completion/evidence/compiler/SIGNOFF_linux_aarch64.json; finding ~/omarchy-jackal-completion/evidence/I_check_compiler_finding.json diff --git a/release/MANIFEST.linux-aarch64.sha256 b/release/MANIFEST.linux-aarch64.sha256 index 0649005..f303b42 100644 --- a/release/MANIFEST.linux-aarch64.sha256 +++ b/release/MANIFEST.linux-aarch64.sha256 @@ -27,7 +27,7 @@ int-cert-premise-aba release/evidence/int_cert_premise_aba_v172.json b07c501a982 coverage-inventory release/coverage/formal_coverage_inventory.json 6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6 build-environment release/evidence/build_environment_v170.json b71fbee10dd83fab7e389d07eadd92e1bff431585f11be5b6887e789f063109d source jackal_calc.anb f579b6f59bc024d24914487b0cd0f18ea43dea1be52708a05a66dc885d80bb4e -compiler_pin anubis-c6affa8c0ae7 c6affa8c0ae7b1f9e2d3fe18ff712b3f35982a5164eef626f25e90628f4497fc +compiler_pin anubis-2704f0832f34 2704f0832f3458052c2bf6352b1b0252f541c185a528b14758c80caafe05bb79 plugin_hermes c6a27483077b89d899d8c73c03bfeb3191f25db2a22f8021254a7dec763ba5fe sqrt_rat_producer tools/sqrt_rat_producer.py 4bc95c331430d2350facfb19da9aba483ab7b3698754e7af2e5deb797e097926 exp_rat_producer tools/exp_rat_producer.py 1997ed81dfbd26a6d45a6689c515832bfbae05435d07e3dd2d6f156c57668ec1 @@ -48,4 +48,4 @@ anubis_program_policy release/program/inventory_safe_v1.json 361979bf89b7c71a4b2 claim_inference_registry release/claim/inference_registry_v1.json c70b33d5aee8071b5125e6a5f8ffe5226fc22a137d920c17d9b3463968be13f0 claim_unit_registry release/claim/unit_registry_v1.json d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c approved-z3-linux-aarch64 jackal_z3_v4154 b6fcd93b2ccec9aa848ac148c4d9b4270577ad046601f211784586eb9f0135c4 -approved-check-compiler-linux-aarch64 jackal_anubis_check_v1 7cdafb305f3b8df53e66e037433803d5154b4f5872758d9b15f7eeedc9670398 +approved-check-compiler-linux-aarch64 jackal_anubis_check_v1 6c3ae920aaaa668b3ec1857b162997c8cd1471949604e6909b898f357683479a diff --git a/release/build_package_linux.sh b/release/build_package_linux.sh index 72fbc38..49f8516 100755 --- a/release/build_package_linux.sh +++ b/release/build_package_linux.sh @@ -364,7 +364,7 @@ APPROVED_Z3_SHA256="b6fcd93b2ccec9aa848ac148c4d9b4270577ad046601f211784586eb9f01 # against the manifest-pinned identity. CCDIR="${JACKAL_CC_DIR:?set JACKAL_CC_DIR to the approved native check compiler}" require_regular "$CCDIR/jackal_anubis_check_v1" -APPROVED_CC_SHA256="7cdafb305f3b8df53e66e037433803d5154b4f5872758d9b15f7eeedc9670398" +APPROVED_CC_SHA256="6c3ae920aaaa668b3ec1857b162997c8cd1471949604e6909b898f357683479a" [ "$(sha256 "$CCDIR/jackal_anubis_check_v1")" = "$APPROVED_CC_SHA256" ] || { echo "PACKAGE_V173_REFUSED reason=approved-check-compiler-identity observed=$(sha256 "$CCDIR/jackal_anubis_check_v1")" >&2 exit 4 diff --git a/release/evidence/anubis_program_dogfood_linux_aarch64_v1.json b/release/evidence/anubis_program_dogfood_linux_aarch64_v1.json index 9163139..dfaeb49 100644 --- a/release/evidence/anubis_program_dogfood_linux_aarch64_v1.json +++ b/release/evidence/anubis_program_dogfood_linux_aarch64_v1.json @@ -11,26 +11,28 @@ }, "compiler": { "authority": "architect signed-off; clean-source Linux/aarch64 designation (2026-08-24)", - "binary_sha256": "7cdafb305f3b8df53e66e037433803d5154b4f5872758d9b15f7eeedc9670398", + "binary_sha256": "6c3ae920aaaa668b3ec1857b162997c8cd1471949604e6909b898f357683479a", "supersedes_pre_emitter_candidate_sha256": "d8c7d38b6d376ee46ecf97817852b40c122df4711a561ec1c33ffa546816abff", "clean_source": { "repo": "github.com/AnubisQuantumCipher/anubis-lang", - "local_branch": "omarchy/program-evidence-v3-emitter", - "commit": "6aa6fd92d4fea1af5cd532767890e00cf918d4af", + "local_branch": "omarchy/linux-host-ergonomics", + "commit": "0ad40aaf1f0e (6aa6fd92 v3-emitter + doctor host-honesty, tools/anubis/src/main.rs only)", "change": "Added emit_program_evidence_v3() + canonical_json() to compiler/src/evidence/mod.rs (sealed into MANIFEST.sha256); emits anubis.program-evidence.v3 assembled from the sealed bundle files; recomputes function/obligation digests with a canonical JSON byte-matching Python json.dumps(sort_keys,separators,ensure_ascii=False). Committed clean source, NOT an uncommitted worktree diff." }, "reproducible_double_build": { "recipe": "SOURCE_DATE_EPOCH=1700000000 LC_ALL=C TZ=UTC CARGO_INCREMENTAL=0 remap-path-prefix -Cdebuginfo=0 ; cargo build --release -p anubis --no-default-features --locked", - "build1_sha256": "7cdafb305f3b8df53e66e037433803d5154b4f5872758d9b15f7eeedc9670398", - "build2_sha256": "7cdafb305f3b8df53e66e037433803d5154b4f5872758d9b15f7eeedc9670398", + "build1_sha256": "6c3ae920aaaa668b3ec1857b162997c8cd1471949604e6909b898f357683479a", + "build2_sha256": "6c3ae920aaaa668b3ec1857b162997c8cd1471949604e6909b898f357683479a", "byte_identical": true - } + }, + "supersedes_prior_signed_sha256": "7cdafb305f3b8df53e66e037433803d5154b4f5872758d9b15f7eeedc9670398", + "supersession_reason": "host-honest `anubis doctor` (0ad40aaf); prior 7cdafb30 printed a false Apple-Silicon host line" }, "verifier": { "authority": "unmodified frozen contract; architecture-qualified host-aware anchor only", "tool": "tools/anubis_program_verify.py", - "sha256": "cafbd25791225856c2914e9dc86b5dcd3e23d6cc0285b09800de34922f76d52e", - "linux_aarch64_anchor_sha256": "7cdafb305f3b8df53e66e037433803d5154b4f5872758d9b15f7eeedc9670398", + "sha256": "100c51dbe5a84fb7120117d7f76cef14d8089cda7f2d5ee54baad706b5ddc4e2", + "linux_aarch64_anchor_sha256": "6c3ae920aaaa668b3ec1857b162997c8cd1471949604e6909b898f357683479a", "program_policy_sha256": "1b94350a6d23e9d76a917f05f0a53ae9e0ccf861bc6aee71342967ce1dccb090", "program_policy_file_sha256": "361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb" }, @@ -43,7 +45,9 @@ "file_count": 108, "shipped_check_compiler_sha256": "7cdafb305f3b8df53e66e037433803d5154b4f5872758d9b15f7eeedc9670398", "shipped_capability_inventory_sha256": "e7bbdce00d6a6de9d562ed39025855c00d0281e2f9a5fa148594bd04051a4678", - "double_build_cmp_exit": 0 + "double_build_cmp_exit": 0, + "approved_anchor_check_compiler_sha256": "6c3ae920aaaa668b3ec1857b162997c8cd1471949604e6909b898f357683479a", + "shipped_vs_approved_note": "APPROVED (live source-of-truth anchor) = 6c3ae920. The v1.7.3 tarball + provisioned runtime still SHIP 7cdafb30 and re-provision to 6c3ae920 at the V111 repackage (which regenerates the hermes bundle identity). Source-ahead-of-deployment by design." }, "observed": { "sample_source": "examples/showcase/verified_loop.anb", diff --git a/release/evidence/approved_check_compiler.linux-aarch64 b/release/evidence/approved_check_compiler.linux-aarch64 index eeb0bcf..5590f52 100644 --- a/release/evidence/approved_check_compiler.linux-aarch64 +++ b/release/evidence/approved_check_compiler.linux-aarch64 @@ -1 +1 @@ -/home/sicarii/.local/share/JACKAL/anubis-check/linux-aarch64/jackal_anubis_check_v1 7cdafb305f3b8df53e66e037433803d5154b4f5872758d9b15f7eeedc9670398 +/home/sicarii/.local/share/JACKAL/anubis-check/linux-aarch64/jackal_anubis_check_v1 6c3ae920aaaa668b3ec1857b162997c8cd1471949604e6909b898f357683479a diff --git a/tools/anubis_program_verify.py b/tools/anubis_program_verify.py index e117b6e..c0081d5 100755 --- a/tools/anubis_program_verify.py +++ b/tools/anubis_program_verify.py @@ -133,7 +133,7 @@ # NOT the guest's ambient bytes. The Darwin declaration above stays exact in the # FROZEN inventory-safe-v1 policy body; only the runtime selection below is host-aware. APPROVED_CHECK_COMPILER_LINUX_AARCH64_SHA256 = ( - "7cdafb305f3b8df53e66e037433803d5154b4f5872758d9b15f7eeedc9670398" + "6c3ae920aaaa668b3ec1857b162997c8cd1471949604e6909b898f357683479a" ) From 4071e28b1c80ac8c2780c21d605114e7bf5ff340 Mon Sep 17 00:00:00 2001 From: sicarii Date: Sat, 29 Aug 2026 00:12:24 -0400 Subject: [PATCH 13/22] Add Platinum SPARK interval decision kernel --- .github/workflows/gaussian-proof-gate.yml | 23 +++ assurance/README.md | 28 +++ assurance/requirements.json | 104 +++++++++++ proofs/spark/hellgate_interval/.gitignore | 2 + proofs/spark/hellgate_interval/README.md | 35 ++++ .../hellgate_interval/hellgate_interval.gpr | 12 ++ proofs/spark/hellgate_interval/prove.sh | 54 ++++++ .../src/jackal_interval_envelope.adb | 54 ++++++ .../src/jackal_interval_envelope.ads | 125 +++++++++++++ .../tests/hellgate_interval_demo.adb | 73 ++++++++ tests/assurance_traceability_test.py | 35 ++++ tests/codex_plugin/test_spark_interval.py | 51 ++++++ tools/check_assurance_traceability.py | 172 ++++++++++++++++++ 13 files changed, 768 insertions(+) create mode 100644 assurance/README.md create mode 100644 assurance/requirements.json create mode 100644 proofs/spark/hellgate_interval/.gitignore create mode 100644 proofs/spark/hellgate_interval/README.md create mode 100644 proofs/spark/hellgate_interval/hellgate_interval.gpr create mode 100755 proofs/spark/hellgate_interval/prove.sh create mode 100644 proofs/spark/hellgate_interval/src/jackal_interval_envelope.adb create mode 100644 proofs/spark/hellgate_interval/src/jackal_interval_envelope.ads create mode 100644 proofs/spark/hellgate_interval/tests/hellgate_interval_demo.adb create mode 100644 tests/assurance_traceability_test.py create mode 100644 tests/codex_plugin/test_spark_interval.py create mode 100755 tools/check_assurance_traceability.py diff --git a/.github/workflows/gaussian-proof-gate.yml b/.github/workflows/gaussian-proof-gate.yml index 24d1cc6..7e4b5c5 100644 --- a/.github/workflows/gaussian-proof-gate.yml +++ b/.github/workflows/gaussian-proof-gate.yml @@ -9,6 +9,29 @@ permissions: contents: read jobs: + spark-platinum-interval: + name: SPARK Platinum interval decision kernel + runs-on: ubuntu-24.04 + timeout-minutes: 30 + steps: + - name: Check out exact revision + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + + - name: Install GNAT, GPRbuild, and GNATprove + uses: alire-project/alr-install@b99b8c21417c79c307905439def2718bc393b94a # v2.0.1 + with: + crates: gnat_native=16.1.0 gprbuild=26.0.1 gnatprove=16.1.0 + + - name: Enforce bidirectional requirements and whole-surface closure + run: | + python3 -B tools/check_assurance_traceability.py + python3 -B -m unittest tests.assurance_traceability_test -v + + - name: Prove the total interval decision kernel + run: | + proofs/spark/hellgate_interval/prove.sh + python3 -B -m unittest tests.codex_plugin.test_spark_interval -v + lean-proof-and-axioms: name: Gaussian/range source closures and axiom audits runs-on: ubuntu-24.04 diff --git a/assurance/README.md b/assurance/README.md new file mode 100644 index 0000000..290f1cb --- /dev/null +++ b/assurance/README.md @@ -0,0 +1,28 @@ +# JACKAL functional-proof baseline + +`requirements.json` is the machine-readable source for allocated functional +requirements, component claims, and whole-surface closure status. + +The current universally quantified proof applies to the total SPARK interval +decision kernel and its complete declared input types. The whole JACKAL product +target is in progress. The closure matrix deliberately exposes every sealed +runtime dependency family and every additive Codex tool group; it cannot become +a whole-product claim until all discovered entries are `proved-universal` and +all requirements are proved. + +Run: + +```sh +python3 -B tools/check_assurance_traceability.py +proofs/spark/hellgate_interval/prove.sh +``` + +The traceability gate rejects duplicate JSON keys, missing or one-way links, +unknown public surface families, and premature whole-product claims. The proof +gate rejects missing tools, warnings, unproved or justified checks, a skipped +interval unit, and proof assumptions or annotations. + +SPARK Platinum is used only for SPARK components whose contracts fully cover +their allocated functional requirements. Lean mathematical soundness, Anubis +program evidence, independent checker replay, and empirical tests are recorded +as different evidence forms rather than relabeled as SPARK Platinum. diff --git a/assurance/requirements.json b/assurance/requirements.json new file mode 100644 index 0000000..b1eacd2 --- /dev/null +++ b/assurance/requirements.json @@ -0,0 +1,104 @@ +{ + "schema": "jackal-assurance-requirements-v1", + "system": "JACKAL deterministic mathematical evidence kernel", + "target": "Requirements-complete universal functional correctness within every declared input domain", + "product_claim": { + "status": "in-progress", + "reason": "The public surface still contains tested runtime, parser, adapter, orchestration, numerical-model, operating-system, compiler, and hardware boundaries that do not yet have universal refinement proofs." + }, + "component_claims": [ + { + "component": "proofs/spark/hellgate_interval/src/jackal_interval_envelope", + "target": "SPARK Platinum", + "status": "proved-local", + "requirement_ids": [ + "JCK-INT-001", + "JCK-INT-002", + "JCK-INT-003", + "JCK-INT-004" + ], + "boundary": "Total fixed-scale nonnegative interval decision kernel; certificate parsing, rational-to-fixed-scale conversion, nonlinear analysis, compiler, runtime, operating system, and hardware are outside this component." + } + ], + "requirements": [ + { + "id": "JCK-INT-001", + "shall": "The SPARK interval kernel shall return the exact upper-minus-lower width for every ordered fixed-scale interval and shall be free of run-time errors over its declared precondition.", + "method": "spark-platinum", + "status": "proved", + "allocation": [ + "proofs/spark/hellgate_interval/src/jackal_interval_envelope.ads" + ], + "verification": [ + "proofs/spark/hellgate_interval/prove.sh", + "tests/codex_plugin/test_spark_interval.py" + ], + "residuals": [] + }, + { + "id": "JCK-INT-002", + "shall": "The SPARK interval kernel shall return midpoint and ceiling-radius values that cover both endpoints of every ordered fixed-scale interval without overflow or range failure.", + "method": "spark-platinum", + "status": "proved", + "allocation": [ + "proofs/spark/hellgate_interval/src/jackal_interval_envelope.ads" + ], + "verification": [ + "proofs/spark/hellgate_interval/prove.sh", + "tests/codex_plugin/test_spark_interval.py" + ], + "residuals": [] + }, + { + "id": "JCK-INT-003", + "shall": "The SPARK interval kernel shall admit an envelope exactly when it is ordered, its target width is positive, and its exact width is strictly less than the target.", + "method": "spark-platinum", + "status": "proved", + "allocation": [ + "proofs/spark/hellgate_interval/src/jackal_interval_envelope.ads" + ], + "verification": [ + "proofs/spark/hellgate_interval/prove.sh", + "tests/codex_plugin/test_spark_interval.py" + ], + "residuals": [] + }, + { + "id": "JCK-INT-004", + "shall": "The SPARK interval kernel shall evaluate every value of its public input types with the specified rejection precedence, zero all rejected derived outputs, and return exact width plus a covering midpoint-radius pair on admission.", + "method": "spark-platinum", + "status": "proved", + "allocation": [ + "proofs/spark/hellgate_interval/src/jackal_interval_envelope.ads", + "proofs/spark/hellgate_interval/src/jackal_interval_envelope.adb" + ], + "verification": [ + "proofs/spark/hellgate_interval/prove.sh", + "tests/codex_plugin/test_spark_interval.py" + ], + "residuals": [] + } + ], + "surface_closure": { + "sealed_dependency_families": { + "lean-range": "formal-mathematics-open-refinement", + "lean-gaussian": "formal-mathematics-open-refinement", + "lean-int-cert": "formal-mathematics-open-refinement", + "lean-receipt-registry": "formal-mathematics-open-refinement", + "runtime-only": "tested-open-proof", + "exact-cert-verifier": "independently-checked-open-proof", + "claim-router": "tested-open-proof", + "claim-verifier": "independently-checked-open-proof", + "structural-checker": "independently-checked-open-proof", + "decision-checker": "independently-checked-open-proof", + "program-verifier": "anubis-evidence-open-refinement" + }, + "additive_groups": { + "measurement": "tested-open-proof", + "advanced": "tested-open-proof", + "stem": "tested-open-proof" + }, + "closed_status": "proved-universal", + "rule": "A whole-product claim is permitted only when every discovered sealed dependency family and additive group has closed_status and every allocated requirement is proved." + } +} diff --git a/proofs/spark/hellgate_interval/.gitignore b/proofs/spark/hellgate_interval/.gitignore new file mode 100644 index 0000000..4ded7c4 --- /dev/null +++ b/proofs/spark/hellgate_interval/.gitignore @@ -0,0 +1,2 @@ +/bin/ +/obj/ diff --git a/proofs/spark/hellgate_interval/README.md b/proofs/spark/hellgate_interval/README.md new file mode 100644 index 0000000..548a363 --- /dev/null +++ b/proofs/spark/hellgate_interval/README.md @@ -0,0 +1,35 @@ +# SPARK fixed-scale HELLGATE interval envelope + +This repository-side component independently specifies and proves a narrow +integer interval decision boundary used to sanity-check the admitted HELLGATE +energy envelope. Because the energy is negative, the demo represents its +absolute magnitudes on a fixed `10^18` scale. + +The requirements-complete component claim covers `JCK-INT-001` through +`JCK-INT-004`. Its total decision function is quantified over every value of +the public fixed-scale input types. GNATprove establishes deterministic +rejection precedence, exact ordered width, midpoint/ceiling-radius endpoint +coverage, strict admission equivalence, zeroed rejection outputs, termination, +and absence of targeted run-time errors. + +The target conversion was routed through JACKAL exact arithmetic: +`status=exact`, `parsed=2/10^12*10^18`, `exact=2000000`. That exact result is +outside the Lean certificate chain and is not `formal-bounded`. + +Run: + +```sh +./prove.sh +``` + +The proof gate runs at level 3 with proof warnings treated as errors and refuses +unproved checks, justified checks, `pragma Assume`, `pragma Annotate`, or a +report that skipped the expected package. The requirement and whole-surface +closure source is `assurance/requirements.json`. + +The proof boundary is deliberately limited. This component does not prove the +nonlinear Barta theorem, the density strong-convexity theorem, certificate +parsing, the Python checker's rational integration, Python-to-SPARK refinement, +source-to-object equivalence, compiler or run-time correctness, or any +mission/safety claim. It is not DO-178C, ECSS, NASA, or launch-provider +qualification evidence. diff --git a/proofs/spark/hellgate_interval/hellgate_interval.gpr b/proofs/spark/hellgate_interval/hellgate_interval.gpr new file mode 100644 index 0000000..68a522d --- /dev/null +++ b/proofs/spark/hellgate_interval/hellgate_interval.gpr @@ -0,0 +1,12 @@ +project Hellgate_Interval is + for Languages use ("Ada"); + for Source_Dirs use ("src", "tests"); + for Object_Dir use "obj"; + for Exec_Dir use "bin"; + for Main use ("hellgate_interval_demo.adb"); + + package Compiler is + for Default_Switches ("Ada") use + ("-gnat2012", "-gnata", "-gnatVa", "-gnatwa", "-gnatwe"); + end Compiler; +end Hellgate_Interval; diff --git a/proofs/spark/hellgate_interval/prove.sh b/proofs/spark/hellgate_interval/prove.sh new file mode 100755 index 0000000..d948839 --- /dev/null +++ b/proofs/spark/hellgate_interval/prove.sh @@ -0,0 +1,54 @@ +#!/bin/sh +set -eu + +# Proof obligations: JCK-INT-001, JCK-INT-002, JCK-INT-003, JCK-INT-004. + +SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd -P) +PROJECT="$SCRIPT_DIR/hellgate_interval.gpr" + +if ! command -v gnatprove >/dev/null 2>&1 || ! command -v gprbuild >/dev/null 2>&1; then + if [ -f "$HOME/opt/gnat/env.sh" ]; then + # shellcheck disable=SC1091 + . "$HOME/opt/gnat/env.sh" + fi +fi + +command -v gprbuild >/dev/null 2>&1 || { + echo "refused: gprbuild is unavailable" >&2 + exit 1 +} +command -v gnatprove >/dev/null 2>&1 || { + echo "refused: gnatprove is unavailable" >&2 + exit 1 +} + +gprbuild -p -q -P "$PROJECT" +"$SCRIPT_DIR/bin/hellgate_interval_demo" +gnatprove -P "$PROJECT" -U --level=3 --report=all --warnings=error \ + --proof-warnings=on --assumptions -j0 + +PROOF_REPORT="$SCRIPT_DIR/obj/gnatprove/gnatprove.out" +if [ ! -f "$PROOF_REPORT" ]; then + echo "refused: GNATprove summary is missing" >&2 + exit 1 +fi + +NORMALIZED_TOTAL=$(grep '^Total' "$PROOF_REPORT" | sed 's/([0-9]*%)//g' | tr -s ' ') +set -- $NORMALIZED_TOTAL +if [ "$#" -ne 6 ] || [ "$5" != "." ] || [ "$6" != "." ]; then + echo "refused: GNATprove reports justified or unproved checks" >&2 + exit 1 +fi + +grep -q 'unit jackal_interval_envelope' "$PROOF_REPORT" || { + echo "refused: the interval decision unit was not analyzed" >&2 + exit 1 +} + +if rg -n --glob '*.ad?' 'pragma[[:space:]]+(Assume|Annotate)' \ + "$SCRIPT_DIR/src" "$SCRIPT_DIR/tests"; then + echo "refused: proof assumptions or justifications are forbidden" >&2 + exit 1 +fi + +echo "SPARK_PLATINUM_INTERVAL_COMPONENT_PROOF_PASS" diff --git a/proofs/spark/hellgate_interval/src/jackal_interval_envelope.adb b/proofs/spark/hellgate_interval/src/jackal_interval_envelope.adb new file mode 100644 index 0000000..32cc0a2 --- /dev/null +++ b/proofs/spark/hellgate_interval/src/jackal_interval_envelope.adb @@ -0,0 +1,54 @@ +package body Jackal_Interval_Envelope + with SPARK_Mode +is + + function Width (Item : Closed_Interval) return Magnitude is + (Item.Upper - Item.Lower); + + function Midpoint (Item : Closed_Interval) return Magnitude is + (Item.Lower + Width (Item) / 2); + + function Radius_Ceiling (Item : Closed_Interval) return Magnitude is + (Width (Item) - Width (Item) / 2); + + function Strictly_Meets_Target + (Item : Closed_Interval; + Target_Width : Magnitude) return Boolean is + (Width (Item) < Target_Width); + + function Evaluate_Untrusted_Envelope + (Item : Closed_Interval; + Target_Width : Magnitude) return Envelope_Decision + is + Empty : constant Envelope_Decision := + (Verdict => Reject_Unordered, + Width => 0, + Center => 0, + Radius => 0); + begin + -- JCK-INT-004. The branch order is part of Required_Verdict and makes + -- subtraction unreachable until ordering has been established. + if not Is_Ordered (Item) then + return Empty; + elsif Target_Width = 0 then + return + (Verdict => Reject_Nonpositive_Target, + Width => 0, + Center => 0, + Radius => 0); + elsif Width (Item) >= Target_Width then + return + (Verdict => Reject_Not_Strictly_Narrower, + Width => 0, + Center => 0, + Radius => 0); + else + return + (Verdict => Admit, + Width => Width (Item), + Center => Midpoint (Item), + Radius => Radius_Ceiling (Item)); + end if; + end Evaluate_Untrusted_Envelope; + +end Jackal_Interval_Envelope; diff --git a/proofs/spark/hellgate_interval/src/jackal_interval_envelope.ads b/proofs/spark/hellgate_interval/src/jackal_interval_envelope.ads new file mode 100644 index 0000000..2e21b50 --- /dev/null +++ b/proofs/spark/hellgate_interval/src/jackal_interval_envelope.ads @@ -0,0 +1,125 @@ +package Jackal_Interval_Envelope + with SPARK_Mode +is + Max_Magnitude : constant Long_Long_Integer := + 8_000_000_000_000_000_000; + + subtype Magnitude is Long_Long_Integer + range 0 .. Max_Magnitude; + + type Closed_Interval is record + Lower : Magnitude; + Upper : Magnitude; + end record; + + function Is_Ordered (Item : Closed_Interval) return Boolean is + (Item.Lower <= Item.Upper); + + -- JCK-INT-001: exact width over every ordered fixed-scale interval. + function Width (Item : Closed_Interval) return Magnitude + with + Pre => Is_Ordered (Item), + Post => Width'Result = Item.Upper - Item.Lower; + + -- JCK-INT-002: the midpoint/radius pair covers both interval endpoints. + function Midpoint (Item : Closed_Interval) return Magnitude + with + Pre => Is_Ordered (Item), + Post => + Midpoint'Result = + Item.Lower + (Item.Upper - Item.Lower) / 2 + and then Midpoint'Result in Item.Lower .. Item.Upper; + + function Radius_Ceiling (Item : Closed_Interval) return Magnitude + with + Pre => Is_Ordered (Item), + Post => + Radius_Ceiling'Result = + (Item.Upper - Item.Lower) + - (Item.Upper - Item.Lower) / 2; + + function Contains + (Item : Closed_Interval; + Value : Magnitude) return Boolean is + (Item.Lower <= Value and then Value <= Item.Upper); + + function Covers + (Item : Closed_Interval; + Center : Magnitude; + Radius : Magnitude) return Boolean is + (Is_Ordered (Item) + and then Contains (Item, Center) + and then Center - Item.Lower <= Radius + and then Item.Upper - Center <= Radius); + + -- JCK-INT-003: strict admission is equivalent to the allocated width + -- predicate for every input satisfying the public precondition. + function Strictly_Meets_Target + (Item : Closed_Interval; + Target_Width : Magnitude) return Boolean + with + Pre => Is_Ordered (Item) and then Target_Width > 0, + Post => + Strictly_Meets_Target'Result = + (Item.Upper - Item.Lower < Target_Width); + + function Admits_Untrusted_Envelope + (Item : Closed_Interval; + Target_Width : Magnitude) return Boolean is + (Is_Ordered (Item) + and then Target_Width > 0 + and then Item.Upper - Item.Lower < Target_Width); + + type Decision_Verdict is + (Reject_Unordered, + Reject_Nonpositive_Target, + Reject_Not_Strictly_Narrower, + Admit); + + type Envelope_Decision is record + Verdict : Decision_Verdict; + Width : Magnitude; + Center : Magnitude; + Radius : Magnitude; + end record; + + function Required_Verdict + (Item : Closed_Interval; + Target_Width : Magnitude) return Decision_Verdict is + (if not Is_Ordered (Item) then Reject_Unordered + elsif Target_Width = 0 then Reject_Nonpositive_Target + elsif Item.Upper - Item.Lower >= Target_Width then + Reject_Not_Strictly_Narrower + else Admit); + + -- JCK-INT-004: total, deterministic evaluation over the complete public + -- input type. Rejections zero every derived output; acceptance returns + -- the exact width and a covering midpoint/radius pair. + function Evaluate_Untrusted_Envelope + (Item : Closed_Interval; + Target_Width : Magnitude) return Envelope_Decision + with + Post => + Evaluate_Untrusted_Envelope'Result.Verdict = + Required_Verdict (Item, Target_Width) + and then + ((Evaluate_Untrusted_Envelope'Result.Verdict = Admit) = + Admits_Untrusted_Envelope (Item, Target_Width)) + and then + (if Evaluate_Untrusted_Envelope'Result.Verdict = Admit then + Evaluate_Untrusted_Envelope'Result.Width = + Item.Upper - Item.Lower + and then Evaluate_Untrusted_Envelope'Result.Center = + Item.Lower + (Item.Upper - Item.Lower) / 2 + and then Evaluate_Untrusted_Envelope'Result.Radius = + (Item.Upper - Item.Lower) + - (Item.Upper - Item.Lower) / 2 + and then Covers + (Item, + Evaluate_Untrusted_Envelope'Result.Center, + Evaluate_Untrusted_Envelope'Result.Radius) + else Evaluate_Untrusted_Envelope'Result.Width = 0 + and then Evaluate_Untrusted_Envelope'Result.Center = 0 + and then Evaluate_Untrusted_Envelope'Result.Radius = 0); + +end Jackal_Interval_Envelope; diff --git a/proofs/spark/hellgate_interval/tests/hellgate_interval_demo.adb b/proofs/spark/hellgate_interval/tests/hellgate_interval_demo.adb new file mode 100644 index 0000000..45975e3 --- /dev/null +++ b/proofs/spark/hellgate_interval/tests/hellgate_interval_demo.adb @@ -0,0 +1,73 @@ +with Ada.Text_IO; +with Jackal_Interval_Envelope; + +procedure Hellgate_Interval_Demo + with SPARK_Mode +is + package Envelope renames Jackal_Interval_Envelope; + use type Envelope.Decision_Verdict; + + -- The checked energy interval is negative. This independent fixed-scale + -- boundary represents its absolute magnitudes, ordered from smaller to + -- larger, at a scale of 10^18. + Hellgate_Magnitude : constant Envelope.Closed_Interval := + (Lower => 4_615_978_698_574_496_507, + Upper => 4_615_978_698_574_496_508); + + -- 2*10^(-12) at scale 10^18. JACKAL exact replay: + -- parsed=2/10^12*10^18; exact=2000000; status=exact (not formal). + Required_Strict_Width : constant Envelope.Magnitude := 2_000_000; + + Reversed_Magnitude : constant Envelope.Closed_Interval := + (Lower => Hellgate_Magnitude.Upper, + Upper => Hellgate_Magnitude.Lower); + Boundary_Width : constant Envelope.Closed_Interval := + (Lower => 0, + Upper => Required_Strict_Width); + + Center : constant Envelope.Magnitude := + Envelope.Midpoint (Hellgate_Magnitude); + Radius : constant Envelope.Magnitude := + Envelope.Radius_Ceiling (Hellgate_Magnitude); + Decision : constant Envelope.Envelope_Decision := + Envelope.Evaluate_Untrusted_Envelope + (Hellgate_Magnitude, Required_Strict_Width); +begin + -- JCK-INT-001, JCK-INT-002, JCK-INT-003, JCK-INT-004. + pragma Assert (Envelope.Is_Ordered (Hellgate_Magnitude)); + pragma Assert (Envelope.Contains (Hellgate_Magnitude, Center)); + pragma Assert (Center - Hellgate_Magnitude.Lower <= Radius); + pragma Assert (Hellgate_Magnitude.Upper - Center <= Radius); + pragma Assert + (Envelope.Strictly_Meets_Target + (Hellgate_Magnitude, Required_Strict_Width)); + pragma Assert + (Envelope.Admits_Untrusted_Envelope + (Hellgate_Magnitude, Required_Strict_Width)); + pragma Assert + (not Envelope.Admits_Untrusted_Envelope + (Reversed_Magnitude, Required_Strict_Width)); + pragma Assert + (not Envelope.Admits_Untrusted_Envelope + (Hellgate_Magnitude, 0)); + pragma Assert + (not Envelope.Admits_Untrusted_Envelope + (Boundary_Width, Required_Strict_Width)); + pragma Assert (Decision.Verdict = Envelope.Admit); + pragma Assert (Decision.Center = Center); + pragma Assert (Decision.Radius = Radius); + pragma Assert + (Envelope.Evaluate_Untrusted_Envelope + (Reversed_Magnitude, Required_Strict_Width).Verdict = + Envelope.Reject_Unordered); + pragma Assert + (Envelope.Evaluate_Untrusted_Envelope + (Hellgate_Magnitude, 0).Verdict = + Envelope.Reject_Nonpositive_Target); + pragma Assert + (Envelope.Evaluate_Untrusted_Envelope + (Boundary_Width, Required_Strict_Width).Verdict = + Envelope.Reject_Not_Strictly_Narrower); + + Ada.Text_IO.Put_Line ("HELLGATE fixed-scale interval envelope: ACCEPT"); +end Hellgate_Interval_Demo; diff --git a/tests/assurance_traceability_test.py b/tests/assurance_traceability_test.py new file mode 100644 index 0000000..a04f8a5 --- /dev/null +++ b/tests/assurance_traceability_test.py @@ -0,0 +1,35 @@ +import json +import subprocess +import unittest +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] +BASELINE = ROOT / "assurance/requirements.json" + + +class AssuranceTraceabilityTests(unittest.TestCase): + """JCK-INT-001 through JCK-INT-004 and whole-surface closure regression.""" + + def test_traceability_and_surface_closure_gate(self) -> None: + completed = subprocess.run( + ["python3", "-B", "tools/check_assurance_traceability.py"], + cwd=ROOT, + capture_output=True, + text=True, + check=False, + ) + self.assertEqual(completed.returncode, 0, completed.stdout + completed.stderr) + self.assertIn("JACKAL_ASSURANCE_TRACEABILITY_PASS", completed.stdout) + + def test_whole_product_claim_stays_open_with_unproved_surfaces(self) -> None: + document = json.loads(BASELINE.read_text(encoding="utf-8")) + self.assertEqual(document["product_claim"]["status"], "in-progress") + closure = document["surface_closure"] + statuses = list(closure["sealed_dependency_families"].values()) + statuses.extend(closure["additive_groups"].values()) + self.assertTrue(any(status != closure["closed_status"] for status in statuses)) + + +if __name__ == "__main__": + unittest.main(verbosity=2) diff --git a/tests/codex_plugin/test_spark_interval.py b/tests/codex_plugin/test_spark_interval.py new file mode 100644 index 0000000..d10dae5 --- /dev/null +++ b/tests/codex_plugin/test_spark_interval.py @@ -0,0 +1,51 @@ +import shutil +import subprocess +import unittest +from pathlib import Path + + +REPO_ROOT = Path(__file__).resolve().parents[2] +SPARK_ROOT = REPO_ROOT / "proofs/spark/hellgate_interval" + + +class SparkIntervalEnvelopeTests(unittest.TestCase): + """Proof regression for JCK-INT-001, JCK-INT-002, JCK-INT-003, JCK-INT-004.""" + + def test_source_keeps_the_declared_formal_boundary(self): + sources = [ + SPARK_ROOT / "src/jackal_interval_envelope.ads", + SPARK_ROOT / "src/jackal_interval_envelope.adb", + SPARK_ROOT / "tests/hellgate_interval_demo.adb", + ] + text = "\n".join(path.read_text(encoding="utf-8") for path in sources) + self.assertIn("SPARK_Mode", text) + self.assertIn("function Admits_Untrusted_Envelope", text) + self.assertIn("function Strictly_Meets_Target", text) + self.assertIn("function Evaluate_Untrusted_Envelope", text) + self.assertIn("Required_Verdict", text) + self.assertIn("Post =>", text) + self.assertNotIn("pragma Assume", text) + self.assertNotIn("pragma Annotate", text) + + @unittest.skipUnless( + shutil.which("gprbuild") and shutil.which("gnatprove") and shutil.which("rg"), + "GNATprove toolchain is not installed", + ) + def test_build_runtime_boundary_and_gnatprove_gate(self): + completed = subprocess.run( + [str(SPARK_ROOT / "prove.sh")], + cwd=REPO_ROOT, + check=False, + capture_output=True, + text=True, + timeout=60, + ) + transcript = completed.stdout + completed.stderr + self.assertEqual(completed.returncode, 0, transcript) + self.assertIn("HELLGATE fixed-scale interval envelope: ACCEPT", transcript) + self.assertIn("Success: all checks proved", transcript) + self.assertIn("SPARK_PLATINUM_INTERVAL_COMPONENT_PROOF_PASS", transcript) + + +if __name__ == "__main__": + unittest.main() diff --git a/tools/check_assurance_traceability.py b/tools/check_assurance_traceability.py new file mode 100755 index 0000000..90d6f1e --- /dev/null +++ b/tools/check_assurance_traceability.py @@ -0,0 +1,172 @@ +#!/usr/bin/python3 -B +"""Fail closed on JACKAL requirement, claim, or public-surface drift.""" + +from __future__ import annotations + +import ast +import json +import re +from pathlib import Path +from typing import Any + + +ROOT = Path(__file__).resolve().parents[1] +BASELINE = ROOT / "assurance/requirements.json" +INVENTORY = ROOT / "release/capability_inventory_v1.json" +CODEX_SERVER = ROOT / "plugins/jackel/mcp/server.py" +ID_PATTERN = re.compile(r"^JCK-[A-Z]+-[0-9]{3}$") +GROUP_CONSTANTS = { + "measurement": "MEASUREMENT_TOOL_NAMES", + "advanced": "ADVANCED_TOOL_NAMES", + "stem": "STEM_TOOL_NAMES", +} + + +def require(condition: bool, message: str) -> None: + if not condition: + raise SystemExit(f"FAIL: {message}") + + +def reject_duplicate_keys(pairs: list[tuple[str, Any]]) -> dict[str, Any]: + result: dict[str, Any] = {} + for key, value in pairs: + require(key not in result, f"duplicate JSON key: {key}") + result[key] = value + return result + + +def read_json(path: Path) -> dict[str, Any]: + value = json.loads( + path.read_text(encoding="utf-8"), + object_pairs_hook=reject_duplicate_keys, + ) + require(isinstance(value, dict), f"top level is not an object: {path}") + return value + + +def additive_groups() -> dict[str, set[str]]: + tree = ast.parse(CODEX_SERVER.read_text(encoding="utf-8"), filename=str(CODEX_SERVER)) + wanted = set(GROUP_CONSTANTS.values()) + found: dict[str, set[str]] = {} + for node in tree.body: + if not isinstance(node, (ast.Assign, ast.AnnAssign)): + continue + targets = node.targets if isinstance(node, ast.Assign) else [node.target] + for target in targets: + if not isinstance(target, ast.Name) or target.id not in wanted: + continue + call = node.value + require( + isinstance(call, ast.Call) + and isinstance(call.func, ast.Name) + and call.func.id == "frozenset" + and len(call.args) == 1 + and isinstance(call.args[0], ast.Set), + f"{target.id} is not a literal frozenset", + ) + values = { + item.value + for item in call.args[0].elts + if isinstance(item, ast.Constant) and isinstance(item.value, str) + } + require( + len(values) == len(call.args[0].elts), + f"{target.id} contains a non-string or duplicate", + ) + found[target.id] = values + require(set(found) == wanted, "one or more additive public tool groups are missing") + return {group: found[constant] for group, constant in GROUP_CONSTANTS.items()} + + +document = read_json(BASELINE) +require(document.get("schema") == "jackal-assurance-requirements-v1", "schema mismatch") +requirements = document.get("requirements") +require(isinstance(requirements, list) and requirements, "requirements list is empty") +by_id: dict[str, dict[str, Any]] = {} + +for requirement in requirements: + require(isinstance(requirement, dict), "requirement is not an object") + identifier = requirement.get("id") + require( + isinstance(identifier, str) and ID_PATTERN.fullmatch(identifier) is not None, + f"invalid requirement id: {identifier!r}", + ) + require(identifier not in by_id, f"duplicate requirement id: {identifier}") + by_id[identifier] = requirement + shall = requirement.get("shall") + require( + isinstance(shall, str) and " shall " in f" {shall.lower()} ", + f"requirement is not a shall-statement: {identifier}", + ) + require(requirement.get("status") in {"proved", "tested", "planned"}, + f"invalid requirement status: {identifier}") + residuals = requirement.get("residuals") + require(isinstance(residuals, list), f"invalid residuals: {identifier}") + for relation in ("allocation", "verification"): + paths = requirement.get(relation) + require(isinstance(paths, list) and paths, f"{identifier} lacks {relation}") + for raw_path in paths: + require(isinstance(raw_path, str) and raw_path, f"invalid path in {identifier}") + relative = Path(raw_path) + require(not relative.is_absolute() and ".." not in relative.parts, + f"path escapes repository: {raw_path}") + path = (ROOT / relative).resolve() + require(path.is_relative_to(ROOT), f"resolved path escapes repository: {raw_path}") + require(path.is_file() and not path.is_symlink(), f"not a regular file: {raw_path}") + require(identifier in path.read_text(encoding="utf-8"), + f"{identifier} is not cited by {raw_path}") + +for claim in document.get("component_claims", []): + require(claim.get("target") == "SPARK Platinum", "component target is not SPARK Platinum") + identifiers = claim.get("requirement_ids") + require(isinstance(identifiers, list) and identifiers, "component claim has no requirements") + for identifier in identifiers: + require(identifier in by_id, f"component claim cites unknown requirement: {identifier}") + requirement = by_id[identifier] + require(requirement.get("method") == "spark-platinum", + f"component includes non-SPARK requirement: {identifier}") + if claim.get("status") == "proved-local": + require(requirement.get("status") == "proved", + f"proved component includes open requirement: {identifier}") + require(requirement.get("residuals") == [], + f"proved component requirement has functional residual: {identifier}") + +inventory = read_json(INVENTORY) +tools = inventory.get("tools") +require(isinstance(tools, list) and tools, "capability inventory has no tools") +tool_names = [tool.get("name") for tool in tools if isinstance(tool, dict)] +require(len(tool_names) == len(tools) and len(tool_names) == len(set(tool_names)), + "sealed tool names are invalid or duplicated") +discovered_families = { + tool.get("dependency", {}).get("family") + for tool in tools + if isinstance(tool, dict) and isinstance(tool.get("dependency"), dict) +} +require(None not in discovered_families, "a sealed tool lacks a dependency family") + +closure = document.get("surface_closure") +require(isinstance(closure, dict), "surface closure is absent") +sealed = closure.get("sealed_dependency_families") +additive = closure.get("additive_groups") +require(isinstance(sealed, dict), "sealed family closure is invalid") +require(isinstance(additive, dict), "additive group closure is invalid") +require(set(sealed) == discovered_families, + f"sealed assurance coverage drift: expected={sorted(discovered_families)} actual={sorted(sealed)}") +groups = additive_groups() +require(set(additive) == set(groups), "additive assurance group coverage drift") +require(all(groups.values()), "an additive public tool group is empty") +require(not (set(tool_names) & set().union(*groups.values())), + "sealed and additive public tool names overlap") + +closed_status = closure.get("closed_status") +all_closed = all(status == closed_status for status in [*sealed.values(), *additive.values()]) +all_requirements_proved = all(item.get("status") == "proved" for item in requirements) +product_status = document.get("product_claim", {}).get("status") +if product_status == "proved-universal": + require(all_closed and all_requirements_proved, + "whole-product universal claim has open surface or requirements") +else: + require(product_status == "in-progress", "invalid whole-product claim status") + require(not all_closed, "all surfaces are closed but product claim was not reviewed") + +print("JACKAL_ASSURANCE_TRACEABILITY_PASS") From cc3c99866e4a3d4131ddff2245bc0a6b99362243 Mon Sep 17 00:00:00 2001 From: sicarii Date: Sat, 29 Aug 2026 00:21:20 -0400 Subject: [PATCH 14/22] Prove the claim assurance policy algebra --- .github/workflows/gaussian-proof-gate.yml | 9 +- assurance/README.md | 15 +- assurance/requirements.json | 53 ++++ proofs/spark/claim_policy/.gitignore | 2 + proofs/spark/claim_policy/README.md | 24 ++ .../claim_policy/jackal_claim_policy.gpr | 12 + proofs/spark/claim_policy/prove.sh | 53 ++++ .../claim_policy/src/jackal_claim_policy.adb | 49 ++++ .../claim_policy/src/jackal_claim_policy.ads | 181 +++++++++++++ .../tests/jackal_claim_policy_vectors.adb | 98 +++++++ tests/assurance_traceability_test.py | 2 +- tests/claim_policy_conformance_test.py | 254 ++++++++++++++++++ 12 files changed, 744 insertions(+), 8 deletions(-) create mode 100644 proofs/spark/claim_policy/.gitignore create mode 100644 proofs/spark/claim_policy/README.md create mode 100644 proofs/spark/claim_policy/jackal_claim_policy.gpr create mode 100755 proofs/spark/claim_policy/prove.sh create mode 100644 proofs/spark/claim_policy/src/jackal_claim_policy.adb create mode 100644 proofs/spark/claim_policy/src/jackal_claim_policy.ads create mode 100644 proofs/spark/claim_policy/tests/jackal_claim_policy_vectors.adb create mode 100644 tests/claim_policy_conformance_test.py diff --git a/.github/workflows/gaussian-proof-gate.yml b/.github/workflows/gaussian-proof-gate.yml index 7e4b5c5..a52b101 100644 --- a/.github/workflows/gaussian-proof-gate.yml +++ b/.github/workflows/gaussian-proof-gate.yml @@ -9,8 +9,8 @@ permissions: contents: read jobs: - spark-platinum-interval: - name: SPARK Platinum interval decision kernel + spark-platinum-components: + name: SPARK Platinum functional kernels runs-on: ubuntu-24.04 timeout-minutes: 30 steps: @@ -32,6 +32,11 @@ jobs: proofs/spark/hellgate_interval/prove.sh python3 -B -m unittest tests.codex_plugin.test_spark_interval -v + - name: Prove and exhaustively refine the claim policy kernel + run: | + proofs/spark/claim_policy/prove.sh + python3 -B -m unittest tests.claim_policy_conformance_test -v + lean-proof-and-axioms: name: Gaussian/range source closures and axiom audits runs-on: ubuntu-24.04 diff --git a/assurance/README.md b/assurance/README.md index 290f1cb..c6e47ef 100644 --- a/assurance/README.md +++ b/assurance/README.md @@ -3,9 +3,12 @@ `requirements.json` is the machine-readable source for allocated functional requirements, component claims, and whole-surface closure status. -The current universally quantified proof applies to the total SPARK interval -decision kernel and its complete declared input types. The whole JACKAL product -target is in progress. The closure matrix deliberately exposes every sealed +The current universally quantified proofs apply to the total SPARK interval +decision kernel and to the finite claim-assurance policy kernel over their +complete declared input types. The claim-policy bridge also exhaustively checks +the current producer and independent verifier registries against the proved +SPARK truth table. The whole JACKAL product target is in progress. The closure +matrix deliberately exposes every sealed runtime dependency family and every additive Codex tool group; it cannot become a whole-product claim until all discovered entries are `proved-universal` and all requirements are proved. @@ -15,12 +18,14 @@ Run: ```sh python3 -B tools/check_assurance_traceability.py proofs/spark/hellgate_interval/prove.sh +proofs/spark/claim_policy/prove.sh +python3 -B -m unittest tests.claim_policy_conformance_test -v ``` The traceability gate rejects duplicate JSON keys, missing or one-way links, unknown public surface families, and premature whole-product claims. The proof -gate rejects missing tools, warnings, unproved or justified checks, a skipped -interval unit, and proof assumptions or annotations. +gates reject missing tools, warnings, unproved or justified checks, skipped +allocated units, and proof assumptions or annotations. SPARK Platinum is used only for SPARK components whose contracts fully cover their allocated functional requirements. Lean mathematical soundness, Anubis diff --git a/assurance/requirements.json b/assurance/requirements.json index b1eacd2..482cd32 100644 --- a/assurance/requirements.json +++ b/assurance/requirements.json @@ -18,6 +18,17 @@ "JCK-INT-004" ], "boundary": "Total fixed-scale nonnegative interval decision kernel; certificate parsing, rational-to-fixed-scale conversion, nonlinear analysis, compiler, runtime, operating system, and hardware are outside this component." + }, + { + "component": "proofs/spark/claim_policy/src/jackal_claim_policy", + "target": "SPARK Platinum", + "status": "proved-local", + "requirement_ids": [ + "JCK-CLAIM-001", + "JCK-CLAIM-002", + "JCK-CLAIM-003" + ], + "boundary": "Total finite assurance-axis and rule-category algebra; Python parsing, rule identifier classification, node construction, hashing, rendering, compiler, runtime, operating system, and hardware are outside this component. Exhaustive bridge tests cover the current finite Python registries but are not a formal Python refinement proof." } ], "requirements": [ @@ -77,6 +88,48 @@ "tests/codex_plugin/test_spark_interval.py" ], "residuals": [] + }, + { + "id": "JCK-CLAIM-001", + "shall": "The SPARK claim policy kernel shall return the registry-defined canonical meet for every pair of mathematical, provenance, model-validity, and implementation classes; the mathematical meet shall be commutative, associative, and idempotent.", + "method": "spark-platinum", + "status": "proved", + "allocation": [ + "proofs/spark/claim_policy/src/jackal_claim_policy.ads" + ], + "verification": [ + "proofs/spark/claim_policy/prove.sh", + "tests/claim_policy_conformance_test.py" + ], + "residuals": [] + }, + { + "id": "JCK-CLAIM-002", + "shall": "The SPARK claim policy kernel shall apply the exact preservation, interval-arithmetic, and derived-rule behavior for every mathematical and implementation class without ever strengthening either input axis.", + "method": "spark-platinum", + "status": "proved", + "allocation": [ + "proofs/spark/claim_policy/src/jackal_claim_policy.ads" + ], + "verification": [ + "proofs/spark/claim_policy/prove.sh", + "tests/claim_policy_conformance_test.py" + ], + "residuals": [] + }, + { + "id": "JCK-CLAIM-003", + "shall": "The SPARK claim policy kernel shall preserve each artifact-evidence flag exactly when both parent flags carry it for every pair of artifact flag records.", + "method": "spark-platinum", + "status": "proved", + "allocation": [ + "proofs/spark/claim_policy/src/jackal_claim_policy.ads" + ], + "verification": [ + "proofs/spark/claim_policy/prove.sh", + "tests/claim_policy_conformance_test.py" + ], + "residuals": [] } ], "surface_closure": { diff --git a/proofs/spark/claim_policy/.gitignore b/proofs/spark/claim_policy/.gitignore new file mode 100644 index 0000000..4ded7c4 --- /dev/null +++ b/proofs/spark/claim_policy/.gitignore @@ -0,0 +1,2 @@ +/bin/ +/obj/ diff --git a/proofs/spark/claim_policy/README.md b/proofs/spark/claim_policy/README.md new file mode 100644 index 0000000..9fd4634 --- /dev/null +++ b/proofs/spark/claim_policy/README.md @@ -0,0 +1,24 @@ +# SPARK claim-assurance policy kernel + +This component specifies JACKAL's finite assurance-axis algebra for +`JCK-CLAIM-001`, `JCK-CLAIM-002`, and `JCK-CLAIM-003`. + +It proves the canonical mathematical meet including the shared-rank +`estimated`/`model-based` tie, the provenance/model/implementation meets, +interval-rule mathematical caps, derived-rule implementation caps, preservation +rules, artifact-flag conjunction, termination, and targeted run-time safety. +The mathematical meet is also proved commutative, associative, and idempotent, +so arbitrary parent folds have a stable pairwise foundation. + +Run: + +```sh +./prove.sh +python3 -B -m unittest tests.claim_policy_conformance_test -v +``` + +The Python test exhaustively compares every finite vector with the shipped +producer-side claim kernel. That bridge is exhaustive tested conformance, not a +formal Python refinement theorem. JSON parsing, registry-to-rule-category +mapping, hashing, rendering, Python execution, compiler correctness, and the +independent verifier remain separate obligations. diff --git a/proofs/spark/claim_policy/jackal_claim_policy.gpr b/proofs/spark/claim_policy/jackal_claim_policy.gpr new file mode 100644 index 0000000..7ae835d --- /dev/null +++ b/proofs/spark/claim_policy/jackal_claim_policy.gpr @@ -0,0 +1,12 @@ +project Jackal_Claim_Policy is + for Languages use ("Ada"); + for Source_Dirs use ("src", "tests"); + for Object_Dir use "obj"; + for Exec_Dir use "bin"; + for Main use ("jackal_claim_policy_vectors.adb"); + + package Compiler is + for Default_Switches ("Ada") use + ("-gnat2022", "-gnata", "-gnatVa", "-gnatwa", "-gnatwe", "-O2", "-g"); + end Compiler; +end Jackal_Claim_Policy; diff --git a/proofs/spark/claim_policy/prove.sh b/proofs/spark/claim_policy/prove.sh new file mode 100755 index 0000000..98d64ed --- /dev/null +++ b/proofs/spark/claim_policy/prove.sh @@ -0,0 +1,53 @@ +#!/bin/sh +set -eu + +# Proof obligations: JCK-CLAIM-001, JCK-CLAIM-002, JCK-CLAIM-003. + +SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd -P) +PROJECT="$SCRIPT_DIR/jackal_claim_policy.gpr" + +if ! command -v gnatprove >/dev/null 2>&1 || ! command -v gprbuild >/dev/null 2>&1; then + if [ -f "$HOME/opt/gnat/env.sh" ]; then + # shellcheck disable=SC1091 + . "$HOME/opt/gnat/env.sh" + fi +fi + +command -v gprbuild >/dev/null 2>&1 || { + echo "refused: gprbuild is unavailable" >&2 + exit 1 +} +command -v gnatprove >/dev/null 2>&1 || { + echo "refused: gnatprove is unavailable" >&2 + exit 1 +} + +gprbuild -p -q -P "$PROJECT" +gnatprove -P "$PROJECT" -U --level=3 --report=all --warnings=error \ + --proof-warnings=on --assumptions -j0 + +PROOF_REPORT="$SCRIPT_DIR/obj/gnatprove/gnatprove.out" +[ -f "$PROOF_REPORT" ] || { + echo "refused: GNATprove summary is missing" >&2 + exit 1 +} + +NORMALIZED_TOTAL=$(grep '^Total' "$PROOF_REPORT" | sed 's/([0-9]*%)//g' | tr -s ' ') +set -- $NORMALIZED_TOTAL +[ "$#" -eq 6 ] && [ "$5" = "." ] && [ "$6" = "." ] || { + echo "refused: GNATprove reports justified or unproved checks" >&2 + exit 1 +} + +grep -q 'unit jackal_claim_policy' "$PROOF_REPORT" || { + echo "refused: the claim policy unit was not analyzed" >&2 + exit 1 +} + +if rg -n --glob '*.ad?' 'pragma[[:space:]]+(Assume|Annotate)' \ + "$SCRIPT_DIR/src" "$SCRIPT_DIR/tests"; then + echo "refused: proof assumptions or justifications are forbidden" >&2 + exit 1 +fi + +echo "SPARK_PLATINUM_CLAIM_POLICY_COMPONENT_PROOF_PASS" diff --git a/proofs/spark/claim_policy/src/jackal_claim_policy.adb b/proofs/spark/claim_policy/src/jackal_claim_policy.adb new file mode 100644 index 0000000..58e1e6d --- /dev/null +++ b/proofs/spark/claim_policy/src/jackal_claim_policy.adb @@ -0,0 +1,49 @@ +package body Jackal_Claim_Policy + with SPARK_Mode +is + function Meet_Mathematical + (Left, Right : Mathematical_Class) return Mathematical_Class is + begin + -- JCK-CLAIM-001 + return Required_Mathematical_Meet (Left, Right); + end Meet_Mathematical; + + function Meet_Provenance + (Left, Right : Provenance_Class) return Provenance_Class is + (if Left <= Right then Left else Right); + + function Meet_Model (Left, Right : Model_Class) return Model_Class is + (Required_Model_Meet (Left, Right)); + + function Meet_Implementation + (Left, Right : Implementation_Class) return Implementation_Class is + (if Left <= Right then Left else Right); + + function Meet_Artifact + (Left, Right : Artifact_Flags) return Artifact_Flags is + -- JCK-CLAIM-003 + (Content_Addressed => + Left.Content_Addressed and Right.Content_Addressed, + Reproducible_Built => + Left.Reproducible_Built and Right.Reproducible_Built, + Authenticated => Left.Authenticated and Right.Authenticated, + Transparency_Logged => + Left.Transparency_Logged and Right.Transparency_Logged); + + function Apply_Rule_Caps + (Behavior : Rule_Behavior; + Input : Rule_Axes) return Rule_Axes is + -- JCK-CLAIM-002 + (Mathematical => + Required_Capped_Mathematical (Behavior, Input.Mathematical), + Implementation => + Required_Capped_Implementation (Behavior, Input.Implementation)); + + procedure Prove_Mathematical_Meet_Laws + (Left, Middle, Right : Mathematical_Class) + is + begin + null; + end Prove_Mathematical_Meet_Laws; + +end Jackal_Claim_Policy; diff --git a/proofs/spark/claim_policy/src/jackal_claim_policy.ads b/proofs/spark/claim_policy/src/jackal_claim_policy.ads new file mode 100644 index 0000000..c9d57c1 --- /dev/null +++ b/proofs/spark/claim_policy/src/jackal_claim_policy.ads @@ -0,0 +1,181 @@ +package Jackal_Claim_Policy + with SPARK_Mode +is + type Mathematical_Class is + (Refused, + Indeterminate, + Estimated, + Model_Based, + Checked, + Bounded, + Formal_Bounded, + Exact); + + type Mathematical_Strength is + (Refusal_Strength, + Indeterminate_Strength, + Estimate_Strength, + Check_Strength, + Bound_Strength, + Formal_Bound_Strength, + Exact_Strength); + + function Strength_Of + (Item : Mathematical_Class) return Mathematical_Strength is + (case Item is + when Refused => Refusal_Strength, + when Indeterminate => Indeterminate_Strength, + when Estimated + | Model_Based => Estimate_Strength, + when Checked => Check_Strength, + when Bounded => Bound_Strength, + when Formal_Bounded => Formal_Bound_Strength, + when Exact => Exact_Strength); + + function Required_Mathematical_Meet + (Left, Right : Mathematical_Class) return Mathematical_Class is + (if Strength_Of (Left) < Strength_Of (Right) then Left + elsif Strength_Of (Right) < Strength_Of (Left) then Right + elsif Mathematical_Class'Pos (Left) <= Mathematical_Class'Pos (Right) + then Left + else Right); + + -- JCK-CLAIM-001: canonical weakest-class meet, including the shared-rank + -- Estimated/Model_Based tie break fixed by registry order. + function Meet_Mathematical + (Left, Right : Mathematical_Class) return Mathematical_Class + with + Post => + Meet_Mathematical'Result = + Required_Mathematical_Meet (Left, Right) + and then Strength_Of (Meet_Mathematical'Result) <= Strength_Of (Left) + and then Strength_Of (Meet_Mathematical'Result) <= Strength_Of (Right); + + type Provenance_Class is + (Unknown, + Supplied, + Integrity_Bound, + Observed, + Authenticated_Source, + Measured); + + function Meet_Provenance + (Left, Right : Provenance_Class) return Provenance_Class + with + Post => + Meet_Provenance'Result = + (if Left <= Right then Left else Right); + + type Model_Class is + (Model_Unknown, + Assumed, + Calibrated, + Empirically_Validated, + Not_Applicable); + + function Required_Model_Meet + (Left, Right : Model_Class) return Model_Class is + (if Left = Not_Applicable then Right + elsif Right = Not_Applicable then Left + elsif Left <= Right then Left + else Right); + + function Meet_Model (Left, Right : Model_Class) return Model_Class + with + Post => + Meet_Model'Result = Required_Model_Meet (Left, Right); + + type Implementation_Class is + (Impl_Unknown, + Directly_Trusted, + Campaign_Tested, + Independently_Recomputed, + Checker_Derived, + Source_Native_Refined); + + function Meet_Implementation + (Left, Right : Implementation_Class) return Implementation_Class + with + Post => + Meet_Implementation'Result = + (if Left <= Right then Left else Right); + + type Artifact_Flags is record + Content_Addressed : Boolean; + Reproducible_Built : Boolean; + Authenticated : Boolean; + Transparency_Logged : Boolean; + end record; + + -- JCK-CLAIM-003: compositional artifact evidence survives only when both + -- parents carry the same flag. + function Meet_Artifact + (Left, Right : Artifact_Flags) return Artifact_Flags + with + Post => + Meet_Artifact'Result.Content_Addressed = + (Left.Content_Addressed and Right.Content_Addressed) + and then Meet_Artifact'Result.Reproducible_Built = + (Left.Reproducible_Built and Right.Reproducible_Built) + and then Meet_Artifact'Result.Authenticated = + (Left.Authenticated and Right.Authenticated) + and then Meet_Artifact'Result.Transparency_Logged = + (Left.Transparency_Logged and Right.Transparency_Logged); + + type Rule_Behavior is + (Preserve_Axes, Interval_Arithmetic, Derived_Default); + + type Rule_Axes is record + Mathematical : Mathematical_Class; + Implementation : Implementation_Class; + end record; + + function Required_Capped_Mathematical + (Behavior : Rule_Behavior; + Value : Mathematical_Class) return Mathematical_Class is + (if Behavior = Interval_Arithmetic + and then Strength_Of (Bounded) < Strength_Of (Value) + then Bounded + else Value); + + function Required_Capped_Implementation + (Behavior : Rule_Behavior; + Value : Implementation_Class) return Implementation_Class is + (if Behavior /= Preserve_Axes + and then Independently_Recomputed < Value + then Independently_Recomputed + else Value); + + -- JCK-CLAIM-002: rule application preserves or lowers both axes exactly + -- according to the closed rule category; it can never strengthen them. + function Apply_Rule_Caps + (Behavior : Rule_Behavior; + Input : Rule_Axes) return Rule_Axes + with + Post => + Apply_Rule_Caps'Result.Mathematical = + Required_Capped_Mathematical (Behavior, Input.Mathematical) + and then Apply_Rule_Caps'Result.Implementation = + Required_Capped_Implementation (Behavior, Input.Implementation) + and then Strength_Of (Apply_Rule_Caps'Result.Mathematical) <= + Strength_Of (Input.Mathematical) + and then Apply_Rule_Caps'Result.Implementation <= + Input.Implementation; + + procedure Prove_Mathematical_Meet_Laws + (Left, Middle, Right : Mathematical_Class) + with + Ghost, + Post => + Meet_Mathematical (Left => Left, Right => Right) = + Meet_Mathematical (Left => Right, Right => Left) + and then Meet_Mathematical (Left => Left, Right => Left) = Left + and then Meet_Mathematical + (Left => Meet_Mathematical (Left => Left, Right => Middle), + Right => Right) = + Meet_Mathematical + (Left => Left, + Right => Meet_Mathematical + (Left => Middle, Right => Right)); + +end Jackal_Claim_Policy; diff --git a/proofs/spark/claim_policy/tests/jackal_claim_policy_vectors.adb b/proofs/spark/claim_policy/tests/jackal_claim_policy_vectors.adb new file mode 100644 index 0000000..da33355 --- /dev/null +++ b/proofs/spark/claim_policy/tests/jackal_claim_policy_vectors.adb @@ -0,0 +1,98 @@ +with Ada.Text_IO; +with Jackal_Claim_Policy; + +procedure Jackal_Claim_Policy_Vectors is + package Policy renames Jackal_Claim_Policy; + + function Flag (Mask, Position : Natural) return Boolean is + ((Mask / (2 ** Position)) mod 2 = 1); + + function Artifact (Mask : Natural) return Policy.Artifact_Flags is + (Content_Addressed => Flag (Mask, 0), + Reproducible_Built => Flag (Mask, 1), + Authenticated => Flag (Mask, 2), + Transparency_Logged => Flag (Mask, 3)); + + function Artifact_Mask (Item : Policy.Artifact_Flags) return Natural is + ((if Item.Content_Addressed then 1 else 0) + + (if Item.Reproducible_Built then 2 else 0) + + (if Item.Authenticated then 4 else 0) + + (if Item.Transparency_Logged then 8 else 0)); + +begin + -- Exhaustive bridge vectors for JCK-CLAIM-001, JCK-CLAIM-002, and + -- JCK-CLAIM-003. + for Left in Policy.Mathematical_Class loop + for Right in Policy.Mathematical_Class loop + Ada.Text_IO.Put_Line + ("MATH|" & Policy.Mathematical_Class'Image (Left) + & "|" & Policy.Mathematical_Class'Image (Right) + & "|" & Policy.Mathematical_Class'Image + (Policy.Meet_Mathematical (Left, Right))); + end loop; + end loop; + + for Left in Policy.Provenance_Class loop + for Right in Policy.Provenance_Class loop + Ada.Text_IO.Put_Line + ("PROVENANCE|" & Policy.Provenance_Class'Image (Left) + & "|" & Policy.Provenance_Class'Image (Right) + & "|" & Policy.Provenance_Class'Image + (Policy.Meet_Provenance (Left, Right))); + end loop; + end loop; + + for Left in Policy.Model_Class loop + for Right in Policy.Model_Class loop + Ada.Text_IO.Put_Line + ("MODEL|" & Policy.Model_Class'Image (Left) + & "|" & Policy.Model_Class'Image (Right) + & "|" & Policy.Model_Class'Image + (Policy.Meet_Model (Left, Right))); + end loop; + end loop; + + for Left in Policy.Implementation_Class loop + for Right in Policy.Implementation_Class loop + Ada.Text_IO.Put_Line + ("IMPLEMENTATION|" & Policy.Implementation_Class'Image (Left) + & "|" & Policy.Implementation_Class'Image (Right) + & "|" & Policy.Implementation_Class'Image + (Policy.Meet_Implementation (Left, Right))); + end loop; + end loop; + + for Behavior in Policy.Rule_Behavior loop + for Math in Policy.Mathematical_Class loop + for Implementation in Policy.Implementation_Class loop + declare + Result : constant Policy.Rule_Axes := + Policy.Apply_Rule_Caps + (Behavior, + (Mathematical => Math, Implementation => Implementation)); + begin + Ada.Text_IO.Put_Line + ("RULE|" & Policy.Rule_Behavior'Image (Behavior) + & "|" & Policy.Mathematical_Class'Image (Math) + & "|" & Policy.Implementation_Class'Image (Implementation) + & "|" & Policy.Mathematical_Class'Image + (Result.Mathematical) + & "|" & Policy.Implementation_Class'Image + (Result.Implementation)); + end; + end loop; + end loop; + end loop; + + for Left_Mask in 0 .. 15 loop + for Right_Mask in 0 .. 15 loop + Ada.Text_IO.Put_Line + ("ARTIFACT|" & Natural'Image (Left_Mask) + & "|" & Natural'Image (Right_Mask) + & "|" & Natural'Image + (Artifact_Mask + (Policy.Meet_Artifact + (Artifact (Left_Mask), Artifact (Right_Mask))))); + end loop; + end loop; +end Jackal_Claim_Policy_Vectors; diff --git a/tests/assurance_traceability_test.py b/tests/assurance_traceability_test.py index a04f8a5..425c012 100644 --- a/tests/assurance_traceability_test.py +++ b/tests/assurance_traceability_test.py @@ -9,7 +9,7 @@ class AssuranceTraceabilityTests(unittest.TestCase): - """JCK-INT-001 through JCK-INT-004 and whole-surface closure regression.""" + """JCK-INT and JCK-CLAIM bidirectional whole-surface closure regression.""" def test_traceability_and_surface_closure_gate(self) -> None: completed = subprocess.run( diff --git a/tests/claim_policy_conformance_test.py b/tests/claim_policy_conformance_test.py new file mode 100644 index 0000000..9c47f86 --- /dev/null +++ b/tests/claim_policy_conformance_test.py @@ -0,0 +1,254 @@ +import os +import shutil +import subprocess +import sys +import unittest +from pathlib import Path + + +if not (sys.flags.isolated and sys.flags.no_site): + os.execv( + sys.executable, + [sys.executable, "-I", "-S", "-B", __file__], + ) + + +ROOT = Path(__file__).resolve().parents[1] +SPARK_ROOT = ROOT / "proofs/spark/claim_policy" +VECTORS = SPARK_ROOT / "bin/jackal_claim_policy_vectors" + +sys.path.insert(0, str(ROOT / "tools")) +import claim_bundle_verify as verifier # noqa: E402 +import claim_kernel as producer # noqa: E402 + + +def normalized(value: str, prefix: str = "") -> str: + result = value.strip().lower().replace("_", "-") + if prefix and result.startswith(prefix): + return result[len(prefix):] + return result + + +def artifact_flags(mask: int) -> dict[str, bool]: + return { + flag: bool(mask & (1 << position)) + for position, flag in enumerate(producer.ARTIFACT_FLAGS) + } + + +def artifact_mask(flags: dict[str, bool]) -> int: + return sum( + 1 << position + for position, flag in enumerate(producer.ARTIFACT_FLAGS) + if flags[flag] + ) + + +def assurance_parent( + *, + mathematical: str = "checked", + implementation: str = "directly-trusted", + input_provenance: str = "unknown", + model_validity: str = "not-applicable", + artifact: dict[str, bool] | None = None, +) -> dict: + return { + "assurance": { + "input_provenance": input_provenance, + "model_validity": model_validity, + "mathematical": mathematical, + "implementation": implementation, + "artifact": artifact or { + flag: False for flag in producer.ARTIFACT_FLAGS + }, + } + } + + +class ClaimPolicyConformanceTests(unittest.TestCase): + """Exhaustive refinement for JCK-CLAIM-001, JCK-CLAIM-002, JCK-CLAIM-003.""" + + def test_source_keeps_the_declared_formal_boundary(self) -> None: + sources = [ + SPARK_ROOT / "src/jackal_claim_policy.ads", + SPARK_ROOT / "src/jackal_claim_policy.adb", + ] + text = "\n".join(path.read_text(encoding="utf-8") for path in sources) + self.assertIn("SPARK_Mode", text) + self.assertIn("function Meet_Mathematical", text) + self.assertIn("function Apply_Rule_Caps", text) + self.assertIn("function Meet_Artifact", text) + self.assertIn("Post =>", text) + self.assertNotIn("pragma Assume", text) + self.assertNotIn("pragma Annotate", text) + + @unittest.skipUnless( + shutil.which("gprbuild") and shutil.which("gnatprove") and shutil.which("rg"), + "GNATprove toolchain is not installed", + ) + def test_proved_kernel_matches_both_python_implementations_exhaustively(self) -> None: + proof = subprocess.run( + [str(SPARK_ROOT / "prove.sh")], + cwd=ROOT, + check=False, + capture_output=True, + text=True, + timeout=120, + ) + transcript = proof.stdout + proof.stderr + self.assertEqual(proof.returncode, 0, transcript) + self.assertIn("Success: all checks proved", transcript) + self.assertIn("SPARK_PLATINUM_CLAIM_POLICY_COMPONENT_PROOF_PASS", transcript) + + completed = subprocess.run( + [str(VECTORS)], + cwd=ROOT, + check=False, + capture_output=True, + text=True, + timeout=30, + ) + self.assertEqual(completed.returncode, 0, completed.stdout + completed.stderr) + + self.assertEqual(producer.PROV_ORDER, verifier.PROV_ORDER) + self.assertEqual(producer.MODEL_ORDER, verifier.MODEL_ORDER) + self.assertEqual(producer.MODEL_IDENTITY, verifier.MODEL_IDENTITY) + self.assertEqual(producer.MATH_ORDER, verifier.MATH_ORDER) + self.assertEqual(producer.MATH_RANKS, verifier.MATH_RANKS) + self.assertEqual(producer.IMPL_ORDER, verifier.IMPL_ORDER) + self.assertEqual(producer.ARTIFACT_FLAGS, verifier.ARTIFACT_FLAGS) + self.assertEqual(producer.MATH_CAPS, verifier.MATH_CAPS) + self.assertEqual(producer.PRESERVE_RULES, verifier.PRESERVE_RULES) + self.assertEqual(producer.IMPL_CAP_DEFAULT, verifier.IMPL_CAP_DEFAULT) + + engine = verifier.RuleEngine(None, {}) + seen: set[str] = set() + rule_vectors: dict[tuple[str, str, str], tuple[str, str]] = {} + + def integrated_axes(rule_id: str, parents: list[dict]) -> dict: + produced = producer.computed_axes(rule_id, parents) + checked = engine.computed_axes({"rule": {"id": rule_id}}, parents) + self.assertEqual(checked, produced) + return produced + + for raw_line in completed.stdout.splitlines(): + fields = [field.strip() for field in raw_line.split("|")] + kind = fields[0] + seen.add(kind) + + if kind == "MATH": + left, right, expected = (normalized(item) for item in fields[1:]) + self.assertEqual( + producer._meet([left, right], producer.MATH_ORDER, + producer.MATH_RANKS), + expected, + ) + self.assertEqual( + verifier.meet_ordered([left, right], verifier.MATH_ORDER, + verifier.MATH_RANKS), + expected, + ) + axes = integrated_axes( + "model_condition", + [ + assurance_parent(mathematical=left), + assurance_parent(mathematical=right), + ], + ) + self.assertEqual(axes["mathematical"], expected) + elif kind == "PROVENANCE": + left, right, expected = (normalized(item) for item in fields[1:]) + self.assertEqual( + producer._meet([left, right], producer.PROV_ORDER), expected + ) + self.assertEqual( + verifier.meet_ordered([left, right], verifier.PROV_ORDER), expected + ) + axes = integrated_axes( + "model_condition", + [ + assurance_parent(input_provenance=left), + assurance_parent(input_provenance=right), + ], + ) + self.assertEqual(axes["input_provenance"], expected) + elif kind == "MODEL": + left, right, expected = ( + normalized(item, "model-") for item in fields[1:] + ) + self.assertEqual(producer._meet_model([left, right]), expected) + self.assertEqual(verifier.meet_model([left, right]), expected) + axes = integrated_axes( + "model_condition", + [ + assurance_parent(model_validity=left), + assurance_parent(model_validity=right), + ], + ) + self.assertEqual(axes["model_validity"], expected) + elif kind == "IMPLEMENTATION": + left, right, expected = ( + normalized(item, "impl-") for item in fields[1:] + ) + self.assertEqual( + producer._meet([left, right], producer.IMPL_ORDER), expected + ) + self.assertEqual( + verifier.meet_ordered([left, right], verifier.IMPL_ORDER), expected + ) + axes = integrated_axes( + "model_condition", + [ + assurance_parent(implementation=left), + assurance_parent(implementation=right), + ], + ) + self.assertEqual(axes["implementation"], expected) + elif kind == "RULE": + behavior = normalized(fields[1]) + mathematical = normalized(fields[2]) + implementation = normalized(fields[3], "impl-") + rule_vectors[(behavior, mathematical, implementation)] = ( + normalized(fields[4]), normalized(fields[5], "impl-") + ) + elif kind == "ARTIFACT": + left, right, expected = (int(item) for item in fields[1:]) + self.assertEqual(left & right, expected) + axes = integrated_axes( + "model_condition", + [ + assurance_parent(artifact=artifact_flags(left)), + assurance_parent(artifact=artifact_flags(right)), + ], + ) + self.assertEqual(artifact_mask(axes["artifact"]), expected) + else: + self.fail(f"unknown SPARK vector kind: {kind}") + + self.assertEqual( + seen, + {"MATH", "PROVENANCE", "MODEL", "IMPLEMENTATION", "RULE", "ARTIFACT"}, + ) + + for rule_id in verifier.RULE_IDS: + if rule_id in verifier.PRESERVE_RULES: + behavior = "preserve-axes" + elif rule_id in verifier.MATH_CAPS: + behavior = "interval-arithmetic" + else: + behavior = "derived-default" + for mathematical in producer.MATH_ORDER: + for implementation in producer.IMPL_ORDER: + expected_math, expected_impl = rule_vectors[ + (behavior, mathematical, implementation) + ] + parent = assurance_parent( + mathematical=mathematical, implementation=implementation + ) + produced = integrated_axes(rule_id, [parent]) + self.assertEqual(produced["mathematical"], expected_math) + self.assertEqual(produced["implementation"], expected_impl) + + +if __name__ == "__main__": + unittest.main(verbosity=2) From abd423a309054724cf2a0fbf5b3f9eabfe75a333 Mon Sep 17 00:00:00 2001 From: sicarii Date: Sat, 29 Aug 2026 00:37:28 -0400 Subject: [PATCH 15/22] Keep claim refinement tests composable --- assurance/requirements.json | 9 +- tests/claim_policy_conformance_test.py | 82 ++++---- tests/claim_policy_verifier_bridge.py | 247 +++++++++++++++++++++++++ 3 files changed, 292 insertions(+), 46 deletions(-) create mode 100644 tests/claim_policy_verifier_bridge.py diff --git a/assurance/requirements.json b/assurance/requirements.json index 482cd32..c018cd1 100644 --- a/assurance/requirements.json +++ b/assurance/requirements.json @@ -99,7 +99,8 @@ ], "verification": [ "proofs/spark/claim_policy/prove.sh", - "tests/claim_policy_conformance_test.py" + "tests/claim_policy_conformance_test.py", + "tests/claim_policy_verifier_bridge.py" ], "residuals": [] }, @@ -113,7 +114,8 @@ ], "verification": [ "proofs/spark/claim_policy/prove.sh", - "tests/claim_policy_conformance_test.py" + "tests/claim_policy_conformance_test.py", + "tests/claim_policy_verifier_bridge.py" ], "residuals": [] }, @@ -127,7 +129,8 @@ ], "verification": [ "proofs/spark/claim_policy/prove.sh", - "tests/claim_policy_conformance_test.py" + "tests/claim_policy_conformance_test.py", + "tests/claim_policy_verifier_bridge.py" ], "residuals": [] } diff --git a/tests/claim_policy_conformance_test.py b/tests/claim_policy_conformance_test.py index 9c47f86..eafa09a 100644 --- a/tests/claim_policy_conformance_test.py +++ b/tests/claim_policy_conformance_test.py @@ -1,25 +1,17 @@ -import os +import json import shutil import subprocess import sys import unittest from pathlib import Path - -if not (sys.flags.isolated and sys.flags.no_site): - os.execv( - sys.executable, - [sys.executable, "-I", "-S", "-B", __file__], - ) - - ROOT = Path(__file__).resolve().parents[1] SPARK_ROOT = ROOT / "proofs/spark/claim_policy" VECTORS = SPARK_ROOT / "bin/jackal_claim_policy_vectors" +VERIFIER_BRIDGE = ROOT / "tests/claim_policy_verifier_bridge.py" -sys.path.insert(0, str(ROOT / "tools")) -import claim_bundle_verify as verifier # noqa: E402 -import claim_kernel as producer # noqa: E402 +sys.path.insert(0, str(ROOT)) +from tools import claim_kernel as producer # noqa: E402 def normalized(value: str, prefix: str = "") -> str: @@ -110,26 +102,11 @@ def test_proved_kernel_matches_both_python_implementations_exhaustively(self) -> ) self.assertEqual(completed.returncode, 0, completed.stdout + completed.stderr) - self.assertEqual(producer.PROV_ORDER, verifier.PROV_ORDER) - self.assertEqual(producer.MODEL_ORDER, verifier.MODEL_ORDER) - self.assertEqual(producer.MODEL_IDENTITY, verifier.MODEL_IDENTITY) - self.assertEqual(producer.MATH_ORDER, verifier.MATH_ORDER) - self.assertEqual(producer.MATH_RANKS, verifier.MATH_RANKS) - self.assertEqual(producer.IMPL_ORDER, verifier.IMPL_ORDER) - self.assertEqual(producer.ARTIFACT_FLAGS, verifier.ARTIFACT_FLAGS) - self.assertEqual(producer.MATH_CAPS, verifier.MATH_CAPS) - self.assertEqual(producer.PRESERVE_RULES, verifier.PRESERVE_RULES) - self.assertEqual(producer.IMPL_CAP_DEFAULT, verifier.IMPL_CAP_DEFAULT) - - engine = verifier.RuleEngine(None, {}) seen: set[str] = set() rule_vectors: dict[tuple[str, str, str], tuple[str, str]] = {} def integrated_axes(rule_id: str, parents: list[dict]) -> dict: - produced = producer.computed_axes(rule_id, parents) - checked = engine.computed_axes({"rule": {"id": rule_id}}, parents) - self.assertEqual(checked, produced) - return produced + return producer.computed_axes(rule_id, parents) for raw_line in completed.stdout.splitlines(): fields = [field.strip() for field in raw_line.split("|")] @@ -143,11 +120,6 @@ def integrated_axes(rule_id: str, parents: list[dict]) -> dict: producer.MATH_RANKS), expected, ) - self.assertEqual( - verifier.meet_ordered([left, right], verifier.MATH_ORDER, - verifier.MATH_RANKS), - expected, - ) axes = integrated_axes( "model_condition", [ @@ -161,9 +133,6 @@ def integrated_axes(rule_id: str, parents: list[dict]) -> dict: self.assertEqual( producer._meet([left, right], producer.PROV_ORDER), expected ) - self.assertEqual( - verifier.meet_ordered([left, right], verifier.PROV_ORDER), expected - ) axes = integrated_axes( "model_condition", [ @@ -177,7 +146,6 @@ def integrated_axes(rule_id: str, parents: list[dict]) -> dict: normalized(item, "model-") for item in fields[1:] ) self.assertEqual(producer._meet_model([left, right]), expected) - self.assertEqual(verifier.meet_model([left, right]), expected) axes = integrated_axes( "model_condition", [ @@ -193,9 +161,6 @@ def integrated_axes(rule_id: str, parents: list[dict]) -> dict: self.assertEqual( producer._meet([left, right], producer.IMPL_ORDER), expected ) - self.assertEqual( - verifier.meet_ordered([left, right], verifier.IMPL_ORDER), expected - ) axes = integrated_axes( "model_condition", [ @@ -230,10 +195,41 @@ def integrated_axes(rule_id: str, parents: list[dict]) -> dict: {"MATH", "PROVENANCE", "MODEL", "IMPLEMENTATION", "RULE", "ARTIFACT"}, ) - for rule_id in verifier.RULE_IDS: - if rule_id in verifier.PRESERVE_RULES: + bridge = subprocess.run( + [ + sys.executable, + "-I", + "-S", + "-B", + str(VERIFIER_BRIDGE), + str(VECTORS), + ], + cwd=ROOT, + check=False, + capture_output=True, + text=True, + timeout=60, + ) + self.assertEqual(bridge.returncode, 0, bridge.stdout + bridge.stderr) + bridge_result = json.loads(bridge.stdout) + self.assertEqual(bridge_result["status"], "pass") + self.assertEqual(producer.PROV_ORDER, bridge_result["PROV_ORDER"]) + self.assertEqual(producer.MODEL_ORDER, bridge_result["MODEL_ORDER"]) + self.assertEqual(producer.MODEL_IDENTITY, bridge_result["MODEL_IDENTITY"]) + self.assertEqual(producer.MATH_ORDER, bridge_result["MATH_ORDER"]) + self.assertEqual(producer.MATH_RANKS, bridge_result["MATH_RANKS"]) + self.assertEqual(producer.IMPL_ORDER, bridge_result["IMPL_ORDER"]) + self.assertEqual(producer.ARTIFACT_FLAGS, bridge_result["ARTIFACT_FLAGS"]) + self.assertEqual(producer.MATH_CAPS, bridge_result["MATH_CAPS"]) + self.assertEqual( + sorted(producer.PRESERVE_RULES), bridge_result["PRESERVE_RULES"] + ) + self.assertEqual(producer.IMPL_CAP_DEFAULT, bridge_result["IMPL_CAP_DEFAULT"]) + + for rule_id in bridge_result["RULE_IDS"]: + if rule_id in producer.PRESERVE_RULES: behavior = "preserve-axes" - elif rule_id in verifier.MATH_CAPS: + elif rule_id in producer.MATH_CAPS: behavior = "interval-arithmetic" else: behavior = "derived-default" diff --git a/tests/claim_policy_verifier_bridge.py b/tests/claim_policy_verifier_bridge.py new file mode 100644 index 0000000..92f653e --- /dev/null +++ b/tests/claim_policy_verifier_bridge.py @@ -0,0 +1,247 @@ +#!/usr/bin/env python3 +"""Isolated verifier bridge for JCK-CLAIM-001, JCK-CLAIM-002, JCK-CLAIM-003.""" + +from __future__ import annotations + +import json +from pathlib import Path +import subprocess +import sys + + +if not (sys.flags.isolated and sys.flags.no_site): + sys.stderr.write("refused: verifier bridge requires python3 -I -S -B\n") + raise SystemExit(126) + +ROOT = Path(__file__).resolve().parents[1] +sys.path.insert(0, str(ROOT / "tools")) +import claim_bundle_verify as verifier # noqa: E402 + + +def normalized(value: str, prefix: str = "") -> str: + result = value.strip().lower().replace("_", "-") + if prefix and result.startswith(prefix): + return result[len(prefix):] + return result + + +def artifact_flags(mask: int) -> dict[str, bool]: + return { + flag: bool(mask & (1 << position)) + for position, flag in enumerate(verifier.ARTIFACT_FLAGS) + } + + +def artifact_mask(flags: dict[str, bool]) -> int: + return sum( + 1 << position + for position, flag in enumerate(verifier.ARTIFACT_FLAGS) + if flags[flag] + ) + + +def assurance_parent( + *, + mathematical: str = "checked", + implementation: str = "directly-trusted", + input_provenance: str = "unknown", + model_validity: str = "not-applicable", + artifact: dict[str, bool] | None = None, +) -> dict: + return { + "assurance": { + "input_provenance": input_provenance, + "model_validity": model_validity, + "mathematical": mathematical, + "implementation": implementation, + "artifact": artifact or { + flag: False for flag in verifier.ARTIFACT_FLAGS + }, + } + } + + +def require(condition: bool, message: str) -> None: + if not condition: + raise RuntimeError(message) + + +def main() -> int: + if len(sys.argv) != 2: + raise RuntimeError("expected one SPARK vector executable") + vectors = Path(sys.argv[1]).resolve(strict=True) + completed = subprocess.run( + [str(vectors)], + cwd=ROOT, + check=False, + capture_output=True, + text=True, + timeout=30, + ) + require(completed.returncode == 0, completed.stdout + completed.stderr) + + engine = verifier.RuleEngine(None, {}) + seen: set[str] = set() + rule_vectors: dict[tuple[str, str, str], tuple[str, str]] = {} + + def integrated_axes(rule_id: str, parents: list[dict]) -> dict: + return engine.computed_axes({"rule": {"id": rule_id}}, parents) + + for raw_line in completed.stdout.splitlines(): + fields = [field.strip() for field in raw_line.split("|")] + kind = fields[0] + seen.add(kind) + + if kind == "MATH": + left, right, expected = (normalized(item) for item in fields[1:]) + require( + verifier.meet_ordered( + [left, right], verifier.MATH_ORDER, verifier.MATH_RANKS + ) == expected, + f"mathematical meet mismatch: {fields}", + ) + require( + integrated_axes( + "model_condition", + [ + assurance_parent(mathematical=left), + assurance_parent(mathematical=right), + ], + )["mathematical"] == expected, + f"integrated mathematical mismatch: {fields}", + ) + elif kind == "PROVENANCE": + left, right, expected = (normalized(item) for item in fields[1:]) + require( + verifier.meet_ordered([left, right], verifier.PROV_ORDER) == expected, + f"provenance meet mismatch: {fields}", + ) + require( + integrated_axes( + "model_condition", + [ + assurance_parent(input_provenance=left), + assurance_parent(input_provenance=right), + ], + )["input_provenance"] == expected, + f"integrated provenance mismatch: {fields}", + ) + elif kind == "MODEL": + left, right, expected = ( + normalized(item, "model-") for item in fields[1:] + ) + require( + verifier.meet_model([left, right]) == expected, + f"model meet mismatch: {fields}", + ) + require( + integrated_axes( + "model_condition", + [ + assurance_parent(model_validity=left), + assurance_parent(model_validity=right), + ], + )["model_validity"] == expected, + f"integrated model mismatch: {fields}", + ) + elif kind == "IMPLEMENTATION": + left, right, expected = ( + normalized(item, "impl-") for item in fields[1:] + ) + require( + verifier.meet_ordered([left, right], verifier.IMPL_ORDER) == expected, + f"implementation meet mismatch: {fields}", + ) + require( + integrated_axes( + "model_condition", + [ + assurance_parent(implementation=left), + assurance_parent(implementation=right), + ], + )["implementation"] == expected, + f"integrated implementation mismatch: {fields}", + ) + elif kind == "RULE": + behavior = normalized(fields[1]) + mathematical = normalized(fields[2]) + implementation = normalized(fields[3], "impl-") + rule_vectors[(behavior, mathematical, implementation)] = ( + normalized(fields[4]), normalized(fields[5], "impl-") + ) + elif kind == "ARTIFACT": + left, right, expected = (int(item) for item in fields[1:]) + axes = integrated_axes( + "model_condition", + [ + assurance_parent(artifact=artifact_flags(left)), + assurance_parent(artifact=artifact_flags(right)), + ], + ) + require( + artifact_mask(axes["artifact"]) == expected, + f"artifact meet mismatch: {fields}", + ) + else: + raise RuntimeError(f"unknown SPARK vector kind: {kind}") + + require( + seen == {"MATH", "PROVENANCE", "MODEL", "IMPLEMENTATION", "RULE", "ARTIFACT"}, + f"incomplete SPARK vector kinds: {sorted(seen)}", + ) + + for rule_id in verifier.RULE_IDS: + if rule_id in verifier.PRESERVE_RULES: + behavior = "preserve-axes" + elif rule_id in verifier.MATH_CAPS: + behavior = "interval-arithmetic" + else: + behavior = "derived-default" + for mathematical in verifier.MATH_ORDER: + for implementation in verifier.IMPL_ORDER: + expected_math, expected_impl = rule_vectors[ + (behavior, mathematical, implementation) + ] + axes = integrated_axes( + rule_id, + [ + assurance_parent( + mathematical=mathematical, + implementation=implementation, + ) + ], + ) + require( + axes["mathematical"] == expected_math, + f"rule mathematical mismatch: {rule_id}", + ) + require( + axes["implementation"] == expected_impl, + f"rule implementation mismatch: {rule_id}", + ) + + print( + json.dumps( + { + "status": "pass", + "PROV_ORDER": verifier.PROV_ORDER, + "MODEL_ORDER": verifier.MODEL_ORDER, + "MODEL_IDENTITY": verifier.MODEL_IDENTITY, + "MATH_ORDER": verifier.MATH_ORDER, + "MATH_RANKS": verifier.MATH_RANKS, + "IMPL_ORDER": verifier.IMPL_ORDER, + "ARTIFACT_FLAGS": verifier.ARTIFACT_FLAGS, + "MATH_CAPS": verifier.MATH_CAPS, + "PRESERVE_RULES": sorted(verifier.PRESERVE_RULES), + "IMPL_CAP_DEFAULT": verifier.IMPL_CAP_DEFAULT, + "RULE_IDS": sorted(verifier.RULE_IDS), + }, + sort_keys=True, + separators=(",", ":"), + ) + ) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) From 98fad290bc54186019ca1272ecf3ab57ca7e710d Mon Sep 17 00:00:00 2001 From: sicarii Date: Sat, 29 Aug 2026 00:38:25 -0400 Subject: [PATCH 16/22] Expand JACKAL with integrated THOTH STEM workflows --- README.md | 5 + RESEARCH.md | 2 +- docs/AEROSPACE_READINESS_GAP_LEDGER.md | 68 + docs/HELLGATE_DIAGNOSTICS_ASSURANCE_DESIGN.md | 131 ++ .../2026-08-17-jackel-codex-plugin-design.md | 59 +- evals/mcp/jackal_stem_v1.xml | 43 + plugins/jackel/.codex-plugin/plugin.json | 35 +- plugins/jackel/PLUGIN_IDENTITY.sha256 | 18 +- plugins/jackel/README.md | 101 +- .../jackal-linked-evidence-workspace.png | Bin 0 -> 576566 bytes .../assets/jackal-thoth-hellgate-graph.png | Bin 0 -> 21202 bytes plugins/jackel/mcp/advanced.py | 858 ++++++++ plugins/jackel/mcp/certificates/README.md | 15 + .../mcp/certificates/hellgate_v1.json.zlib | Bin 0 -> 699181 bytes plugins/jackel/mcp/hellgate_verify.py | 1145 +++++++++++ plugins/jackel/mcp/measurement.py | 1341 +++++++++++++ plugins/jackel/mcp/server.py | 1717 ++++++++++++++++- plugins/jackel/mcp/stem.py | 1577 +++++++++++++++ plugins/jackel/scripts/provision_runtime.py | 573 +++++- plugins/jackel/skills/jackel/SKILL.md | 90 +- release/capability_inventory_v1.json | 2 +- tests/capability_drift_gate_test.py | 68 +- tests/codex_plugin/live_acceptance.py | 798 +++++++- tests/codex_plugin/test_advanced.py | 250 +++ tests/codex_plugin/test_hellgate.py | 237 +++ tests/codex_plugin/test_live_acceptance.py | 431 ++++- tests/codex_plugin/test_mcp_adapter.py | 316 ++- tests/codex_plugin/test_measurement.py | 159 ++ tests/codex_plugin/test_plugin_metadata.py | 112 +- .../codex_plugin/test_runtime_provisioner.py | 182 ++ tests/codex_plugin/test_stem.py | 520 +++++ tests/codex_plugin/ui_stem_acceptance.py | 157 ++ tests/jackal_skill_contract_test.py | 32 +- tools/capability_drift_gate.py | 242 ++- tools/hellgate_generate.py | 453 +++++ tools/hellgate_trial_oracle.py | 166 ++ 36 files changed, 11639 insertions(+), 264 deletions(-) create mode 100644 docs/AEROSPACE_READINESS_GAP_LEDGER.md create mode 100644 docs/HELLGATE_DIAGNOSTICS_ASSURANCE_DESIGN.md create mode 100644 evals/mcp/jackal_stem_v1.xml create mode 100644 plugins/jackel/assets/jackal-linked-evidence-workspace.png create mode 100644 plugins/jackel/assets/jackal-thoth-hellgate-graph.png create mode 100644 plugins/jackel/mcp/advanced.py create mode 100644 plugins/jackel/mcp/certificates/README.md create mode 100644 plugins/jackel/mcp/certificates/hellgate_v1.json.zlib create mode 100644 plugins/jackel/mcp/hellgate_verify.py create mode 100644 plugins/jackel/mcp/measurement.py create mode 100644 plugins/jackel/mcp/stem.py create mode 100644 tests/codex_plugin/test_advanced.py create mode 100644 tests/codex_plugin/test_hellgate.py create mode 100644 tests/codex_plugin/test_measurement.py create mode 100644 tests/codex_plugin/test_stem.py create mode 100644 tests/codex_plugin/ui_stem_acceptance.py create mode 100644 tools/hellgate_generate.py create mode 100644 tools/hellgate_trial_oracle.py diff --git a/README.md b/README.md index 4c5382f..f3bdf00 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,11 @@ Qalculate!, Soulver and SpeedCrunch. JACKAL does **not** claim parity with a gen arbitrary-precision-float engine, or interactive graphing system. Its differentiated implemented surface is claim-aware and measurement-aware computation. +For an honest path from research kernel to an externally reviewable engineering +pilot, see [`docs/AEROSPACE_READINESS_GAP_LEDGER.md`](docs/AEROSPACE_READINESS_GAP_LEDGER.md). +It separates implemented evidence from the qualification, refinement, +independent-verification, safety, security, and operations work that remains. + ## Why a calculator, in the age of frontier AI Language models are demonstrably unreliable at the arithmetic layer. OpenAI's own GSM8K diff --git a/RESEARCH.md b/RESEARCH.md index 70c772a..4252c79 100644 --- a/RESEARCH.md +++ b/RESEARCH.md @@ -5,7 +5,7 @@ This matrix uses official product pages as the baseline rather than review-site | Baseline | Observed strengths | JACKAL response | |---|---|---| -| TI-Nspire CX II CAS | Linked algebraic/graphical/numeric views; CAS; matrices; regression, distributions, hypothesis tests; saved documents; programming and sensor data.[1] | Add matrices, numerical solvers, model cards, and reproducible fingerprints. A terminal Anubis program cannot honestly claim equivalent interactive graphing or CAS. | +| TI-Nspire CX II CAS | Linked algebraic/graphical/numeric views; CAS; matrices; regression, distributions, hypothesis tests; saved documents; programming and sensor data.[1] | JACKAL now adds an identity-pinned evidence-aware CAS router and a professional PNG graph lane to the Codex surface, with exact rational x coordinates, estimated f64 y samples, explicit curve breaks on refusal, and reproducible wrapper fingerprints. It still does **not** claim TI-Nspire-equivalent linked interactive views, matrices, regression, sensor acquisition, or a general-purpose CAS. | | Qalculate! | "Arbitrary precision with both rational and floating point numbers"; exact/approximate forms; symbolic calculus; "propagation of uncertainty and interval arithmetic"; extensive units/constants; plotting.[2] | Add first-class measured quantities, propagated uncertainty, dimensional checks, numerical calculus, and explicit model limits. JACKAL now implements exact arbitrary-precision **integers** (`big-add/mul/pow/fact/ncr`) and exact **big rationals** (`rat`) in pure Anubis, plus outward-rounded **interval arithmetic** as a certified lane (`integrate-bound`/`range-bound`, refuse-on-doubt — with its f64/libm rounding model stated rather than implied); arbitrary-precision floats and general CAS remain outside the claimed surface. | | Soulver | Natural-language notepad; variables, line references, live updates, units, dates and scenario worksheets.[3] | Add human-readable calculation cards and Anubis-native audit narratives. JACKAL now has single-invocation worksheets with persistent variables (`worksheet "a = 5; b = a^2; a+b"`); a persistent reactive notebook with live updates is still not claimed. | | SpeedCrunch | Fast keyboard workflow; live results/history; custom functions/variables; "up to 50 digits of precision"; formula/constants library.[4] | Keep a scriptable CLI, add domain models and self-auditing output. JACKAL's `big-` integer lane is exact at any length within stated compute caps (verified against Python's arbitrary precision, e.g. 1000! at 2568 digits) — beyond 50 digits for integer work. Float work remains IEEE-754 f64: 50-digit float precision is still not claimed. | diff --git a/docs/AEROSPACE_READINESS_GAP_LEDGER.md b/docs/AEROSPACE_READINESS_GAP_LEDGER.md new file mode 100644 index 0000000..dbaba26 --- /dev/null +++ b/docs/AEROSPACE_READINESS_GAP_LEDGER.md @@ -0,0 +1,68 @@ +# JACKAL aerospace-readiness gap ledger + +JACKAL should be presented to aerospace organizations as an evidence-aware +computation kernel under active verification, not as a qualified flight tool. +The strongest credible pitch is that it makes assurance boundaries visible and +refuses unsupported claims. Grant and pilot proposals should ask reviewers to +evaluate reproducible artifacts, not superlatives. + +## Evidence already present + +- closed, identity-pinned runtime and wrapper inventories; +- explicit `exact`, `exact-given`, `checked`, `estimated`, `bounded`, + `formal-bounded`, `model-based`, and refusal outcomes; +- independent replay for admitted formal receipts and claim bundles; +- fail-closed MCP transport, process isolation, bounded resources, and mutation + tests; +- THOTH provenance carried inside JACKAL rather than a second authority; +- exact-field matrix workflows, model-scoped statistics, sensors with supplied + provenance, idealized aerospace workflows, graphing, and linked views; +- a fixed HELLGATE nonlinear eigenvalue enclosure with subject-scoped trial + diagnostics and a narrowly stated ground-state quartic/energy transfer; +- a repository-side SPARK interval kernel whose contracts and run-time checks + are discharged by GNATprove without `pragma Assume`. + +None of those facts by itself qualifies JACKAL for mission, flight, launch, +personnel-safety, or hardware-control use. + +## Blocking gaps before a serious operational pilot + +| Gap | Required artifact | Admission gate | +|---|---|---| +| Requirements | uniquely identified shall-statements and bidirectional traceability | every public claim maps to requirement, implementation, test, and residual risk | +| Independent verification | verifier developed and reviewed separately from each producer | hostile certificates and semantic-laundering mutations fail closed | +| Formal refinement | proof that admitted source inputs refine the checker model | no status promotion until parser, arithmetic, and source-to-checker gaps are closed | +| Toolchain trust | pinned compiler/prover/runtime plus reproducible build evidence | binary identity, environment, options, and proof reports are independently replayable | +| Numerical validation | benchmark corpus with reference solutions and explicit conditioning | errors are separated into model, discretization, domain, iteration, rounding, and quadrature components | +| Safety case | program-specific hazards, controls, independence, and human review | consequence ceiling cannot be raised by mathematical assurance alone | +| Cybersecurity | threat model, supply-chain policy, vulnerability handling, and penetration evidence | no unauthenticated input can silently widen authority or bypass refusal | +| Operations | configuration control, rollback, audit retention, incident response, and training | every operational result remains bound to exact version and policy expectations | +| Human factors | reviewable rendering and anti-automation-bias controls | plots, badges, and summaries cannot hide assumptions or non-claims | + +## Recommended pilot scope + +Start with read-only, non-commanding engineering analysis where an existing +trusted workflow can run in parallel. Candidate work packages are symbolic +preprocessing, exact unit transformations, independently replayed bounds, +matrix calculations over exact inputs, and provenance-preserving report +assembly. Exclude flight control, autonomous commanding, pass/fail launch +authority, and safety-critical sensor decisions until a sponsoring program +defines and accepts a qualification basis. + +## HELLGATE residuals + +The fixed certificate currently supports a `bounded` ground-state eigenvalue, +a `bounded` ground-state quartic norm and energy-functional transfer, and +`bounded` trial-only moments and consistency residuals. It still does not +enclose the true ground-state polynomial moments, nonlinear sensitivity, +tunnelling split, or Bogoliubov spectrum. Spectral stability and the remaining +strong-coupling topology work require separate mathematical certificates. + +## Funding-grade demonstration package + +A credible external demonstration should ship a frozen source snapshot, exact +plugin/runtime identities, build instructions, proof logs, mutation corpus, +benchmark results, a signed limitation statement, and a one-command read-only +replay. The evaluation question should be: “Can an independent reviewer +reproduce every admitted claim and every refusal?” It should not be: “Does the +interface look confident?” diff --git a/docs/HELLGATE_DIAGNOSTICS_ASSURANCE_DESIGN.md b/docs/HELLGATE_DIAGNOSTICS_ASSURANCE_DESIGN.md new file mode 100644 index 0000000..af8d1c3 --- /dev/null +++ b/docs/HELLGATE_DIAGNOSTICS_ASSURANCE_DESIGN.md @@ -0,0 +1,131 @@ +# HELLGATE diagnostic and transfer assurance design + +Status: implemented and locally replayed in the additive Codex plugin +worktree; this is not a release-qualification statement. + +## Objective + +Extend the fixed `hellgate-v1` replay without changing its problem, Barta +theorem, top-level `bounded` status, or refusal behavior. The extension must +answer two different questions without conflating them: + +1. What can the exact-rational checker enclose about the normalized certificate + trial `phi`? +2. What, if anything, can be transferred from that trial to the true positive + normalized ground state `u0`? + +The existing eigenvalue enclosure remains the primary result. New fields are +additive and are rejected at startup if the same identity-pinned checker cannot +recompute them. + +## Trial diagnostics + +For every interior polynomial piece the checker already proves a uniform +enclosure + +``` +abs(exp(q(s)) - p(s)) <= eta, 0 <= s <= 1. +``` + +The diagnostic extension shall: + +- convert the power-basis density polynomial to exact Bernstein coefficients; +- refuse unless `p - eta` is pointwise positive on every piece; +- integrate exact polynomial lower and upper bounds for `exp(q)`, `exp(2*q)`, + `x^k exp(q)`, and `q'(x)^2 exp(q)`; +- enclose all omitted half-line tails with the already checked decreasing + logarithmic derivative and exact exponential-moment formulae; +- divide only by the positive exact-rational normalization enclosure; +- return intervals for the trial quartic norm, moments 2/4/6, kinetic energy, + energy functional, energy/eigenvalue-identity residual, and virial residual. + +Every one of these fields is about `phi`, not `u0`. The result must carry a +subject identifier and non-claims that make this distinction machine-visible. + +## Ground-state quartic-norm transfer + +Write `rho_phi = phi^2` and `rho_0 = u0^2`. On mass-one positive densities, + +``` +F(rho) = epsilon^2/4 * integral(rho'^2/rho) + + integral(V rho) + lambda/2 * integral(rho^2) +``` + +is `lambda`-strongly convex in `L2`: the Fisher term is convex, the potential +term is linear, and the final term supplies the strong-convexity modulus. Its +first variation at `rho_phi` is the nonlinear quotient `R_phi`. + +If the checker proves `abs(R_phi - c) <= delta` globally, normalization gives +`integral(rho_phi-rho_0)=0`, and strong convexity plus +`norm(rho_phi-rho_0, L1) <= 2` gives + +``` +norm(rho_phi-rho_0, L2)^2 <= 4*delta/lambda. +``` + +The checker shall enclose the square root by exact integer/rational arithmetic +and transfer the trial `L2`-norm interval to + +``` +(max(0, norm(rho_phi, L2) - d))^2 + <= integral(u0^4) + <= (norm(rho_phi, L2) + d)^2. +``` + +This transfer does not enclose polynomial moments, the lambda derivative, the +Bogoliubov spectrum, or the tunnelling split. Those residuals remain explicit. + +## SPARK boundary + +The SPARK component is deliberately smaller than the mathematical checker. It +implements a total fixed-scale nonnegative interval decision kernel with +requirements `JCK-INT-001` through `JCK-INT-004`. The contracts cover exact +ordered width, midpoint/ceiling-radius endpoint coverage, strict admission +equivalence, deterministic rejection precedence, accepted derived outputs, and +zeroed rejection outputs over every value of the declared public input types. +The level-3 gate refuses warnings, unproved checks, justified checks, a skipped +unit, `pragma Assume`, or `pragma Annotate`. + +SPARK establishes absence of run-time errors and the stated arithmetic +postconditions for this component. It does not prove: + +- the nonlinear Barta theorem; +- the strong-convexity transfer theorem; +- Python-to-SPARK refinement or parser correctness; +- source-to-object equivalence; +- compiler, run-time, floating-point, or physical-model qualification. + +The SPARK executable is a repository-side independent proof/test artifact. It +is not inserted into the cross-platform MCP startup path until separately +packaged, identity-pinned binaries and source-to-input binding are designed. + +## Acceptance gates + +- The original compressed certificate remains byte-identical. +- Existing eigenvalue endpoints remain byte-identical. +- Coherently repinned mutations of density, tail, normalization, parity, + continuity, or non-claims refuse. +- Trial diagnostic intervals are ordered and contain direct high-precision + producer values used only as test oracles. +- The energy-identity and virial residual intervals contain zero and satisfy + their declared exact-rational width gates. +- The transferred ground-state quartic interval contains the trial quartic + interval enlarged by the proved density-distance bound. +- The full plugin suite, plugin identity gate, capability drift gate, and live + acceptance remain green. +- The SPARK proof gate and runtime boundary tests both pass. + +## Reproduction commands + +```sh +python3 -B -m unittest tests.codex_plugin.test_hellgate -v +python3 -B -m unittest tests.codex_plugin.test_spark_interval -v +python3 -B -m unittest discover -s tests/codex_plugin -v +python3 -B plugins/jackel/scripts/verify_plugin.py +python3 -B tools/capability_drift_gate.py +proofs/spark/hellgate_interval/prove.sh +``` + +`tools/hellgate_trial_oracle.py` is an explicitly untrusted mpmath +differential path. Its high-precision values must land inside the bounded +exact-rational trial intervals, but agreement never upgrades the result. diff --git a/docs/superpowers/specs/2026-08-17-jackel-codex-plugin-design.md b/docs/superpowers/specs/2026-08-17-jackel-codex-plugin-design.md index 8e07f92..44bedb3 100644 --- a/docs/superpowers/specs/2026-08-17-jackel-codex-plugin-design.md +++ b/docs/superpowers/specs/2026-08-17-jackel-codex-plugin-design.md @@ -12,13 +12,17 @@ Current publication base: `c3ec10f5b446b28a04f9bd19606fc8b329ac43f5` The current v1.7.3 release exposes the ordered 41-tool catalog recorded in `release/capability_inventory_v1.json`, with tool-containing implementation ref `d25bcd9818e0d106f337798f80527ae611cc3acc`. The annotated tag, GitHub -release, package receipt, and downloaded asset must bind the same bytes. +release, package receipt, and downloaded asset must bind the same bytes. The +identity-pinned Codex wrapper adds seven THOTH measurement/provenance tools and +three CAS/graph/certificate tools plus seven STEM workflow tools, yielding one +unified 58-tool surface. THOTH is a named JACKAL subsystem and never a second +service or arithmetic authority. ## Objective Add a repo-local, publishable Codex plugin with migration-preserved package ID -`jackel` and public display name JACKAL. It exposes JACKAL's complete +`jackel` and public display name JACKAL + THOTH. It exposes JACKAL's complete mathematical evidence-kernel tool inventory on macOS. The plugin must make the full engine available without weakening JACKAL's epistemic classes, refusal semantics, checker boundaries, or pinned runtime identity. @@ -40,6 +44,15 @@ unsupported until JACKAL publishes and seals a corresponding runtime. general structured claims while retaining every exact, checked, estimated, bounded, formal-bounded, model-based, and verification lane. - Preserve backend JSON values losslessly as structured MCP output. +- Add one closed CAS router without changing the assurance of the delegated + runtime result. +- Render graph PNGs from delegated exact rational x coordinates and estimated + y samples while marking pixels and interpolation as visualization only. +- Replay the fixed HELLGATE nonlinear ground-state certificate only after an + independent identity-pinned exact-rational checker accepts it as `bounded`, + never `formal-bounded`. +- Name THOTH in the user-facing plugin while keeping it inside the single + JACKAL process and tool surface. - Keep named refusals first-class. A refusal is a valid epistemic result, not a reason to retry silently through a weaker lane. - Add complete Codex plugin metadata and a repo-local marketplace entry. @@ -51,15 +64,17 @@ unsupported until JACKAL publishes and seals a corresponding runtime. ## Non-goals -- Reimplementing any JACKAL calculation, proof checker, claim router, receipt - verifier, or bundle verifier. +- Reimplementing any sealed-runtime JACKAL calculation, proof checker, claim + router, receipt verifier, or bundle verifier. The wrapper's specialized + HELLGATE checker is separate identity-pinned code with an explicit theorem + assumption and never inherits the sealed runtime's formal status. - Copying `plugin/hermes` or any pinned runtime file into `plugins/jackel`. - Editing the load-bearing Hermes bundle, which would change its pinned bundle identity. - Presenting a checker-admitted formal fragment as whole-system formal assurance. -- Adding a hosted connector, `.app.json`, HTTP service, hooks, branding assets, - screenshots, or an automatic first-run download in version 0.1.0. +- Adding a hosted connector, `.app.json`, HTTP service, hooks, or an automatic + first-run download in version 0.1.0. - Supporting Linux, Windows, or Intel macOS in the initial release. ## Repository Layout @@ -73,7 +88,12 @@ plugins/jackel/ .mcp.json PLUGIN_IDENTITY.sha256 README.md + assets/jackal-thoth-hellgate-graph.png + mcp/advanced.py + mcp/hellgate_verify.py + mcp/measurement.py mcp/server.py + mcp/certificates/hellgate_v1.json.zlib scripts/launch_mcp.zsh scripts/provision_runtime.py scripts/verify_plugin.py @@ -94,7 +114,7 @@ backend. It locates a separately sealed runtime and invokes the unchanged - `name`: `jackel` - `version`: `0.1.0+codex.<14-digit timestamp>` -- `description`: `Expose JACKAL's claim-aware computation, domain-pack, and program-evidence kernel to Codex.` +- `description`: `Expose JACKAL's evidence-aware CAS, graphing, integrated THOTH measurement, nonlinear certificates, and program evidence to Codex.` - `author.name`: `Anubis Quantum Cipher` - `author.url`: `https://github.com/AnubisQuantumCipher` - `homepage` and `repository`: @@ -102,15 +122,23 @@ backend. It locates a separately sealed runtime and invokes the unchanged - `license`: `MIT` - `skills`: `./skills/` - `mcpServers`: `./.mcp.json` -- `interface.displayName`: `JACKAL` -- `interface.shortDescription`: `Claim-aware computation with explicit evidence classes` -- `interface.longDescription`: `Expose JACKAL's 41-tool v1.7.3 release runtime through Codex. The MCP adapter copies the parsed runtime result object into structuredContent unchanged; its only adapter-local tool result is status=refused reason=plugin-busy. Runtime result and assurance vocabulary: ok, exact, structural-exact, formal-bounded, bounded, checked, estimated, model-based, verified, verified-program-evidence, verified-program-receipt, indeterminate, and refused. Formal-bounded is limited to checker-admitted fragments; program evidence leaves construct-totality, source, and runtime residuals open. Requires Apple Silicon macOS and Python >=3.10 at /opt/homebrew/bin/python3 (install with brew install python).` +- `interface.displayName`: `JACKAL + THOTH` +- `interface.shortDescription`: `Evidence-aware CAS, graphing, and integrated measurement` +- `interface.longDescription`: names the unified 58-tool surface, THOTH's + in-process identity, delegated CAS semantics, the graph visualization + boundary, the HELLGATE `bounded` boundary, and the requirement to preserve + statuses, assumptions, identities, route traces, consequence ceilings, + refusals, and non-claims. - `interface.developerName`: `Anubis Quantum Cipher` - `interface.category`: `Productivity` - `interface.capabilities`: `["Interactive"]` - `interface.websiteURL`: `https://github.com/AnubisQuantumCipher/jackal` -- `keywords`: `jackel`, `mathematics`, `numerical-trust`, `formal-verification`, - `evidence`, `mcp` +- `interface.brandColor`: `#00E0B8` +- `interface.screenshots`: `./assets/jackal-thoth-hellgate-graph.png`, captured + from the installed `jackal_graph` tool and explicitly treated as estimated + visualization +- `keywords`: `jackel`, `thoth`, `mathematics`, `computer-algebra`, `graphing`, + `symbolic-algebra`, `numerical-trust`, `formal-verification`, `evidence`, `mcp` The short description identifies JACKAL as an evidence kernel, not a generic calculator. The long description names the mathematical, domain-pack, and @@ -121,10 +149,9 @@ rather than publishing broken paths or invented policies. Starter prompts: -1. `Classify and verify this numerical claim with JACKAL.` -2. `Find the strongest supported bound and refuse any silent downgrade.` -3. `Verify this receipt or claim bundle against my pinned expectations.` -4. `Verify this Anubis Safe program-evidence package without executing its artifact.` +1. `Use JACKAL + THOTH to solve and classify this calculation.` +2. `Graph this expression and separate visualization from evidence.` +3. `Replay the HELLGATE nonlinear ground-state certificate without promoting its assurance.` ## Marketplace Entry diff --git a/evals/mcp/jackal_stem_v1.xml b/evals/mcp/jackal_stem_v1.xml new file mode 100644 index 0000000..cb25e5c --- /dev/null +++ b/evals/mcp/jackal_stem_v1.xml @@ -0,0 +1,43 @@ + + + + Use the exact matrix workflow to solve A x = b for A = [[2,1],[5,3]] and b = [1,2]. Independently multiply A by the returned solution with the matrix workflow and require the product to equal b. Report only the second component of x as a reduced rational. + -1 + + + Fit the degree-two polynomial OLS model to x = [0,1,2,3] and y = [1,6,17,34]. Preserve the model-based wrapper status, then send the returned ascending exact coefficients through JACKAL exact arithmetic to evaluate the fitted polynomial at x = 5. Report only the exact predicted value. + 86 + + + Under the declared Binomial(n = 8, p = 1/3) model, obtain the exact CDF through k = 2. Use JACKAL exact arithmetic to take its complement, and independently check it by summing the exact PMFs from k = 3 through k = 8. Report only the reduced rational probability of more than two successes. + 1163/2187 + + + For k = 9 successes in n = 12 Bernoulli trials under p0 = 1/2, run both admitted one-sided exact-binomial hypothesis alternatives. Use JACKAL exact arithmetic to compare the two returned exact p-values. Report only the smaller reduced rational p-value; do not turn it into a decision about the null. + 299/4096 + + + Use the supplied-sensor linear-calibration workflow with sensor_id eval.sensor, channel A, quantity displacement, unit m, raw samples [1/2,3/2,5/2,7/2], scale 2, offset -1, source "fixed evaluation fixture", observed_at 2026-08-28T00:00:00Z, calibration_source "fixed affine fixture", and calibration_as_of 2026-08-28. Feed the returned calibrated samples into JACKAL descriptive statistics and compare the two population-variance fields with exact arithmetic. Report only the common reduced rational variance. + 5 + + + Run the circular-orbit model with mu = 398600441800000 and radius = 7000000, then run vis-viva with the same mu and radius and semi_major_axis = 7000000. Extract the exact square-root radicands from both delegation traces, subtract them with JACKAL exact arithmetic, and confirm that both scalar enclosures are formal-bounded with checker_rerun ACCEPT. Output True if the exact difference is zero and both checker conditions hold; otherwise output False. + True + + + Canonicalize x^2-4 through the CAS route, obtain its checked derivative, and open a linked workspace on [-4,4] with 17 samples. Inspect the embedded text/html resource whose digest matches the returned resource URI. Report only the short sentence in that resource that warns against treating the rendered geometry as proof, including its final period. + Pixels are not proof. + + + Replay the fixed hellgate-v1 ground-state certificate. From its displayed decimal eigenvalue interval, subtract the lower endpoint from the upper endpoint with JACKAL exact arithmetic, then use an exact algebraic sign check to compare that width with 1/500000000000. Output True only if the certificate status is bounded and the displayed width is strictly smaller; otherwise output False. + True + + + Differentiate V(x) = x^6-5*x^4+4*x^2, use exact polynomial equality to check the derivative against 2*x*(3*x^4-10*x^2+4), and isolate every distinct real root of that exact derivative polynomial. Report only the number of distinct real critical points. + 5 + + + Convert exactly 3 international statute miles to metres and exactly 2 international nautical miles to metres using the definitional conversion lane. Subtract the nautical-mile result from the statute-mile result with JACKAL exact arithmetic. Report only the reduced rational difference in metres. + 140504/125 + + diff --git a/plugins/jackel/.codex-plugin/plugin.json b/plugins/jackel/.codex-plugin/plugin.json index 746512c..44a1308 100644 --- a/plugins/jackel/.codex-plugin/plugin.json +++ b/plugins/jackel/.codex-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "jackel", - "version": "0.1.0+codex.20260820135554", - "description": "Expose JACKAL's claim-aware computation, domain-pack, and program-evidence kernel to Codex.", + "version": "0.1.0+codex.20260828140726", + "description": "Expose JACKAL's evidence-aware CAS, professional linked graphing, integrated THOTH measurement, matrices, statistical models, sensors, aerospace workflows, nonlinear certificates, and program evidence to Codex.", "author": { "name": "Anubis Quantum Cipher", "url": "https://github.com/AnubisQuantumCipher" @@ -11,7 +11,17 @@ "license": "MIT", "keywords": [ "jackel", + "thoth", "mathematics", + "computer-algebra", + "graphing", + "linked-views", + "matrices", + "regression", + "probability", + "sensors", + "aerospace", + "symbolic-algebra", "numerical-trust", "formal-verification", "evidence", @@ -20,20 +30,27 @@ "skills": "./skills/", "mcpServers": "./.mcp.json", "interface": { - "displayName": "JACKAL", - "shortDescription": "Claim-aware computation with explicit evidence classes", - "longDescription": "Expose JACKAL's 41-tool v1.7.3 release runtime through Codex. The MCP adapter copies the parsed runtime result object into structuredContent unchanged; its only adapter-local tool result is status=refused reason=plugin-busy. Runtime result and assurance vocabulary: ok, exact, structural-exact, formal-bounded, bounded, checked, estimated, model-based, verified, verified-program-evidence, verified-program-receipt, indeterminate, and refused. Formal-bounded is limited to checker-admitted fragments; program evidence leaves construct-totality, source, and runtime residuals open. Requires Apple Silicon macOS and Python >=3.10 at /opt/homebrew/bin/python3 (install with brew install python).", + "displayName": "JACKAL + THOTH", + "shortDescription": "Evidence-aware CAS, linked STEM views, and THOTH measurement", + "longDescription": "Expose one unified 58-tool JACKAL surface through Codex: the sealed 41-tool v1.7.3 release runtime, seven identity-pinned THOTH measurement/provenance tools, three identity-pinned CAS, graph, and nonlinear-certificate tools, and seven identity-pinned STEM workflows for matrices, regression, probability, hypothesis testing, supplied sensor batches, aerospace models, and a professional linked evidence workspace. THOTH is a named JACKAL subsystem, never a separate server or arithmetic authority. Every reported numeric field in the additive workflows delegates to an admitted JACKAL lane; wrapper orchestration and UI rendering add no mathematical assurance. The adapter copies each parsed sealed-runtime result object into structuredContent unchanged. For additive results it deep-copies the result and removes only the identity-validated _mcp_content transport envelope before returning structuredContent; its only transport-local refusal is status=refused reason=plugin-busy. Graph coordinates are exact rational JACKAL results, sampled values and pixels remain estimated visualization, and refused samples break the curve. The fixed HELLGATE lane replays an independent exact-rational certificate as bounded, never formal-bounded. Result vocabulary: ok, exact, exact-given, structural-exact, formal-bounded, bounded, checked, estimated, model-based, verified, verified-program-evidence, verified-program-receipt, indeterminate, refused. Field statuses, assumptions, identities, route traces, refusal reasons, consequence ceilings, and non-claims remain first-class. Requires a host-admitted pinned runtime and Python >=3.10 at a fixed launcher-approved path.", "developerName": "Anubis Quantum Cipher", "category": "Productivity", "capabilities": [ "Interactive" ], "websiteURL": "https://github.com/AnubisQuantumCipher/jackal", + "brandColor": "#00E0B8", + "screenshots": [ + "./assets/jackal-thoth-hellgate-graph.png", + "./assets/jackal-linked-evidence-workspace.png" + ], "defaultPrompt": [ - "Classify and verify this numerical claim with JACKAL.", - "Find the strongest supported bound and refuse any silent downgrade.", - "Verify this receipt or claim bundle against my pinned expectations.", - "Verify this Anubis Safe program-evidence package without executing its artifact." + "Use JACKAL + THOTH to solve and classify this calculation.", + "Graph this expression and separate visualization from evidence.", + "Open a linked symbolic, numeric, graph, table, and evidence workspace for this expression.", + "Solve this matrix or regression workflow while preserving exact fields and model assumptions.", + "Analyze this supplied sensor batch or aerospace model without upgrading its provenance or physical assumptions.", + "Replay the HELLGATE nonlinear ground-state certificate without promoting its assurance." ] } } diff --git a/plugins/jackel/PLUGIN_IDENTITY.sha256 b/plugins/jackel/PLUGIN_IDENTITY.sha256 index 7f3bcbc..9204620 100644 --- a/plugins/jackel/PLUGIN_IDENTITY.sha256 +++ b/plugins/jackel/PLUGIN_IDENTITY.sha256 @@ -1,9 +1,17 @@ -49bbd046759b045add1caf1f19300431fe7d697b59bfd93b57daf1d7edb709ff .codex-plugin/plugin.json +0a02d80c9dca90aa91d62c311d669392e485efe4f52987795ce0d3621b6669cf .codex-plugin/plugin.json a165e6b00292a3768ad134562539dabf7874cf23bf9ac8f80e893f7970a63cdc .mcp.json -13da0c677be5eb6161c21415fc280cbc07af9263f0356ebab77e715f0ef600d7 README.md -5ae164132f21a8dfd19a5ab0c679ccd3ccfc6e2c35ce4a6a6d2968cd550bc07a mcp/server.py +a68ca7ac13c45bbb503509902fe8f3e8379fc1454e05ef6f4bd85a1920ebe9e0 README.md +4179c34e62ff530c5d188a6143b740313a833f898774e269cb669a1f33cd0319 assets/jackal-linked-evidence-workspace.png +6bb4691420e3ae36398520ff9143e49073fe82bbcea3270f6766ccd0b109010a assets/jackal-thoth-hellgate-graph.png +c1d87448a8e87bc16911a228e62ae8d02527a2f9238dd38ef1fe2fd7a27b4e21 mcp/advanced.py +edfac51432ce8b5e0db09246b4b90e3dd7427d11c7f1f20cbcab9b28cfc8b27e mcp/certificates/README.md +e41ef05cb7ea6aae121a8a60330f52faf58e5827ee39adea3ef298ec4a873a88 mcp/certificates/hellgate_v1.json.zlib +5ce6683fcb259fc74047dbeb174d5e9fe633a2a6d57d121ad65bbf2c35da2b50 mcp/hellgate_verify.py +25a1abf4591cea5cc197d28cf8ef7e05191da31d63b60dc2439d1d945b27474f mcp/measurement.py +1fcc4c9793c6f36da5700674d07b5eeb202dd99209c419171f34174cd4d7f001 mcp/server.py +36f54651b7ddd4fe7ae6c05485766bc298ea9be5803600f0430e2d4d83c71041 mcp/stem.py e4fb2996fc2a905a5101974ad6119e6c29fbc10cc8ca2f0223e18f89686dcdff scripts/launch_mcp.sh 878a9d94788a6c132fad151bbddebecb41c08615fe310278e586871fe8f9c44c scripts/launch_mcp.zsh -b1cbd346b7f2a8c7708e5459c413bfb06e12238597fe4c09315a6210adbdc322 scripts/provision_runtime.py +bba7f8c80c4ba50a4affa41d891bdf4a987f7aa633be6f67af70a2113a4a31a2 scripts/provision_runtime.py 60f6a068c5f6bd81a2ab80e8d9d873864aefdf7f6ae7c2db37fe6572b41f898f scripts/verify_plugin.py -63f726fbde9e4484424388ef5af68dce92d7f55a4af9354e7d812833f090c972 skills/jackel/SKILL.md +b69ceb5a76018cb44ca63619bb81563a1e4e0e3bf215dae9ac896ff8c17821b5 skills/jackel/SKILL.md diff --git a/plugins/jackel/README.md b/plugins/jackel/README.md index f9ef5c8..e71322e 100644 --- a/plugins/jackel/README.md +++ b/plugins/jackel/README.md @@ -1,23 +1,51 @@ -# JACKAL for Codex (legacy package ID `jackel`) +# JACKAL + THOTH for Codex (legacy package ID `jackel`) This repo-local Codex plugin exposes the JACKAL v1.7.3 release runtime. The -installer supports Darwin/arm64 and Linux/aarch64; only the macOS-arm64 release -asset is published today, so Linux hosts must supply a locally built runtime and -its own pins. Its current source contract is the ordered 41-tool inventory in +provisioner recognizes Darwin/arm64, Linux/aarch64, and Linux/x86_64. macOS-arm64 +has a published asset; Linux/aarch64 has a host-specific pinned local build +installed with `--tarball`; Linux/x86_64 remains unpinned and refuses rather +than borrowing another host's bytes. Its sealed runtime contract is the ordered 41-tool inventory in `release/capability_inventory_v1.json`; the package receipt and downloaded -release asset must bind the same exact bytes. +release asset must bind the same exact bytes. The identity-pinned adapter adds +seven THOTH measurement/provenance tools and three CAS/graph/certificate +tools plus seven additive STEM workflow tools, producing one unified 58-tool +JACKAL MCP surface. THOTH is a named +JACKAL subsystem; there is no second entity, process, or measurement server. The MCP server is a transport adapter. It loads schemas from the admitted -runtime and copies each parsed runtime result into `structuredContent`. The -adapter's only local result is `status=refused reason=plugin-busy`; other -statuses and fields come from the runtime. +runtime and copies each parsed runtime result into `structuredContent`. For the +seven THOTH tools, it serially delegates every arithmetic step to that same +runtime and records the calls in `delegated_to`. `jackal_cas` is a closed +evidence-preserving router over the existing runtime lanes. `jackal_graph` +renders PNG output from exact rational delegated x coordinates and +`status=estimated` delegated y values; its pixels are never evidence and a +refused sample breaks the curve. `jackal_hellgate_ground_state` exposes a fixed +identity-pinned certificate only after an independent exact-rational checker +accepts it at startup as `status=bounded`, never `formal-bounded`. It also +returns subject-scoped trial diagnostics and a stated strong-convexity transfer +for only the true ground-state quartic norm and energy functional; trial moments +are never relabelled as ground-state moments. The adapter +also adds exact-field matrices, model-aware regression/probability/hypothesis +workflows, supplied-provenance sensor batches, assumption-carrying aerospace +models, and a professional linked HTML evidence workspace. Every reported +numeric field delegates to an admitted JACKAL lane. Python validates structure, +selects closed workflows, and renders views; it does not become a substitute +arithmetic authority. The adapter can also emit +`status=refused reason=plugin-busy`. + +The plugin-card screenshot is generated through the installed `jackal_graph` +tool from the HELLGATE potential. It is intentionally a visual demonstration, +not a certified statement about roots, extrema, or topology. The linked +workspace screenshot is generated by a fixed browser acceptance fixture; it is +a UI demonstration, not evidence for the plotted function or delegated status. ## Install and provision Add the JACKAL repository as a local marketplace, install `jackel@anubis-quantum-cipher`, and provision the pinned release runtime. The -default command downloads the fixed release asset; pass `--tarball` with an -absolute path for an offline installation: +default command downloads the fixed release asset when that host has a +published URL; pass `--tarball` with an absolute path for an offline or +host-local pinned installation: ```bash codex plugin marketplace add /absolute/path/to/jackal @@ -31,8 +59,10 @@ cd /absolute/path/to/the/installed/jackel/plugin codex mcp list --json ``` -Require exactly 41 unique JACKAL tool names and an MCP working directory bound -to the installed plugin copy. Python 3.10 or newer at +Require exactly 58 unique JACKAL tool names: 41 sealed-runtime tools, seven +identity-pinned THOTH tools, three identity-pinned advanced tools, and seven +identity-pinned STEM workflow tools. The MCP +working directory must be bound to the installed plugin copy. Python 3.10 or newer at `/opt/homebrew/bin/python3` (macOS) or `/usr/bin/python3` (Linux) is the supported prerequisite; the launcher accepts any of its three fixed absolute candidates that pass the full capability probe, which includes the host's @@ -46,6 +76,47 @@ atomic no-replace rename symbol. It never searches caller `PATH`. request and identity expectations. - Use direct typed tools for one exact, checked, estimated, bounded, formal-bounded, structural, or decision operation. +- Use `jackal_cas` as one front door for sealed exact, symbolic, numerical, + bounded, and formal lanes. Its nested delegated result remains authoritative; + the router adds no assurance and performs no downgrade. +- Use `jackal_graph` for a visual PNG. Treat every rendered segment as + visualization only and use a separate exact or bounded lane for any claim + about roots, extrema, continuity, poles, or behavior between samples. +- Use `jackal_hellgate_ground_state` only for `problem_id=hellgate-v1`. Its + exact-rational nonlinear Barta enclosure is `bounded` and carries explicit + theorem/interpreter assumptions. Trial quartic norm, moments, kinetic energy, + energy functional, identity residual, and virial residual are explicitly + scoped to the certificate trial `phi`. A separate strong-convexity transfer + encloses only the ground-state quartic norm and energy functional. It does not + enclose the ground-state polynomial moments, sensitivity derivative, + tunneling split, or Bogoliubov spectrum. +- Use `jackal_matrix` for exact-rational addition, multiplication, transpose, + determinant, RREF, inverse, and linear solve. Each numeric cell delegates to + `jackal_exact`; the identity-pinned row-operation orchestration is tested but + is not Lean-proved or `formal-bounded`. +- Use `jackal_regression`, `jackal_probability`, and `jackal_hypothesis` for + declared statistical models. Preserve top-level `model-based`, every model + assumption, each exact or estimated field status, and the advisory ceiling + on hypothesis results. Exact fitting never validates a model or sampling + design. +- Use `jackal_sensor` for caller-supplied batches and declared linear + calibration. It never claims to have read hardware. Preserve + `input_provenance=supplied`, calibration metadata, and the distinction + between exact-given descriptive fields and the nested formal-bounded + arithmetic enclosure. +- Use `jackal_aerospace` for the admitted circular-orbit, vis-viva, + rocket-equation, Hohmann-transfer, and plane-change models. Preserve their + physical assumptions and advisory ceiling. Formal-bounded scalar arithmetic + does not certify a mission or inherit the published finite-burn certificate. +- Use `jackal_linked_workspace` for synchronized symbolic, numeric, graph, + table, inspector, sensor-dock, and evidence-route views. Its self-contained + HTML is digest-bound and available through MCP resources. The UI, Web Serial + display, sampled curve, and pixels add no assurance. +- Use `jackal_convert`, `jackal_rate_apply`, `jackal_percent`, + `jackal_date_delta`, `jackal_stat`, `jackal_compare`, and `jackal_scan` for + THOTH measurement/provenance work. Preserve `exact-given` as exact arithmetic + conditional on the explicitly carried, unverified datum; `jackal_scan` is + lexical and verifies no numeral. - Use `jackal_anubis_verify_program` for caller-selected Safe source/evidence bytes, `jackal_anubis_verify_program_receipt` for receipt recomputation, and `jackal_anubis_check_program` only with the caller-pinned approved compiler. @@ -74,3 +145,9 @@ python3 -B -m unittest discover -s tests/codex_plugin -v The wrapper identity manifest is tamper evidence bound to a separately trusted Git revision or plugin snapshot. SHA-256 alone is not author authentication or mathematical proof. + +The repository also contains a separate SPARK fixed-scale interval envelope at +`proofs/spark/hellgate_interval`. GNATprove establishes its stated integer +contracts and absence of run-time errors. That proof is not integrated into the +cross-platform MCP start path and does not prove Barta, strong convexity, +Python refinement, compiler correctness, or mission qualification. diff --git a/plugins/jackel/assets/jackal-linked-evidence-workspace.png b/plugins/jackel/assets/jackal-linked-evidence-workspace.png new file mode 100644 index 0000000000000000000000000000000000000000..a8915f545e214ce6361b2e8e29249b2b27a79366 GIT binary patch literal 576566 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

fAVb`ARpIRwUicoqX{%^IHk%~s5L)W zI@CllGu^{1U1r|ub(R&X4MB{=9ibZjdkA=y+lxRmT;Ka#l&$D=%sYqx(XmET&y!h{ z{UcL?BzIEHxZDWPxJD)9r`W3tvw;hwyPhp>^csbkn%|+yXx`ToMvl@r*QZ$vKRD%@ z1!$+2UG5_BeHXAk{Ao?zA5dR#@=Ck#J(eL@$WLW-ea1DXbbLjTRo&6yPK`*W3y;$%sW%6Z{_XV~?fd^9**CjVyA?mZW}~ZrfT?+|*c6 zXGu}(69V9sHvX_w{k&|@YNx+sFq1&u^I@2wZsQaPdVl9&vY!5Cd{spMc-=lM z)?OiHTIxjCf9gWuHM*}B9aHRpRem1k@Pil5;W9?(nb?`hxY zM1(o(9!A^-JA8m!KAZ&^qLHgMa6cD9k;D^|e=Xw_EJK&??ejk^Al92@tB=r&AG2*F zkGjlK__7!+{H8vmMu2+8EvdHshwK{$t5jG=ny_kZ2dNn^GGKG)cZGF_fA^PZUrp#4 zBwSKqYa*pLQ`;6J@gl90RhvL0i67;w^qY~t?-0!;n1We>`sKA?$%rka9>dUR5=F3# zv?dl_e<4rz!>at$vzApd^e#*Ey6u{IQj-=s)5r%fxWs|g-BnpRUp*D@E;wT^qamt4@!Bt_*=hGe4+nTi;=};s1yJsilqIbCSQ&hdNPN7(~5uIWeaO-`dXXmrSJtNm(DW zh}Kvq*p{E>d>?MFJBEHfAn1+^JW5V)johb(kLBKwV&uG_q+{~Q!B!-+B+}rn{z95( z^uuyd^)F@inI$&3lQbX2 z7h$z}f~GWaHCH_c`EXEac@W>5R-Ck!8aR*@?5C(OPZzt|hU7SSVTInT_nTpv#3Hro zTYN>dYm_~!5N5(`9nS3c*A2g)-%T6_^c=_7jQe+!0!4v5TJ`TJdtj(5OQ=%=)amTz zQQJ8MK!8WD05OF=gzKnYOD_w{Yq5Wks`?%!jHc7{8v+!4`Yxb;KL7CmGe2?Sx1rvDxn z0vX%SR15N(!e7q*?E|-9#dgPw2wi4C&6v%tdtZ3s7lQb*{kaA85Q#7QUy=_4NuzVr zDK3}b<7srs`^a%(mMX2#X-CBw(b!!s7{ob^7D#^Q;ufYqBl|tHSYhy6kxa>V^gN=k z))|kCNYh}7JN)XOlnKx-LDOiQ67+XgOkEwx&$7-!th*9&O>d|FSPk;`d;4P5vn@L- zt-EThS64G8>rGzFdFXJpTnzUjd|dWkyQ%`pe)molEYi;EWrL$L5Kz6uSo zvUweKg@y8$=~lZVR(Dm#FL`eiAQ{Pr;01cRFSO`3p;b$-->pquWk2cKc^~Q4;R&Dp zy;2mr{eec|o^xp!O#&jbC1|%`Y3x>PNqqbGz1`G#V}Ex{ z*V0#N=Z2THZTO6b=sOWv81Id|85*v)lXKKw5(cM0S7gVAF1qagq-TsNX7!WNOOGu7 zRQ3Ua_u9h1tAS3~+f0Glgtha-k}Bm&arPV@;c>@G(UT_ItgWfN{SbQ-8zS9<{3*r`*~bUyl#0&-(nO!Ta14hg3p5WZglP;Pw$TQ{ z80?!Zx%^%wVSa>2tK%J+>+Ss`a3$R&079^B$()XOjP0!`7_Un`)ovg(dv2PkvRN7>2d7ohQF?^u0dSV{{9k}A)g942%qZ>ul1)q zdrFS@9>NJS2;Jlx_+!5zg&AXsFtIlzPaIGmw)M zHEAC(xD<=b_^322{-nU9^wt(p>YKIGwYO=ztTYX13%|q1WKh8SQ;2M zYaf?1Pitp>{(kd^^68QC>4H*hL2_BV+}expCi$V;d0yX5-*Kuyp_m=B)|-R!{iwjY z>rBb~*FYBr{K#--TPYu2C>JQA1zX_kpC>Aoi|>NVvgPZ4AT74#Q>}SU-V*MS9U(JiV%|Z&IyzR{2qQv%B32VE8uCcF-&b2h3Fiz3cIZtbBG!m-4`52$L-^ zcDBw6t0mBFfG+39+<9F-F?hPfyyI3oL<;Ip|6Z)h060ic_Jy(XN2D^ymMyO{pL`}} z-s07+t(|`#aq$WJNXAUDTtkbe3D{!kgf*d-`+ynBoBx{YN2>v<@~4Q7vyk$q-oNMz zZmL~(Zhzi3mr~^jlMlTxKOq7E5X{S&oUlJ6fbfU!E%cHwkdxOrD(ZQKf$THosLb4l zn%Oos%WzR-XYg*Iv7y4SK~J@1lKeoq^Q}zxi4VKj#Qv_L?L{kJc^TRtcJQh^un5YRpJU}$|WU$mda z+oqPq5~$3~@T477ZHg*CmxdB^I#vvlc6DR4f%?24+xPe2?I zm24$1cD^M+9yAHRhgsSxnv!eit&}&iy6m7C-kTvVA z4>64_DENU_HCxWZ*h-&!=s_9F2{4FX4DNqKBZcIz4Ze;1%D+m!b+D&5wHY#EHBk!<=N^>&^oKE6*B`N^T<-Xm`pVWSZ?PmMHo(8s zBKO43|H1VUs!+>vKlS*gqJj+h4XX|VVcjJ+iReiXUbg#pk(!F^du<_6mL>%t-J}Qs z$mgzM&~%Pk%9*_vn2MFat0ALxN<3T-|uTw#nYL}xMTld`O4*Arf zUNSt-ap3yg(5@TlIu5B61HHz_O`4}=1zN+`92-Jn7G(h9=){aL+$o`+{~T2W!Y3B> z#flTUnUA9&=96U#08sF3(1-`AI>grcnsuXt$Kd_zy7n@rD;PR>ikazJ3wBSX^DQxn%xdG5w2{Rw-y&`RB<*bId97#Xpn?jj&g}Ypvu(G2=+b#%)!r5_8SjV zZIxa^AGzj(Apk4{dWjC_6Zw`~DR@Ef4&J=Hz z8NYX7&6OU3c%NrekT({N5^mEq+qaOq3pqOa%542H8zrPggs{arMrLREJ=ZK3rY0-L z|FnPw#|;S2oAQ|8LlRP8bkCcS?zQxm2tSet?|CNoShv_GqTLJd!{Iw3KT%)friWzs zTi)8_i9ublQ|9TdmWG1OozZyI2U?K;xEo=4*89UQ=lRly3B|MYOyZ*>gH%eZWIpfR zxoLxx&H?vdJ4Nq=u6iHbPKQ4j^~TFs4cx4veDI;+V~E|$vJpc$r?HjboC7trMq7+W zhTmH?*N`6bwL)GbSDhp8lk$w2+MTLL2h-Q^ktt@JWl31Bs10vf;ksY&`t^-7F7f1$ z8sK~+9Q;f5-t$x-AwR)pEs;DCd#O+<1V#-bu43ok7 zFmf&JAQ~1KP9Z{pH>WZ#Sf-jyoDUh4{>^8g_`PZB`>vVChV{0M-mQ;hW}4nH&C!$t zA~@=bd<5Jv&QCL>Bh$xuDYRE};S<}HAN$o}>;M+(tRJaS}WQH(lPJHyz=jMdfS|=H! zt9o}pe4)=>>Aux`Md)is0=5)YZG%?}Mb+Card>I*w~A6~9hV6GbjFi)(rvPLc2>y->qwDe_pCSrUl8&Wp)1S6rya4#_`SZ%lHoKDp6C^tb&p3*sa3=jxC8kGyD_^QmtQNQGsD&~?uOi)#&D+^Ok~p6f z+oby9XmI;QA2C5+*e~80f2+}hag6@u9qgU|Xa&ZMC@4oTHEMY)Qar`hkt?$;=l1nt zIR9;*vhIODuXqDBJ~bUCUVM|ATn?dvYaCbsaEY$G>cP2DJiS1|IIs*6`;Jp~G^r{(9c!FIv-UIyG(wJ56j z$fJ~TdLf6B#nfnQ&RyMt6!iymH32QCBly=ajw7m$SXoq)we`tgiJ$v3FNBp67&tnv zx}?`Ux~#=L>=RR6M{0;@(%@a!#U{ku5}%ix*Pem-yo^${7d`lF$uiFVl`Cqt@uIjX zHdh&$?Kj*`N#6-Dldmrd^IaD--8UC^T%R50su)!S*(Gk<1<{JP+Qc6Ip6TBCNRXg1%_K|3$)F^j0cIx_dZqRRZ#5T2HG9;JdiG93;Vtq-H z>2;%au{5jSl#Y`exrf{A8a0l_d%(QSc3`JZqIi-X{KyAowh(kbxqYtj_j+X6H@C7stnl_9p8I7Q)TJO&5*^teA-2*2tD}E2>Yu{V*y+2mTpYVf#R` zTajz{JZpCVC9sR*KwNxgjr>cR9c%^MooY)T8Q*BL8ou%~kfe=Qw1ff{LyT-(H>72J zaIt>|ePA95@Z}vHdsu%ebR<_GMs8b1V>DT}K9%EXYyDz?&KaUY-yW4jsgWWldwxhC-M4=Ym zmng)3`kBHy{nkwA%IE`O1+UXU!JG0ghy{(yYd-HwvuTu3g|o~|!Q!RDjwf?W2q2d_ z?`tdVc9}3v`994|9pJ4`xY}5$9)-EcS(AupX^0$bH0l4?C3q;V<8n#aX)jm^$Ze&7 zl_B(Ag>p!kFjG?CE6Rjw6iC@*idIuV-@<_3+ZeL zYs7@E^;pf6HIF8I7DM?R-ev^d1l0>rijnN!)~;f9?!n!^J1#>HfocPv2gaM+d`2#F ztw}ZC{h&}JyhLU**9yweXvsJ7Ug4#(U%qK~28^EVrk zOyj&cC#)Arxbo$b?>Uor>g}IIQ$wMdedDyxe+)P(=j84T_J1iae=I}?oT&9b{M4Kn z@?BEN)+|pgDOz2x7LvVdL79&RS%#L=>x1D7{LeqgNX1&QdFYwTtZnqekSN@w$KR9l zQIHuDEqqVWL2J~E9mzRrtT;KQSZJXHu1s9tlA$J6Sf5=E?$rp=K4V7+dbpvnWsdh# zUwBn+MNz)-C5@Fm#tLB2?J~ARqRWzrh0Ow0zIuytO|o+8Lrhbt8w8dyQ0s_mE~+TC z0je|=L1*b*togx4xVZXos8dQLn(UJ}S0}6ez{#P^LQa)k0cNM&Z9t}ah#ia`K&GKU zJABE|F*WU+6QKtK;sBv_|5gkfUc7a7X8l(qnJmxcSolX|EdQ{xu5qinJ(Cgt z!A{w3<#ve-7L(8xlVGI0^fH_Ol7)kth;vzwe#{&Taf!w*Dkf(`51wduf3xK1Gh|%I zzUVdkxmsIj8Xl^j-;Q`bIXkvQ9MFO&^)htvJBAD0=4jTkmTlHVq0Y7BfRj9#B5O5M z7-J&Ku^9=qD|C5|j7;y<_&+OmZ#&VTz-180!K4guhVt6K41NV|%-3uX=rnexp}#|E zJI8i?W7oR<(zmHo>OqUYtk8|PU`s`F>`{di4NrtvsWBto-!Xr6)~*0 ztinL~X?^oZ0C1=hGBFyw7yMVG8S+)~7UJh#{w^t_yRxEKfFy>l5O4m~O9gD z*`lG;1!&x*K9^f+9&4&Ep4FSIo5Ty)IU6m_pKrA}#!eDrNOMq$0Ce*2V8G%1K01v? za4BzKa5ohd1H8Rr)JPWdO^(p-=Q?k&IDh8$xRR@4f0IdeE3y1p&w5HJ zI1*2Ym1y*wt0_%VvuPp&e&JWAGhq+j&i&bx+#@*66|X=b zvnr`_^LVP|niPyxcE*p2e3ZX0y^!=r%}ToGkU3nsykDD-ESor}nu<)3^Hs!Jw>W9? z7eB(wj^|NLmb6e5XKZBk#YKs(fqIH_r|CX)E_|zAOCMVZ3zIVYI=U-98Q2mil~w+gt26YI@BQ0X9i;2t z+ z!`iPs8p8}1T_`x>Ua(ztpUCGHj@FTPzryxqf+-75RJsrGXS@}+07lzp&_Q^<^blV( z{M%9MO98ewRtpHE{io&_U4G2{ir)it$7yfta+%y#vz=2LU_gbAuT8XWUU~6xQab!_ zeAd$6<`2{XCxQT7JvV>CvM3@_D4{|D`;F3I9XiBX z31hKjL0Gr84g{E>x)%O844%9qZ;XfTkSgttFm)L_`CT3$)lgO|LuxX_wu-6O$RK%I7olHEgU7>H*ZyAIV)|xK5gzaDj5!C`- z;l9Po#3>kj*ISOZFpiwc-)<>?hhe{rvCG{O|EC2Mt$6tUmRsZEU!+XYd6O`#XB>ItadTr#TQ_oDwO_~oH& z!pxNumACZCiXoSNX1lRVY$^C=v@x_%km;!+Ya-A~GgcL?woYdcI@CN!<(H1Lz7seM z{<14X$@mTDx#6Y1vzP=#OhR7_NoXDe5gz4(@_rOg?%tF|mI~m@Ri@NbGV~teEZ(8~ z&=OV8T6mdUyFx{)PftHbbFk>meA#W}Q1EpF3iCo@r<@s$!z_EPHTO-pSXI+Q3aQ^s zI=L453*7>rcirD7tKbl&87?`GTzfKMnnG+;&WmCd2aX zWdb}Z!x}z?mFT~*JC7uE7rarQA|Cl(YW6NoUhr1)bcFPb8U%V3R(Hx;CcW2_rx9#; z#sB)Z74eHymuUQaA~@c^G_ol@Wq=`LG9Rsl zg*=xTM?;}2tsat3Pw!aIuXVz4wS~0XhV1GhJz%0p8(C#h=1yj)t6fxRyW`IL+)&?ER1E5ELWY=kKRLd=OFL4ojsC61^(sZ)lC^)y_{!EO zw<%=G<&wp1FS&KF(c{!SCt*(*4*n?gGnjb#dJuG4UA#!Tdnpz&n!I~ky_8v$p0aYK z$!Pnsug+>R5^1x3o65pzc6Dip6wLATj9W3`Z_5`>4l#_)>yIl^BrNGHUnfv|a_nSg z$B_qPDkC&juPjdSgraKKTUzZqxv zNA`k0@a}g%7Kg`2GOb$@=Q~V0jKE4Qt5pi0qtEyQQmRvkUD18B1jpyeN4p6iMT-78KRMr5?3MkHy*CKjvc&~ViPaYKZwDjUk@o*M z?{5$m25;iyq@&3M4>*}3C#!!8HP(w;@ITVSo zvrIJ#JD(MO4NG@}@$(U=POuKCl{003-BxYvGqeXcQMf01^S0^jr#b&t3z3TwQo>68 zcN6AYMYahYq}pZK8Sad+9n{PCkzEj0sC*j5((8OgTq$w(Mh^BVUzV*gciGJ&62=)4 z^T@S&gCzII_ciAJ$*lTf<{IM2c&xOgjsqIk)wZYHNS371Rjyy|q6-HCG#8JnTiCyc zs(+b#6@Dx>qo38vURzGD2$kP8GZWJqPM6JN_!_dq2ernRPWMOv2BCgF%DJ{6Vw5xt zlTO~x1b)|tVo09c5-_ddliBtrvldGI7CEfs96dDEet9&m)h<*`hDt(zlOxe4MqEiJujf)6v_%aQS~UU3E~K-P46q zpv7H-v_OGU+=9Clw*oB`hvM!MthlvBi%YTM#Wg^H;O-8=EjR@I@_sYFe>0QkncVEX z_w3oTXL%uHH+o9yY**9HgJ}npGAhXcqq=lpQw`FLbuZOrENypm8^xD&O$B3xK9bPlr#gHmcKT3T7Sfvb#A$L8D6zM?|jj;!QR?=i7`BviVG6 zY~w9|>Q9wY{pTrbTBIXk3SxD*-`q7*U%CTLAwV~)BC{pMg(Ng;9~-II;_HcCNc~`aByVZD((1eWbqd zita@xC~`{-_{2_dE#V9AP{+rmWQr;7mo;}8w7lrH=bcu6i8oOuy)-*Jj(%TPkP{_b|wR_)l%d4*Evu&MrtP(}{Vc8-xpFHhvP4ig|;7+Ee<-?SJm_l%4tGtZ6RT7ypC<oX+xC8H*PVb#H!VOp&Hsw`Go*nq%;inGGD4W9-Aye&|qD%q5 z1U%>?z6$x6H$GHs_!9T-i+-X32`tFoJ3U z+6R~v`4;OF;uzrox zOi?lhpdDn>M8Rp_q@0aeM8{I>x@BO_96l^f&T`({^thl9sHShBp2-$|A*39K-&1C2 zb<8Kv^CkVo=TnQa=yi*?t}5j_z`Dea#6&bHBFN-hOn28#6}%5jNsNE&u?y@=2Hw$` z2RQ3MPu1Q6`@Zi8zPh3{8qTLqsv48?;0yaFFD6UuY`;-*RY_%Y%rs0!gK;MPQV96L z^;OjZIo|?Q+VE?h^Y>YbZ3Lqie>taQZvDjK$s*!cXn}8*>N#;VDOH4Y5C9t;8WAgS z)~dPJ84;_Sla0F>--05L5iBdd<3H|G-tv8XVGS=K2R|PF>#c!61^w~LoFQoGfX&f- zMEJB9YOp3^H@X@1Ic6OcXcCU8HR#N+{e+p=MxE;;c=VyfiPv{(a^Xvhy3!wE9GSwO zvj~EP;saL)V7XuEcT-3Qu_=y&kKp+BV#(HAE+beTH6^3ql!UPvm2Yb<$QFdFE@UL* zDay)E)fPPysF{|)Fdeo{zz*npAHNE^&ZB6+tEP^(QYFUFGfvN7@cr_L6dU5MLT@+_WYaVDF(}yrF*zCrYH#q^qJxYhLoyI1-y9wxF7zX-Gsy|@Rri1O)n7RF zGHsZ5Gee6rb2b9!oi^;^7e{P9cornBtBs&QCvfN?Fp+f90P97^cb%s%4p(!AH9Eic zv^n&w`NwK-XT7A+Ly^QvrhX=fkoZluBqmKxl*L$zud!?Q11EjLTU(D~Ptr+?iNO`S zolirsb~cl0LrkMj?8QG7V&QrmaGlM&0cUI;lf*XT%eCCIES!NmKb|FlHneD!$cqms zr^}0(EQ1^5(?^)}`q6K-nBI12XztS+K550l_!&LpDIzH1PSxyLlhVCp=_-6j#I>XT4UWf*pAJH^xUon)_bxJvtg& z&<4>bCPjD25oKuAqePnH?R9ZrZo{jtPPO`ee9I5>3yFo^a?=*9lJBkmQQJk$tnB2( zpJQ$ATibda`+sIBGfHg?4Dvtt#0z$%5IJ4C`-4X!e43Z1z^GV|`o+awER@@dLS$2l zL>Q)4m$};JF+`)=IwXEk*5Tiv!jY}-dSv|6+o3=s@l9&2o;$FW$yowe!h52~4TpC5gm=|ZIcL4|&@cs>dD?Bx^yQl~QYF+Ty{)1F5{Jl{!=hG^eiSM-omUC0##mvcE zkZ8ot5vUNrfc<8Io#uHO#09}VZQ=T-WCatP%IuXrc8qB_LrNWI#1e`jaf_*(A-q`i z6qxIO80x>UEx(Vtd&kwq8YZ9;FRkQbAMu`6_Kg|!cK}lY>xKIdySK09?JNp$R=GVH zdZw)b3Y|I!dJV613P0skX*f!yB!rq}yywq;^`_4;vZ0_LtT);H)8PNO053@gfI=$j z>+n1--Ar0OzM|1IoNpw&%ktb1wTstOUu3JsFYdU*f#143?`f{8&2#Sc+Pli;g%|uz z{(-J>2Nr8>rW_OvWNuO}DHxmL)Lo!VK90Yge~JA%K>T5nhS1zPGKE@ui(5Sm2K}rX zA&Z{*OphaH3c$@>k}~h5v1$E{0>Li#3v^Am;$1qRP_}d@s#_*p87YVvr$h`V;L4J( zp|*8lIF|EvEK9(K%Hu2)VVDa0eIIGk)%8=F(Xox+#hL)s1U>?I{slP!1xy0Kz}TOr zTq*?jUqV=f$ZI=^Kdt}vqH4{1A%j9{(79fdM6>;sOWW!*>*jo1H`I}S>4ilNb;yLp z3l7gv<6dD-`fpOuPmJna&Tlbi=v`fNg@tlc(PYP7wkV|lkwz&AWob?%*|2J?q#U`D zCJlSxP8+e9@k55O;lkQV6T6pc%xu1jl~LbsxPO19enZ|W#i*S;y-6y(bo=FYQ!EvLi2oxfZv9@d+K`z0 zUg{E$Vpc5~pWR>Ko<~odA_tITd;4)^;RhYU|Zeis(>0W$*fz}EFee&Mrc zADTLQSk2~TXCAj_Uy1(l8HqM-5pqdzgt9YRFUl8Uu7P`L5$Tq572^yVsXFofN?hPVFmpSDpsZ^(?_B(?d&GcqwXkJJ zrQFN@txo1iF{Miy($sK%xICqsvuvx#)!FR4Z1O+7w(U`fAsgmTu8_v%!y&xne{=n) zTv0F-7y4Y&8O(@}neW4!2ai#MRado?bIN9t5A*upEN8guV2;!iB3@Yp7RcI0N>02c zmy45n0I;U?{c-J_XFQ(W^4@$G#jeAwT2JxbAAauY&_rE{7a#rxQjz8MU*PQ@(53C* z^^)fpp>b#pe;u!;(2AuD|H<8zGD7VH8)SL+&a?TVzcel*@G&bP^Ja|`apfhxm^ew7 z^HW||2jIi$9c|JiuJ=qocU0s}{A_65Oz<_9!p{=L{dn=tJZQ&?W%{~# zC;4>V>EmkLq;miWcX}SzW4griV|Xv$9L5L`EFUdXhaUbw^&t1!O-YtKX2XT30QHwT ziGAaX1a8QYOcXa&JTmBh9ew1%V{`$G+A4OGe=Lvc$E*;6`Psu_sDsNMgkwF@+^2ay z#GvG+7)@XG9H0f_QZOIOf7H?LE9e=l4GxCNuv$c;Zr%M0`JBifAFAh|^fg9TOx@3< zRz$SHA3*=~QyTX79EjIzatE)jv+m=91s5}f>5A5deyKr18SLIKvHTR;I9c2}F5Grq zn=*coS(%)3LD?w*`{ay$v1J)M+=_jg|0Gd&I z-@kEcxBixyI~prV%oVR*2x6Rn{3#$`svQSS1LRm>y(Tahyu<${j_+!7B)@f7yV=8Q zro>b<`~9kZ>jQRl3i_6hpoY<}e7422k&sj5@mH}m{GLQ+xb;m<1`?LNP&F5nJhD?c zcl>V5Dqrot?Z0My<%}Wc>RQs{I6V-ogO@gdswE^@0g!znC^PtqeYBF>iKE+AVnb;z z_yI28`S{NcfSE5&-unuhA{L*e<26EJQKZCHNiwV>t;hOQIht5*a47AH{nfOYpd?qd zK_oXzN_Q}yXFqrjW4B>tqC#?6?V<*&GA9SV?%^ig7yp z_-&taEF+Eoeovv@WJ1layg8sZzc-?){X(m$iVi4Bqe-lZ(M{31QS!NjokS~U)>>C? zT*Xo^@(We1Js0}lk*c4YJPXW)!QuTeU!v3PWXy%lV&#)tB603PjD6N53!jl)CV`k1 zE`Yehve4PDY}`~e@#%;l@gg(_U!%gLEXzV(H(P70dT@n7?VhZ5mOwygm($yKF?AtD z$}yfyc&YtYvG)NyP(x>oxXk>q96YUq$YiC;IMH~Br*e&B+OLylCDt{t0@wYErgd9Q;2?8v^N2YaF@8rL*dMmWDNt9G@7^{)mcW&v}oltj5dql_Fe0L_eqQ za7$C{`?aeru1GidncP?&^4jwNS}d_gPo-3@IN#G$Kt9fLONEPkwqTfYp<5vduvX#~ zqzmVEhN``R-0W~m_u_m-Yxgz@y)3eEL!B00G&ypN7uGCZ6~^OD6lu1p11Ubn6#B*b`Lm5L@@q5M9_ zuwFr^M|Wo%B?|B-rN@23lJ{)v`;ye9Ho`luhj2IB&fe=rLu)KzD*$CHYzsebP9va( z3>9TBEOJ&>R^K9qV6kUfjEwHxm>e_av_a^~SawUcGYWdwK|_t^8_i9vWc~23$dFpTIp?pT&j#Q8HRJ5v9U9kE&f6u2P{d$lSn6v!0G;spki0nGSpjQT zle>S^4gm<~J+)%}j~^RqWR$To`>iy5L`8THWYJva7kR(Cfp>{#*Ss*%7QJC0n`HL) zlf2j!$(=rqtgO;Fz#T0O6eVA?crJGtGjA{fKXNiIF_16E`O^F}y)E9!q5$w^G|cu0 zBM7>MST`qoJ8J~+9}cPT=GxhJ&H0fO$!HXc9@MQc{`ynT)3fIAzNnBcdIV~ZH*VJ( zFotCf^`HXz!ka`#yj?Dl{?tYt%ojcLar#ztt%PlqTAl}tm_MKz?=VYJ(RzLw90oH` zj=y`s=&35v`CDTXs5BGN@i7)KLbwUUspYyK>$)}UN;{za11CTfJ(Da+v+z{6hOG(2 ztq|Db3B70z<`<9HZr%cLY)IJBCEgxxHPaVyHhU_}B6D>)9!fL`Zo7hV;Ob5|#r6Pm z*9~LMRvI*z_Ff`4VXorW5%mSxvGMR1l$-Nli1{%r9Kt6l<1j|D%8qW~?7}CEJK+4L z#GL3l|E0=hNgwC%Umg!XNjqJ`0TqOb2h?Q*CLe^4mK^y}R?(3Sp-4y~m zYR0!R+>tc+I-xP|aAJG!QQpWi+>!?g#RltXY`6Y;>9?jp2sY5{xJl4KB$-)vT_tt8 zynP2{{{IlhAH582uzNo@r=iI8%Ja_rX*sf&KAj2LTs}xjpVQc1s zqMk?Lo)Q+~;T%oTZ>mj`l+_?}`{OttcNVKh&$>xkxhxg*5_5J77K9}SSxm`VdL2-E zxq{Yd0+Ra$F;l#qcec7UA~L8hwypmCB>7h^%1D!6-dsOZV;j;_j(*Xwl)B~|K#_fJ zY6od)Ey-ML+qWX3D@+sT?FyP`ebZ#!!}WsW;C7Ok&2a~_JfP|N;I#x?sk0vHtHK%{ z&Rs(T8765*bpGU;Ju5x250enTFtsMco5_i7%%R+!Xg9Os*o)l$xJ5e%#KM|UL^Hrm z!PBkc#($&1H%X7I0UE>c!Yf`%P8c6@FX(Wq6w+YS-@ctiQ1|Vdg}nLdNDhGdkKA-U zH?F33iu?WeEy!mElByv39{I`LW&u4_4X}G0WzOIWL2M4&I4l? z(7Wj3BMmU7NekvzrHtcqu#>&$Aw*rWw6!*RqB~7r)xA48=(Q=_bJX&hExNJ)QOV)Z z4%JrtmWqBOu2)lHZ}0Wh<)_Mk?K_*RDFH{80m;{tj>mrQk?H!k_=;le!q;x^*I&i| z!z<|VVsYH$#pv3*y?c;X89|b#OITBvJ8_Nn`fj`I;MVgX^PJmq!K@qRz^4YFM{w>#NZ1z_I(x6V zan2z3+n2qCE__BZx@}=->*tOp2CKM3oCKMh|J0R+>$}8XteC$YYJDTK+i6J6qsPe= zwereR-Jc*@6KwB=;6E3o5;sCCA-m|zb=hYPCmS|O#=xP(;0;9rBla~FCathRL|jvf zG%kk0S|wCJqV(M?L(LtLp+oTE2SWfRV_tfQa>QqLLro#i0=`(hB{Go~PhuD_1S;$5 zcIv!WLs`nhWl%O@O+%EJD=2loM?tE!}tR*=Vc@>mW}w9|DN{EnmaL%ORb=zwB8@)Kl& zMb$b18GDKWH$9{uBHM`8A9i|| zUATP5@eAv7e7KszYuY$UQ!_C1;;H<@2bD-azm%2unpLO7TsnZn3_K6Efpk1dng>=Q6=DYz;Ad3`sbQAQe{R+0sM>8>KhsNo4gC zTM3d7li&O=Wx~699U0U9o>Aqo@gB7^6To;dHU|UfArpy(9T`{>eeU{V(r92puOcp# zL#igI@S+HyqT;SWww?s{qKu)%v~B9;Q}39? z$oY#Q0;r}uP9dl)WRk;{t2r$`SD9++XP--~${Wad@Y-=F-a{S8#apR9=>Q=)j%4Y= zM%OlSqdvPGKPLD?h-bx}_wNGqt})72t7oX&Dm%8GL1z`}8qGeiK2lA(AW`Hl^j&^b ziWEnmFy&F*;o$5Vj~~L(4jTjEI*15WzQ$otTr7o*4<{Um#BMV|he=xYt#$VVo;2J6 zJ2DJm8@)oSpq*@S`I5A}_bBfv9xM7;EGX=Y7-Xoa)^@5#G52oQOJEs2AH&q6!}3j{ z!Mjd6iUk5BLpZ8jzz+`E@7yNU?wP?pqjScH8%{Ae^{()5MR*L)`GrX26_sOTNmUe4 zg^97ocLN>Sn|9I=7Uy zmW@ApkEd)Bh7+*NTWIT8me^TSATV&i2%FAxT1_0tDL6`tV*C-%Jjx>b&o{;RRYQ!-(GRANBfL-K6 z`ijAq#eia=sY3MAT=5uy)o*O$_qaU)=tn(oU7J#>%s(`uyVr8p$*VZ%V<;hqpnB{4 zcf$HRpHcDazXcLS^HcD~Ld-i+DTK}E$(p`B*&DXH`}z(gONi}e(D}gO8?&;zrsnnC)VO7{eK&2P!*>m0T%$Yj^C@(m&8h?|2rH#H-!GW#1F^M433{SDu0RQrW*k#Nyf^+=@5{H8 zQ^$-lj;u;Oj9-LN;66+#NL(xL`oq3~TP_3W?y6|K7KI*O8YDp1W?I;5(#jIw>2^j^CMoY6q(L zE%N4^A*wPT%h;;!y7jA@Z1RWAZgtR8 zIs9>tc}?h9A@GSjkkSZ{gZvg~gYDb%-C!Bm`+6=1QU1-%lwRn@a?UhQi>bt?*7c8p|DfpL7F7n3o{t#TF&2;J zE8!J#&wFbp^D>RkBm89o4y<0wAWyiJ7$&qbW_P*9_E5@?v(4^G*CaKYD(<`fKYnVfC{l1tG(MYRdXj>-46}q1W3^! zV_{I~3!Tg}*7M-E#@yhH)4XK$cy;qFb*HbbJ}~w!)Q@HGHXno@r?Fq0#TxK(n|XL8 z;O7C?u(AIuvf7Pokrw=Ee)A>zWlgqbYSs@h47T>lL#p~@BVOz)yXRcAwl6GR#dkfH%d@Ax!<#CIwHMh80@YO3#_2smkHP0g z9a#xzl`(!&d@{cxZCtrbR-Rk-;58`E5L{K!KKu|*#NDTpA5(SI9U)3PmBS8@_fq|7 zxYnnzoe0xN9)P{46tft2CKbJ`&--R_>#m(z0>RMJ0OTo47a_*Jar2o(83p;LObY%m zYY&HRt=4)Ow!vD}1J-8rjLvf4-uGP*fa}FMaE+JiZkE>*bgsj3f6{L4%;{M;@F^q^ z1k3PERU1uj9}~X^oelFoA8ipg8n@jt1>Q`~%hd8|JUg{>$}Ritu|4hcgWHcLBg9YB z=s@sR=In*jA+i@aacVt6 z!n@1u>7lPw}Iz z{&Uj`_FEXjli2LX&%9fO`yaOLir!SIiSAqAf%YE%X683OK}Cv+i`SlJ1#fOFY5)NH zi6Nb@T&d{}bfpT4)!uD5iKSKt-KWAvWoWu{x}Fgp7Oy_4K`NBvELnb?q!~TxMX=u= z4A9-D!a}@#@#1F`XsaLd?%D6I>dUr>iuG9IIq%cK!bjn?>QA>|(U%Ks&}b2jWCF?f-ea<&c4W>%<0YioreJ>#(dGk z$e~j@zumo=E6ACud#3p5HW=Rot%OXC>g~;M!R8ap-pE2Vb1wp(glj(&O#pPb$A$KI9p~pKW1u@J$&op0JTU zMOPIsdQgJ6*bTgnRsZVJ>y+TL9vUCePj_|ecicX05P4F7a~L$*Z~O#gy+6f!3;MoWE9zn7yW;U5DDZ>VjyVPTAw*X1szg;6 z9d1@~&dR@4sjwmb#|7Lxow1X_n_z>HBSH1R9p2p$q}4Y}{>cZv zQh9s4{ruF>cz#dkF^mTCTd*{~>;4==4xhgexm0q7Ocu81I4w7w@#frFz)K|_2NH@0 zZ8*H@jNS3-rZ`#+5ld@NaAfKfoh1}5w`*k8i}r`sih3ptUwAAWSQkk& z;GlzR7?VhpSCTs`^31A#iK^l@J<-LlxZ}ESybPa}c_Msz+HB8hKL|y(@1uuzsVM${~kH*F=DejxE@AzOx%~Q)Op6NFb;}tRzs6)Q; zT^3ds_0#=73BN5P@~3MK4(J4?!%ZaS@nY*j^pYUxez$QMbW;?1^Z6Fxw02nzJ-J#s zocr-gI-R*sD}DH-LGL`jJSygCj6UTuCNT4Y|E1(JMPCVZUV&p5L}R#G%V-XFlMNCp zZO*3z)9!!${*0=dGfq9e%7v^CbA=Uh%N3~}&v~5)n`+p(;j@LL+vV=|y?U|e54}4S zzjSj%iNRal?j)BWxlGG!U&)la?-cW0KSfr`lCDt|6E9i|lk8n|S%!G=;^^D;wv+)8 zo~8m@>4JY~TRkL@%C^{h<_vSee{Ix&dd&J!m2toPUt*?#Wf*`K0i?u$FLtp*KiZ>7WI{@_)G1TE2^5jy7tbX7jWRtx6NBR_ z*tfY1g=7yD5|Kw23OfX47;2hD-4*b2BBx>$vB3VUc2zbxMZ26OwO`GO23P#+elq zB{bF<^ZrvwWa`!&bA5~}teYA7bZ5Fm^N$T?CvjO@`YEGXf!)RzmTsqCXR1cmk%p$) z1vo2tSY(?xtIy(D+n^E`68G4+vDx4fP7ma?@h?ti$2CU@lRvDk&3_)sSoNO$Y^>km zk3Rfht$RYLY1<2#qIprR%26s(fT zf&`&E1&O<}*$RWo*6X`%!3yBro;d~<$srx)VvE*?vMxy%Qo0=&yCC%zC8$}h4!R?6h_;s=yNjCmCVlgD%u=RY_D|<(J;UTl0{AN zlDX5f09Z}7>-i2`{bPum#*V8r89d>;AECbP+aqkh zqrT*>YO1JQKHblaJ(oQr#xYZk0#{rD-5++rm)i(z@(`LW07&W$pqaAXXVW;+VEu;qas|befo*HJ2z<3|jN^it035K$AdMHVf=CS><9)c0Yb;JRZywGn+p*5{Gl z6BOV#-Uw<-IW?&-WF52 zVYv|C_z%q((hc1xtu8AIdGW1>x4v0igC;2QT@&zTT$Z{`DVlmnC>3owu@3|vvJf|TOpE_akKy{ke*FHsoQ`c*_j7K?@S99bhrnUlBAg4d zlSX#0xI*3KpJw3^lj4f`0*syowhH;R{0u2=)I6N3Tx()y^LDFoK)x@;GnC{y7mk++ zT|R;qy}>shU&{^HAn$XQB8tfXEudPfb|tPsIC7eBC9ZvcYZo`wM}LK`Gb$5JYVHL2 z9*sm}2#^qlA|8)^2xJAg0=KopOI_RdGxl(1DU4(^xmtrfI2T`i!Wm6Rp;;bLKtr<5 zHsS0ma`MQ))9A0>14Dm>%2;gHcmqnJFQ8`9!GAvs^>4#+!~Fpt#G+H&j-=%w`%*II zRH%(w0L2X>VOROHXiz8Bl=igiM)dU!oP$T!UTE!Nwtzz1F32syTZ z*pSZG4pJAF_`Tok$nzugDyPMlO`*kj{z|udw`P_K;+E4FL*aJ7_)s;2hLfZrr?`<$ z!Pk4z+V@rA(rn=hqMP4|)kV*mVDa~t#bdWa;9KkxG3#>gm(dm8-gk$_Pj^MzLw>j1 z34tn~Q&PWzgnkfH^T)XHaeM8nr{DkHNT|^pHpz4A+5T)SdRVINr?iH%*O-I)qVOP8 za?yZ2rAs;M>F>P&nG|vjmI&t8PY{n@FemzM?e{){lJ;Uc%LYozj`s>;*DeXZM=-j_ zdFbfZYLf-rfQ$S6G5=Zf9PdpTByX@oDtN_V*kRT?Jw2_Ra~%s6J#onqz9@fwToh_I zII7c@;9tGFI;6d;j-U$|Mhm(>9*3`jmK>HG8XpsL?&^>)sJTA|(=Gg=q~FPqyuJM< zAtEOBnC;a8%dE<2H|YxTx!Aoi+Dl1hqr3UeeAED?eZEbf1D#$bgnY6nlFPY0+O_t* zlX!;F?D|(cUm$VDP1;cEn)lX(g2cw3#O#}V@~bDqhD!`>FtCO_6EM7kbsI0@DDlwG zkaPMc(T@m))`k#~tuDIXv)jJcE4G8H?6i00)a5 zF~8q>zy_VxJR@=<#E(p&5|^euY!hKBW5h?6(vCXJ+DhkGSRG71wcqj>p+j%8^sljW zg;3;$kZS(yv%P@Ihwem>3xXz<<13_!po7Eb+-c1BZ33xRlDDmJR0p4F6=g(AxFy%?^dxY8(Yn)B2@&e|NK)njCp0{F$%!UwQU= zxRcB!8&Nc}v|`tz@YwjCL!M!K&eYNC{A*ON8K0>-{~g*?O6#buG?Iu^qF<#X(VOUD|B7O0XbP%@w~a#sdZ^sD&tXil@e%vDhg^6GGbd`? zxSeP)WMhIbP9HbUYYtyD-2BV2#F!nxMM`3m^0NEkBDFY(u$2FcuG*WuIsw~*(<9T?p$;x*0r0ru;;zU;tqI@(c{5M_)(7&*~60>-vpx<*2e%5s(XTXA6_Pw5%F(feO`e`-UYuR(@ ze)S?J@Z#CX_k1eb6KOm7bRp64*DHt4|Je`RcDq^I;eUPHxCVNxpSw21xn8acxMCag z9X0NNt-$wJE*^{9c8Tc_k+G`}ebHkgH_NNqMvpCX&yEYY#aX_#aMt!(xX*52+lle2 z`|1tIdA};~;w%9KRC+)4_6Z?z1p+~Ei`(JTOZO7R+21zy%xS#`G1U&gI?wKk-juHmNB>Hb2uBtfp&m@rLzW>+-xaf8g z?M23Jw%e-E8p;AO`a6?NWn}(og)6iu~oKc+BdbT?7!bb7s*p$0xuEjH$uJH&x~2R{aHsAiZ9 zOpVrXH$c}~>iu^P1Buvyxq<<==YlyPp;B>RsK#)Em}hn?vVJfM-V*T1a{i3|ywb|C z(M@+(e&PH4xz+UGmOK#bb=}Y^D7M$Uw!d;UI+KwqdQ9CuM2DEX2>w8i`H4;oKpMN8 zF)z7H$+>v;W52XQ!!K8R6ToofwVpRr32rFGY|&$F{zOk#!{~m-;WxVCQC#n}>ewJ+ z?B`@+bFh{E*dD(-V$3IWL;u0b#bM0&-))+gSWVgNl)`7xx>p*F% zq#XNEALp_&6Yi`oj`a<3?`Y-SUW$+H)2^9dlZkK-yUjT^%X}k`rb5LDpQ*wtP5aHe zUaYmLa~BGZDYb6%{TBzl>FXN_NPv0eSPfcP#FEexl(=RETLIcQH60S7iVM_tkDVh= zGAAWyPwCY6;hB@f*X}<1hoc5wkgv;AFC13>?Jtf{&)OnNJ2hT7QaiSr&m6NU(4i3Ae0A-Ndt};9ajDgu7`vYpTzjnaLJsxV zy*Y)7KmE*kxGm0k*eae>_Gd=tSE$X$S2qyps+q*3z3&_gxaNiX@3xBH{~n7w9*r~0 z{!GrhY&u5ut(R|neg<^QK=-t-4m#iG6<>lF-`~xt1t3j=C7u2a*Ui|8N`{?u4v8iP0*>qGCIo!v3 zVu4!SAXAfwytV1-kf3*7Xu6Q2J4w9eaKRX0l()|6Rw*T2&xkT=gIlS+!!|>2t@&!- zXPH%-a4?5Wl`s=PKPXi>SCj6?PwG#1k^i!gvsgc{$fuuwD(HV)fMB(4@tjzJy7S|q;jGfEWxe9CvFKbkzf_u|Moh5Gq#M+jPmTT9y^g^Y8eanIPkyz+f9r| z5o=hetO1H<<-L>s6F`VmxDG0i5Cku>}oVR6E^!Zf|!eVn*??r700&~%7K zUWLj554T+IRI0>Xul@QFGm$HW;77{obh#pPLT<#O z2q`tph_W>Q+-Fl@thOu8If=cC2VNc^xp}8fE{cEjB_qGTrPLZB2d>;;o;MVtR zC^2W1FZLtFdRTfnr158dTP}t4$BW_O@<+xdablJ{jb15)Jwsx*&?z5GUM)%{G}2tK zBtDunv91GvStT1ggfe=xckW`6ic}<53?nj#kbOr_|COlKWuZ_;yU@!_Frj=eq6Z*eupPR}@$&msF&5Jdz(hoM`;yJt035r@sW zbsmT%d!JNO`Q{?V_`C!E6zVm(g?>C+Rns|lf{zNA=w=y)itoK%nEDk<6?z&i&R6)G z5-)2cx*%TooHys`(obEe9=;MJ)qVIsiD;}5Dx2e%C+0xc?jG5itxl#0fa__T;3`nV zfpjJ!T>))G^JH zuMt!sY;v=y+-1s;yUzzJ+8yLSO+8NtfLW1&F`kUsIn`XR{|-loA~nn3 zflV4T$={MUmtK2um6HJIM8WIyX@6JEp#t~=^DEj++ySTAYNbGtfF30fadh6UgQ7aotD*jfAU>l zgdeda>1@L*a~98U(t+`daKQg!UMcA0?@!MO$gm}$W!O%7yPZjeT1+WOKhhd( zQyHg$GE#~v4wk=EMIi-#sl<&d{=unXriKd!zh-I{c&m#=i3g(O0vsfZ@#7Vka^aXm zv-`M-mqms8c_A_yO3s(>eq@CK>$z77tiRX8Y}H@wyd$^w!--=1iea5V6ZXCV0Qj*3 zWBE0Fr8YLAzUwmFwNYvycawx8LYIH!MpAm>Kb@2idLP_l6oT-$- zu`q2zAo>$dwsfB+R)xObmRbA~IoS@p7Lvyq_!2gwx9mHm$ALL>txBysekuGyF~9Hf zh@c4&%g1fjZ&Eya$fe@Or>%-F08tC?Cgt7mC+}i!Bmjoh8 z-N^NfQLHxW14bRYZqZfSJ*SrflGN%J?gj=G8Dc)KCrhdnXW)?wNlvLG{v$c-0i}A); zdjN~>ULDG{fK#C1?ENyfg^;4_q9W(jHAxg#=?t z{mxBj>71ixpL?C5*`VljuJd!OOmmSmhI9B`0uZGd?C^eWF@jiYQ})bn z$hv1k0gHLR`j$Bx9Sz+iq*1 ziAtP&>_^%-iYm>n9WucV)kYe+zV2f8FPcMivaB**(;cRhX`t%=@YI4NxqUu@S|a_?Z=hPrD2|0wviUBo|X2P9!!J={|;o*1)k5 z%>ig|G63*&_orxDR3_gV0c2q5g&i@~FgV7|p^&Gddi<9j^8SA+lX=q*GS<)hba@k& z#k&A8m~-ejNV=H0?5$`A3x2@-Kbp?EFRHft+aM`0gLDmzG)hW0(v5TvA&A7#4bt5p zq99$8BHhvr5<}O}-5t-q?$7h%k9h&in!V5SyVh~6fsc?@{94il7#Gr{gptzFmxi4f zo~Tf7t_-L4&^BoMd#z^Wmfd@Pj5PzMRP*94Gl+20>V}@%b?L{axtdR^|Nq*;L*4Wp zAKZTQ)AYIt-X=z#Pvnvp`oB^?vig2FW9aC0kVn1kkA@N&amO8z8a`hOwiwi1s@zy* zu2F`l^E(Z-5a)>p`LuPj#*9AweTz0LGtD_$HZ=2BLY(rIQF?u2#(nTMuQxqXxI*

l?Dw(7S349J!E}jf#Q_|sBw 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%0A2=aMUmK}unZEF*^{9R6v~k0 z;IQX}vO86$6V>eV+ z$-9G%*bVBy>4%~^lg~pj2nJB|UolUeU}HjtGk`XZHB7`DyMY1wxI<{harEUE5QCF_ zvf*~i7b>bs4Cewvogy?G{tbLEc;AikXP@yg@NpnN%mg{7Kfmz?3Isk3sIOm3IRz z??(DT$h!f3@@`id23diGI1UQ=I241%TUqQziVTlAIMUK=Kt2ut@;LK2n#8w~>X;%p9D{g8 z!QL$_Z22E^aDc~gG`t((ER}XX4uF}DFNpj)=h12PA}aAm7tcHM9Z%vOoY=JU+Q0pw zjiB9=TPAki#<=up3gw>E>>MtGdN~2iUm(#vKpi@C>fD<&Uz zy086!*ashk{qFMOzbK(X5UASpmm1wW}a_LDF_;1s)&9)Xf;13;Z5 z>0iOh52`{GfEaRU!wCUH%G1<56fqelYdQ+oQ&ig1@Czt|^E>~-+<>+OSG>>oEn9yOABW}_f$yF`H2beF9|9k8J_bJe7(yE#flo8zQ{W3uW_#LZ zE5^56N7Umi8@snoT>GI5_|fxLEWGDiA7|cyIrGLAEIA%y-i-n};yB7M^L52;G;?r} zWYPD$8+>Pw{P3vjWQ*g-PIztQ-N2Z41N!FOAkVd77`pOqNUn`Oc{ha0+Ry9^=?k90 z5zH=(_5@(G@PcVN7-#NL0JDuEh9(B+he0QvV1gJQfy=LUl2~1aAzTUo( z4k23=hvF)RjJn@#|L4!9J?8qMPYw?992`FVU=VQ~p~!rKJO>90i1vc|-=#v?Oy?d< zGj>@gL|+xykFzcf`>dF0EmQxH%LdrjwqXdM5gdrE92|xFqtjH8$`Epe>Mli^$K!oO zzk&GiyK-=_wPqAB^A>ftgI9iFI|vQ!DZSvmnJodrtkl@U$masn+mJs!>rF79RMrb# z28g{NAIc@cZqHMw_dkSRTOk{mr>amny@xufO^|{_Qg#g~MzWtH=wc7ViqYE#m(M=@ z%;xx?{it;G0Aj1zTDpnHrJXlE-T>Rw0q`4XOjw zY+`N7|EU-nPJA9csWe@fP{*_@lp5#!7fK!Z>qWws1Kd zh8BjIU}|B?@Lo`C;bbk9=|$;kzVD51U7au$1#bT3+FSM1*aIJQ+>uW`o%Af#1&a?K z8C}*dc6*^*Qvd)E07*naRHLvJIFV*j1WzYtYrHbYzjVR)7$E7L6644S$Gso={*TvyIX1)KoTi zohkDUFep z$8j(fPbjkgqLqUK@;D9(*?G8yOL7}aM>k+Lp%0AXXpg&qN9Hb_KX!!m%MnjK!_I}h z^}l|(^_sQX6*RtWHT0$+NS%+k$dQECfu9;esaIe+J_%J3_l%@~9jBE$g}{eMfts9{ zEn7Ijs3B_7{h9xf>o>RuY``%7!d}#&E}#bX0A)A%{4xXgKF3Hc2Gn5W3xTXlIWbDmG>R|;4?)Aa!DZVg`y?80GXo8YymJyiS8R8_;y?2+KnJgpz#{nEtc8| zPT%RSHwzHt{-S;Iu?5?2)rZ@>FE%;ok2Adr+UFFyyMaxpf`>Bggpgsea53cCpgive zMQlL~ia{)(zBuesY3v3vKaCG`3nF1PYLPUi135qgSg&_sQMVC81A}-j#Oac8#s#KU0P2d@i0Y!7Uu63kVTuaMF{qD>Hns$?58h8dWd3HGQT7Qg2jX%#T(od8 z9Hthg{un!O8R{|wc8dqY*^{08CN0XI(vg~$yEpF|Ut82M9ku;bpBj6UoEm%5s~)!S zsAU?*QJ)%H!e}FQBTy@Y%-qo%f?3`T#^Mc0(HXL9ZSQl+nxtst-H=sEk>P=PHzY9Gwu)-Rz*LL=D=H z4`vl*wcyn(W}N9LKSnLHfbH>$lNlMbp2ukP1MbYN19P2ax9{7Vim# zOdJ&AI5Iz}!UQ%=%DL=Ty2jR0uEu4brSa5z=@kG9~ zPq+qy$N)r&;iu~sN4k%1 z6`Dm?f7y|PqpHBY-}Xnp`t<*v+_WVQ57FBkyWu%FTrZ_ZrIW>(%C?NoLEgU-fh)fP ziyuL62UEx3lWRW1$}%IifL0fEHKx4@uBK%i>Aa)8pfMB(u?&>;Lc0vjD3TTTJMD}= zeg5U|{4_``Mtz49U-;xXV++rF_M0z#>nHB_o>vzO=35!G-BNU(?e4hPHf9$g)~h0N zB{}v+w&{l=hJ2tkuaT04>(Hhv!P4}zF*^U>Cw{!Au`l*1u#L4ZeaPA+ifK9upq|=f zr;EF*PIJKg)d+LXM_p*h!Zrw+8;lN+S|61 zuupI?5Eosz9Ei&t;~rt`!qkC_P?sUF**#8;Uv_<)_{B)7(MXEma7w#&+&ne4v*6#B zbj|zDms4Zsjh^w&CyvZ5*js_coW;veDVupW#L6$dB!O?(^KQsGlVdkJ@@_zP?1rpN zW}0^+JvhW}KsYC5K;Dhg^KMw|h7Lws=^0jwlT~G04Z6PutYy#^3lQy_3eHIn%%r_oHs7Il6}fgj>@K%+VQO6?rXb8}>r ziUu|VPv`9>1ve|qrYE(7K_sw|kAt$cee_}k&1P{NW$-FG1_=2$fa5;E<2b}(F^tkt zy26q8GS;r(Ylc*>QY?#vRi3#d&?g@UHu7JxynBWBH?MPbzYDCin@(87!OTv#4A zbBZ(n>dBSjg>)|L)$jWrP4-yc%5vBE)*HdmRWm#%6zsx~krFKk%PyMI=-1kWM* zW}gmv$Ts6pDA4t@|X;e|b$&bO(8sazrx?(rd{}aa0(!pRO z(KHxZ5yR+@u^SwyLfU`rE%Zr{4< zpMHAss~%Ey-`H^n9RJ4;zWyIBWKkTQzij^4;S<}}pq?+F@f!T5iCbV<>_#5PVP2S0 zux9j-yrkkQ@feNTPa*vL%#^Sj%w=$Fc{e12ql{;!F}z*1kmzj)9u|3e+1&qZQ}QuYYRps`p=A*~Acc)zXvJ{| zE(<>8kUyZX=1bZBZ)(f(H9F5WKy4}W-_YOjH zS_d&rVD5s$>T_XrG@ba;hmIY0Aa}v)fBebLTeonrsseA{bgiV^1$|pVJ;nOwg7GQv zd1gtcw+dfQc;yx2^n7aZlkd0#mwUix|9gyQ6bjn%Hooo_{MlV`$g^zUqNHr3>+wHS z`lRyf|2+TT`@i~$-}-nptzY$_&-b?PB-Ow=!-8oN5L-AZCdhPqoOiT$z%OClLZE!L zO9}J)P>dRYkpIHW?D_}nzbL`yBl{K8u;&!CQ}wHbM;vtGbI$qE%icY@XyI|c``A^V z{bv6h9A#dY>^_=!1gnQ7MP5t8aDtg#5RBdlo>EC)avSY9hib z%*G`EYL-Mlh}WJV=Ld|^J!;+9GEkbP5DSPK=;-54f_?Wvm7M>HpQz!6!PEb~L3K=Z zV;w0nmJ|c;fe@0;@uHhkNBrW8Pk`UzkDB_X!W8SGLXAu4KfVTI9Iab?D(dZNC`L}E zG23|m{vgB&G+2cDf}dNQ02uT>+L|-tQ{XpkEML>^D}MgmBL5b;Vl>+PVtW2akyaGR ze^EGw+PhIgWnT6sckJGAOR?x^w%zai&UFVq;HU%ccU0AZ$Nb*CH~#ddO;_B?)5Lu%)23Hlt2+Z8kk|X$eku5P2)T26$R6@4k<(4jeJF<*I@8>WRx>*h>ydr zQR;89puMp#R$AJV^t>Aw_C11K*czlAJszcT2DIxw5Ou z^M^I?K-xTx!j_=}aR-GK4wOwA-kNs`EessrfzxA`^CJTscz zLEppj-o#)5x2$2c$Th|rvK>g1b8J7wRwIS1OoA^m8?B)HGL7*_HOj-Nwm|w-Ic@ut z8P1-IK?KmK`hAL!8x{TR+vYvHT3E(rH0T8@mAP?b{=((QgK}2f@2F#b?=1dm{be`b z{+(-0+IMZch02}&ln|HadcLH%63%Hc9WGnAG*5(MEF?NZvGUWeq{nB3sfq9AbaqX% zOb;})0r-AK6vX3y@9YZv@Fjn<Ka;M;w24c2MTG$lV9 z5@7R1mlY&gFv5Hn_ z3}Ucny}A7K6CUv1*IfG6PYf!9zQ+eVuK+-BS7g)#8`6~818l5$$*c)2m^dxSXQ%cx zL};rdHj?;eY&?NBN9vc&>u%B4JHdAmhQXvOXfBcmpa7Ut#mYw7-cp7PtGf#gi>pd% z*oF0P$D~1~(muh5)aSXaGWhk=W7M9LrqsH3v;#UGcu$FWB*YAhCRM=%=c{>=;ne-9 zKX`6VKO`A>$2{$u{pxP3dM$icIicCVpd!ind}Nofv^NJpqVplgncM=!cJs$$j;EIg z2_FG9@8uzB3rEyhws;5=KvW$3OWi&R<8DYSr>H=~pzKdG(=$^Ixt`enKh$Bt19&&j zkWX<9Fpy7yPyP8A_}HB9qj=1i-*x}y*^pYEGL)(e07*naRPj^vM4~&#*G%o++DqfIqANf8qlt8CZ1uV4+s+bTCC3odxb;qssfE*62tDpt zM@^6%ldDoOcnFJOk<3zLwf-ZiOc@%^h02lKB7td-A|z+Vg)bRq9DRS4>;|{ zubw}C^V-`lxNP$^zg}_1iDt};xm(0piI-R!L!l;AHiIM;mh}#(<^k6&KFPVbt3Cvw z$>auI$>@^Bbqkk4(vPPbkWdUUM4*&cH;K+!vgnkTKK-db`p3tA^+Ptoz_l@HrsPHr z4xP0n2S>9VKr8{SOA+p-78;nQ<@>~ymo_5BSs2iE8i2A#$pSo-0fNSm*+g41F9YUf zpsq3iWR^heg)%&<3=*~Eq@y14i9f&UBcES)@s$+H5M{oZgF{fbW0+7ftT{Ne3jneS zks=0+gQ9f}rfQ+adnlIX#^A2-+Oc%8gaj;77h6~{dYfyJDV0qJOu+TUXw8&kSw{i{ zj3Vk>*9?2b1J>`bi974g7=qAiM1y5RAF}1K*N8*tZEaD8R z9x@CN$EUuZ$0(k|5XL#k5?r-l}hOpmoeT{sT4O~IT}TgHsi)RNjIVN;lLPnkHT#|4B1 z4*(3n*ycy6&i}X@e9&h^*A9&LgpYxb1No|j!6`(qLn8aZj{64 z-N0tvjS?GqH=u#znJIdfN|;`(Uox!gI-OvsuVTian1fBD6gA>KSS@iBWFvyh0GU_VbhbP?7qf04%4WHb=_M!hVZ@^gnS&(%EtjA9|vka4sKd9e}w6rRz41CbG7(I z7)ywlbQGiI;9y~aMh*_g7XOuxVyDspvMr=JGJQ0)@WSQCkIq?S;0Hhm2R~yY9i?0m0J& z5ctrSuXsgAM=(jt`?|UR^6;N zn6`F!lT?PlP_)EU~tUt2{Q*Xs#%(gm+%x-@aHVV{_6fbs2yjs7*t;~lkl zyt)&E$^0wn$HGs|oz{<%k`mQSOgOm|#BstU<>pJbv|6jp=AEhSK*F{9g49dpn=_wf7^S6?FM`a5kP0S6l%7wF z%Yf@^3icXR{Pc*b>;)w^gi0mqUXDgWLHu96#HqWzRU4&M(UJM~dAjdK$ZtIQ7`+ z5##Eoy=_}pS6}zi`ef79cij44a%${~`yO@V)6Xb%DY{_sVIy;wdEN~c-F|sD%6Mi9 zXN#10jkK*osAr})=IHbqmzsBj-_jRbt<*CkHSb1R*J<7j$YM7j$EdcE;exM$q!a?? zIa_9JBDX@^%0zXD+sX=}Vpg1f)``tl0C2k*pkY5{HV}E)GTbUNDi%G2!B9ZeSS<|Q z7#n=b%_}ff1`P@-h&g6S4sjfEJWt|VQWnQ)SsnP22q8JMix9O@=yDbmb2$UX{QVT6 zta8<_(H~y(pW5G&bw7QDy7G2|E=w|YNFNVLHEOPA)uSDm1ioX2r!J`UC=?$-mg z=@p}EKYn^C8jlS&DOJQW;ut4qlz2w?%`zRuf+0m`a5M*49EV`m22vx;;y6HaWB_VR z2XuKA8*v<<({sm(Dk3bxFJlCUPSEaOwwMl3v!etvg`Sr%5^E=#JiDE~rTr8isCK`e32ZZ7QgWtq zVXXl6u8qkb3XXjK&ss(eyP9ue8rmVPBF#Kat7bBDP-aY2yADB{namYI+SL5K;0DnG zB+*1`7O6YRAnM(N-1%X`r7z)sS+(rHp=vfGCid<4-jLC0<8xV>FSPM zGW=Yb)>8#a)P@HRi$lkNk`g&t10SK1VD%W_i_(C%*h48!x|k$1PiUnixCal+9}|OHL9hJRd>s z=`ft--5^;BAoj_-5pr!<#zD=v(ayVpL+9NPdm_)fA#d{Q4v(s5n^a{OXEucUFWP+p znPQ%X4v>v#oODoV^QXOMpzWIyWnPTwD7NrGT4+KGqJYa`aI)-;AH>UYi?*>X>kI74 z!7&`gW_$-W5;jP?d3z4g@^1TO*qWC5H97gNW9L0vv`rK}oc6r8+ ztMs6qy2iElqm8)skZb)`o?e8xGL}tqa0m@vj85AO+BBVIR9sEltRXlI76?vo3+@)& z-GaNjdvFMD!QI{6T?cn3xVr_Hoc+A(d_U*ctXZ>rcX!=YS8;s3Y&YI>_d8N3__^3V zNQbZF?B<=(6qHeC*5KM?UO)(;ZEEqaJg+OGYg?qtp7GdMub`%ld>|?B<-S;7=P?Mo z8_H+7YH6j%<5A$>F5f@WGqhuE*yuW#HhCRToG@pV?>tgILoCxcDg3vUPqeaGH+cE2 zJWIB+)_g9mP<`^&227x4G#9}r|t!^6w zf}nx^ev~mL zjwfK0<@Dz-COjpWxGGE2e`U4@x-ZpwRBA*7nEW^>@}n#>(ddyKBhPqd%F@}GagGfO zg}I1Co*av8JdTyfAuX;%Z_nGzvwh{Wf||*aVV;c`a)ekZN1(>$!-7WRJ~|2%b^d*@ z7nZ1FqS%;e^oW~e7$t*(GSh`cIAm9f_*L82ikU^CvT}BJ!ky34WJ)ramfdUewHr=_ zrF*O_Yj54oBnwK;M>s$Mw@2*t?k?>Iv)gp7KcqytxbHR;;1b)Fp!h{Ef0q89^KW)B zL*VZ?FL0aWun)Wlmh_?=8;>AG3{4vEM;AS6ZPSJh|8&NS|84XMI)Iqf>~EFg5=yzk zuAFCuiZA{lnU74&Z213a0j!*&U+S?u?`w2r!lorbcVlo?? zhdr>DX&q-pY{s8lLRLgC1mN>!Xhob2%2@Q3edmybE{Q3_&O3D=we}o7UJ;dpnZTf34Pw*Z|K`>MpGl!i$}z})Qt;_)CXF!xuEfZ+^VFHk zf!+Qw={~J+#JXsoHvGT68`pcRL?N1J00fowDCJniea)C4LLau2`p0Zl zw_xJ%M_4l%N9CuYG>U+>Bm^_{@CLmSkqlR-N}hUrP8v5O%uuF8#-Ux>k3Pdm@19SeZq1P}I#|%{4AD#=cqK?!}P0i>?)%U}{ zOZqH%+;Da2Xdx!c;>y8CCwaHC0gt3FA3G5uJ6oZ?6KXE5OyP$RC*>f2bCURXi8L7; zhg-%12@Sv^tLWrll1QglFq|116jA%d&{7p3`?=if?Qae%ujBIGI%+)ZzK|sbDvsd! zV-{?vEdM^Cc}Z5;7zd0~63H>Eo{=aS9R|46{|eRl|4aqz-p68JX?0}rcD$Is9=b5t z;BtH)St6%?%e|mE{l`RBd+EyWay#CuU|4-?+Yj}W>)jka{@Ypli7BkcdSq~VdGXr? zq538Gt(Ef6Yiv}p@`UiCk4#0exg%;|*=IJYpcB$N^SZ~$@BR?P6|gGrjtmevv0Q(J=4E|=nGPLXu|4leu`7PH~I$>wYnn0RNjh!a99LAgK36~`gU z>jp%3zv9|M(gYoCOFB!NnOotC%F0%pX?q1PChwOK!^SUu0}9_isdcL&c3S;rkJS~~ z!COjQ`qQUIa`tUKGB9%(>{)U8skR%v7@Wr#A(eWfdBS3LtHnZ(IXc8@0P05jZGAwp zhK7bW#G{B7pkE~~bjXS_z+Sge7LG~aWEgG70B0Xc>`EG|2m8fHvqUA&G`W3TYqOSN z*2RMx41-pmhsGYKu*MQ69qZ)Ru+#U?p&A)X>}QFB0>JJ$r2fS<#v&%6q+3vQD2`iG zly{>^I=(xFmo-Ib;%qUKXM%9s#G|l>n&w1qv)J}q9#)&V<$ckgBFdsw0;AJoe#At&w2XBye_}70GLRUO^cj|JuNRFz zOkLySZ`(^&Rws7%er!ih+34T!{M#_4MX~im7^p$d8c5uu#%#2&9ZUX)=7Zpbfr=3~27L}M0I=DYh69J911`+)LGqtu#Rg?MkZdw`Vh3)n5PzSK)WC8 z`FlLDuB=cAj!))ca1XgsE9{CSF&JOmre)t)FsGT`Pajo8nmnFrL#qLQCqt)80 zg9~JX#F+hd=Jsqq^c}YfVtfy~G`lK${vI}M>6NJl>aN=}jO&_wj&#B+^#ISw_#}R1 zOk;t)enze#-9`canP6|E2)JvK+di3HoMQ0ryY)<8^-DkR!Bw{9!D*Z+AJp;HL@5Bmg^>=*&>`)um zNd5*tn+__V7jC#zmQn3vjqC?Zyb{0QF4&{gzs)cd@^__KTHc73s3mx^P9mX+=l@)k z>ksOwObZ(D{nW;cs+myyFNwjgf7#0fQ{-;Ynn`cq^>0}X^UAk;uLHlRAtLpZDeQx} zcvnMA1Z{GqfZ>v0QlGy6@_kg-vP>MoJc-n>Bc0?P!dr+C;xe+=7eW zDD%~7z&{Z&wgIYHW$9(TA{;4k%={y<7+?(vdP_ie^6Yy?-C9oXjlOr5$zjU>y}ep7+&((U#M8rFO}u=ZLAmbmsykfMc{ z8%~iBkj-R$;(0+T>Z?q1l$1gnr3n;G1OIAQyDt}x_m$K?=GB3Lo+g&z1sZ+~Yg9|S zn)JfTAk{)Nvdy5OkCp|eh-{3pzQ4jsu}OHBg$WZ#V0EC=_*0JLpi}L$2|bZ*;gy8v zs9^~%7FstbB3ONfv2*RM{d22ri%7Yfwrzu0fy!jo0dM?TD)mdO`c;iyYOrV4Rb{7c zf49=zHOixRLQ_{2wjZVc(Q0|C?1g_}{-w0&7+o397jty_%iV)o9H_lSyHpfOGDt!)W1UPKLPOGmE| zHRMA*y2!;A93=1ZS7!N9urj#CP&bMzXN@KdRYFqCm-V4=4mno)ZxZF(hg>g<2FZ4> zIt{G88+P+_w&AxG^x1%L8N@{6q%=02r(>+XTm^R<`zwr;0PV3_Oh$u9DML`;5Qzj{ zlOdO@b%+op`Zrs|5l6qZuM{!7U8<5zx|MpUhKp# zaK>WLaOzxt#Jsf|(XsI4tY1Mcfxx4Xr#>nv+|ac+*zgzMjGkgufmPaw#iP7}E!Bf* z^i-+^*|2H<4)lX#sRUTyTdS~99EjybEFg-sPp?X0IDHFL+l`6oIJx7V^VljF*z`Ik z-Vr!j8jBXQ{kP?skZT`f%Uhp3I)@Dq>90tj3HG>31s2T!genm`^8qvAoW9c67Z>%3 zzPKUB6|Y%pYmXD^hnKPlX{~;0HX|PR394fPPzA~=x~fiK&sMgS*Mwf)!mZ;-hgrHY z4uG2grygt{j||Q-#)zov%PGO!JryQjO%2BNz$6@P3kK5N3w;FxBLEHc+KgWYvvU~Y z64(J&N#{B%k6HRO8p(}LR*w%=v=nYZ)11tpnaLW*RU&M>$=QCk)U7Y8b&pSeT)~=e zCQ4A9fd@C#R@t25LB#1V{vX_2{WdU;szE>D@*VJ*{uS5Q+mb*PR}@@ej%~k0FAyQV z133n0za{LXzLamicfYk8vx1;(q(^=@h-}H{1d&<8oxs4mDk&uYL~NWZjZ_??+5kns zd>%t13SKMOxTs&Ht8A8%KY|OTqS{(9V?`q1Ath0_5O1w&ITzE}maXo4u*X46 zgsU{A;?7Je3>wLOnyy1?#Fz1lbDkza^h&%C5;5Z6xN+zeV_`Ux1mw;G9vS|U!DC?~ z!pHOjomeOrGlOd=JnLE;v$ddiUmT&FzIX7~(jTZX^IpN!*h@d&lf>(?BNfE zE#?OsbeObK1VGDu4>Q7{?!M0)GF|Z|Z%xF_#}L^M-3q*Lm#UBk!MGTW)aszlUqjMS zwK1ChpB9i5XpGoeNMMYl9r9^=6^<$LFxSllj(webK#=}?P3pomscYu7YAP;XtY*my#=!g4>R2xC08Alx*Bv)_%-usCz1@J3h^#Qq2(?98 z@?x0DeqPXxkLq{e8>a8qe+%@Fp`{kZ(qo$T1)joT7g1{$t;Td!ivf{c8Ml-gQx*IrE|j;Dy#I?@Yq z4$af<#1`@w1rx|)0-OB}2sb41Zu#MUh3GIW?cPX{OCG)H21N!-?fqiz z)x|OHbe|AT6gIIUXEj#1{zuZBSEu;Y;|j7b zN2zwqyX}khK1&#Uyo>9uGb7otb*=wPIhQA@VXxeW#ZofsJMo`r0rDVc3%WI28^QA) zt|cXbqLWjGiO+hl>`S8(avAKhRf79C1%%mp~=&bNSS+L@b7rb1hzX z)r4nkD85#U+-vkw$vqU6wI3`6L*`c* zWF^#IOr0!5rbSaD`k}=<{FeV`Xm&L$ju6OBgCUm6Mmzvd56Z$}VFld^J213_1>MgK zioq2_;&eFHnRBs+K#wxPvIfy537_E|8pAP=*&UvviPVEubH@yJfl9l6+{%gJ$)M0yY!2-rsfuFm3D2Ko=K)} z3{WV*uzih;|9;?IqMCZlf9P#fr1R1J33+ez^_m49DQ%Klc;38}Gz881?0Hx0FQ{xI zuygF7NMvaxzkI=cx@C5C?2zupzi_Mk&{8@u!s+laU^{l?a<3b9vM&!Yu_BR8_9aQt zO9sX}S~__)oZ6Y=$dr0yv#FTHdG@-_Ft%*MY2#zK92WR zE{Ay{+&#aEf_s*k!t~oo9_Q%alBeum(!;qwO8J9x#h>w_oueO!L&{={rh3w2esVRq zCae%+f=Dz)GDJC^Ug)j#v8|4vR|^v5dN5_K3dyj89$H6YK`C~Bn7n9S5zY~L?LQ30v&xcN~>=pWaFM4kUE9_UR4?jQGLZA@}t62){Z|aeA@}vsjxhzZw zH1Jt(76EelrTg?T-L=druHaBy#BxtUEcDKsGcUG*hOfG(12GYlzL|=}-K(ww)1Upg z-Dqop;2Eu+$2_-az3`QSmp9DtbK7Umy9BM|M z=i)o|Pe+NWKYKr)k?;aJ{-=H1$!{6XaE;E*R;T&T_h~==<}|X%7%Af7#X}8jx}=9f zcKq(b6WeYX_y3)QR-7_j3=-KE*(Rsi)hLwrO-28e{Cr3h)<^K%e7pbZpIH>&bs!Iv z2-JfJvoP1<2!phFCyYc=gX)}%FT@{lBH#l0*R}WU!wT8Gr)I6Cz3ylg6PTCHfH_%O zY>*2%)|z#?Pk|7#=Qm(;3PeG~oA291o5h*qx5~=+J|aC(xG?NWh1@Q-wZwcSRk(Rk zY+1*~{Z|peOGTktvvD`kXiDd@(CG3w&5z=!|H19z!P&4vz>C+-t_!_ud~byyL>Y;5 zaTU!Qp1=X`X=Pg^#s8AeZ)?Ld=hpmwenuuu9%6lQKH3e%QvZ|@oK!}{_Em-ZGV`Q0+^ zYjVWv2SpWg!N)A4X=y)@RT?6$!c}Y8A1y6X+$(pAaJSk0k&o7OS*XX*yFt^ool0xb zQHYkKI7x9Q1MEJYoTqceSWBhI;oJZ~BKL5^|2wNu!fme7gtrU>D(h4SiFF~DEoby^ z0__b~;a_1S%EuB#;2_NVlF1BtkwvT)VUgNXh)j%XlB{sh_}iZMNOj)fy^ZU^mN4+# zTad#DZU@~tG6}dEGd17i6`}3&evZM^(x6E*fFa;v>4exsH9n3M7dSM|`C;;)Nl)smKpA#G+B}xNb;G1=Bl+pBH zK;n=i+pQz?RmiYoqMAgF7fuk*W)(~?J2{&ro@sV?(6r#r-jy&xsHPB}@GoWTn^txw z2g!5T9zRa^z8&Wy#un_UtDDnMMjk6}+Dz4)W?&sCaCduB+#YHgXPS9H3}Hd(D!^gF~;3-JL69-D?q> zf{lPv7>uC2`e+)h<0Q);=-CgLGBzN6#;_kJ&5sH2_T(cD_hl^GM&LVgE{q!iW#_9L)0 zsf_dq>B(it&=~cupif#agt1Cl8~K~n6sa-EUg+SLZIs5ji{Qt3OG|2eDUb2Pko8yG zBM3@TNG^jcxjmuBp`9O0Q9s53PVZ2pu3yVP$6ow4)I@|kI7mHZra_i;4Ft}HZ z$|Gd5par?QSGpQe#D7>C$M-02yz?@6v_rwJS{jd;jQ5zgk)|-yL?5n&rS{(0k+VuW zuyj|J-BYN;uRNFgP6EAom_bYIOT6r@?ZH3Vt{)Grlqo3h*)_>>8s|)lhqbu@V`R?| zHy3fGm6>cL!+$8qNPSrT9wAe2oOGf(B}DJf-IFuL-6W;ASo(`T4&T?=6nXT?l+33T z?1M2s_w}JKoY*9~@YuxFN2}GZoE35M{&cMrtx0iHw2taht`;3W$A$dU<>hSzuA&(b zd#4<4zpB>rJDL2`Bk?|ULVM}gSoJ(#R%cx3$=M2XtAo$2)=?rjK+>LF(C5mB<)+!t ziJz;<@z(`v7=p#v)RPm!g;JztPBD~f^hbX~rtAd)~6j z8)`i6V!nD^C6}cLKOiHb6964LpH_)?ya|2{tK%~pb+hcyA?3>WmM5v_P?)%dUS&kcJMY?qG=1o>ouIYN)#jD{2NYyb8yI9<+h^DxH=gvp1^#r}NzeaqdHV=^ z_v-*CNS90mni|hS^TjEdMu1J4BLbMeephGG+>8!;Z^IcQ^T`W0Eo1~$d=|;kahav( z<_Z}e8X5T$$L%a3eiTE=Lsq%>V)u;TYxE1nW;HJaJR}GVruh03_aF~qt+)Nhg;u&g zqdf)RA*YC3v;LuV6wT-O#t0ijjyeSYV>2QyZl4go6{qiO(ih6U`8G1 ztZ<77`KVLeJf@OQ`);yk{E$s!1J31IzU5KOMiz$f2~;k8y|okXx3Jv?EU&%vGJR5` zksAnKJ0J~_i&N8aoF^QyaK*t(YxQ5ypU|EVTJ~6483Evv;8f@dvl)(XCEPwUVJTO* zisuh9x=0QEwY9*2Z1cQEhzLbnyE% z>Rf8Mo#Mh#|D~4o8Di~X@D3@MiOhyZ;nmtF^#u3W2`TBhGf?=q^s(N(g z@or>gAB)dGCB_2u4ja_ma^I(i0d#E{*2d@5Eg7Ptv!9_IzJgEz&{GR?o!`cs9-67JdZZ3HhKU3a~ z@~lP%VUkLxgL8W3KLamn*$jz+$tV@Ae_d#TTp_Hp^Tr_REf|fa%T;?H7fNJ`5f%rO z%|4d2a}!@jc;G}Li!3y2+Y2XQWaYiuw4>nSUQXNL-$8V~JoR4>)d+CYSb18s+9q(* zcw-%zmG?xgCo-*c_Xvhu15OWRhqd!dF_Qx4-q!OaHx$VmrYnW^Pw<2;1hi%>}-W#Cokv93n*~N23J$GJx(#C-)3COTZXs_v$>@eA+6A(Q9qC&2!iN#|V+ zil|Q3KQk64R81#^rD-&Tu4+BeSx!CO3fXN zwnnl*xOSnqqArGnO^yRyQXBm9j+&3pAbB!SM;9oU7}62wo3yX?u3hLL-^2^jZ^{ z$*d(fzSaskG}#FBAwx6UDXZ*aR6PrsQeqgfQH8Bhq8QbD*k1^7Z{Sh-`W2SdH-CQ? ze61@tyPubIOADfu;fn!d5_ru!OjmGhiUrFM|kVe)Zu#r1l->=(U7 zRHhKE>-|<;wS4qHRipOt2+8VjL(r>-?{K@9&TYWSfjmc^=u{2cDBHc@14r!Fc8~u@ zz10><@pDaXn+h8r`#<$o)YQz}>R#9P?|@}uy z*h?)#$p^Vtrm0b6H@BU=#SlNFlMJq+bsOf*RxFd2yzHsi za^GBdg8tXc+2r-woK!quE;*j)NVBWFsT`#N7%^QEd7gBF9gyDz@LY)}hRvs{U-*rU zWxQc6XO2%SyjgsVmch@|-uO@SuA}Z}%JnmRD|lOnrgo-+XS>=cF?5I^VeUMAT{OJO ztr|kSb{7X;4>4!2UN$}7e+&uvuQWkpzwhYFrau^ z?Qh6dtKaT7e9y*QVb!->}5LkZiY1Ow~kuC|s zbVv*u#c)yHcqjEsMu+~4J_?m*t$$BG7ekP?&0m4ir}4AvC1}rkY-xYA4F!d|<<6im z19%wBQJ-cWP@oY7zhIwZhfis6*({3ZM)(#uDH;PI)L9k}p+o~5ESgZLj}^mR5|YS2 z0G&>zr4KePQkSkq9%ITQAPFVZxJr{QOdVQM4b;dh7eB}AP_VM|+)>AC->H`i zRl)n!^<4~R$L`s%>@y5z(yU;m+oFw;)sA;eczXv%%KlxbF%E3QvOg;s2h+n2YPd{H zt;57sHu+eqe^j!oj(C2mQu%j0C!#*r?Af1OKbvRQ&SuxUP4D9mO0K1i?-s4?-%nK~ z-t7n-yWS=SVm%+a>_2X&tt!$j`c@1(s5l-dIae9#vT}?{xL2N$JU62yfuog&Emm3e zV6TPNyRN6EI8uK>t4wy2l^5;41xgU)=g(p2vwZolrjw|C0{r$iN&nVBKoxI z4tm^Ms-ev{HF=3@6|2K-hq1J9`VU%-XQBN&CEQZHY@E9(C-<^v=;TTI;yv;QsWm0!4g(+HR z+Bl~6L%Mz7Yxx6R}qTD|BnjFy!LvhbdXq;q$x1?7xA~Ueo>l^O$7-c!6$8Zjb zpAG9`qXz_ih;(OXOQJyVaO{Mc@%{68q}PKF*2(E-vpHJUp?y48RIlA$sMsm9daNQQ z?|!6Zj@%!XCBipR-^OQ{%1O66(QZq`@d7>LJdmw79THU$^fv-#Uy^J_YYvJ1+eq_I z3LjG6*;1*D_)Tzx?BWa=f|jeoSqtV}VmvAq?ap6ihpom-ZE2(70%|_*^ylGhWRIR^ zw}_}cR=Yvqa_hM#Hj6~N{4Pt6Ot?8aE5uLuld6C*=@##mCT8-L_KXNbrk*X6KcQQ_ zU?IU?Ct3Tq2Obki3t_k1v4?>1qmnqHi4c9!W1dE}?t1pBdV2E7?CE%&`gD25vDh~A z5k|}J^htValq5q3HfM1BTqo({t!tvsF~xFj^}V*Wc0Uhg!m>_RLBx2Bd4gbot@U`2 z3B-T{KsZ3DW>G5VA=@u<3Hw*2(p)UcuR`MSBb1;JnaC+gM_jV=S!$qV_V@eZ*BgZT zpMV#g(em*yYwyfv>po;!zwZ47`Ohl&-whNvhL=3*y3oLn*1sR zW&YE}e&7@V0bn#Dks-aVz07eBk~C*041vDnaH&*=-h72P4ZO@nv(&jdsZ^Ns;h3Yz zbWD{yIB}v6nd7LP`WIa`;FoULMLijuFXhd!F9AaroIo@D^^ny<|BptFzdTN%?Mi!b z?}zvQ?oZblKeQnh4h6F+L;KPl{Fwvwp*FbQmBb0oqgb@aHG9}zBG*<-m5U``FqS@Ug&gZdJ-^C`<~ZnszaNp8#pQ>vNzA1szf7t?QoPPrya7w~f%#Sbt(+ zI)OZl(H&*l$Y~1DD@D(fD?Hs0@ng*W8>Hv_?WVvxD_{dMI5>+GSdrl_ z{Lf%!7Ofnl3dR;X{+nD3{TG9;2kUAz|L(CF6)4JVZ*)5@Q`1-AgNrB>-dr47lpcH* z*7;8~t{RzYaiT{Up#(0}c!)B*LEb-nx!BdPNzxC#T_2!KQH4cfS-jBB`mz)FU0q#g z98PbBhV;Ik28kFKu(8=G;^4U}5Hc+PlWfV>n830Hv6w(9VClr!@0U13}!{in8Oc zgMf*~bhK95BNn?c!pt)K3yE(r$phQn2pp}_;a)4J|L$}DI(2rjruzkupdYf1q9*X= z_=$hT%?{DZ!)!<;e~HVvnxVRa-9KZvDRkN2$OY2Pg2kgiVk)kCmFZ7%ctk16VUP$FiU7=vYm?FGut7y@7^LjQSfF-otm2^e zP-($5@N>h*6cEu>Et4VL0jjx@eDQBpQGuvA{mMbO2g1hZVAtSo*ssqs!^g{!+7#C2 z7R{b1hScpvP%^86UMf_1t&9QX+_sZBI{?ozn_uJ{cEyWy;?bLc=fTvd0O(al1GXaK z-PBmJCuaHp1o&d$-fHm7HFoJufP#JEf9#vGCY-!Zs`fza_Y(@k2uzk%yp<2bP-chY^VRnyx&=>14R@c;W3yrn-8C%%T zD6Qh8)r2kf<#ZzjQiu?{ElPVqEYg9qEt?=tVAAp^&U+nX#Cu%uTz0O2=<|)Aw8#j8 zf+z~t%|`81nveywgc8yfKqC!^7$U7;=LtQA6u9C0WaRj?Hv|!+y9_eYw3}W|;Tlui z({!e0hj*SYr_Kqkv>9T9B}KIa`E<2THuuOsIP=32)U7h$=+G%9aKlD#^u!#{(1C}V zvejlUP;))V;lHi{eH1X)XzNZ(tS&pX-}5deEF_sNWv13Zd$2MH$CZrvJhDpE<&&p#j__16Y9D(8gXQyI zpaW`pX%?uAdc!tUiFu{ee3To6u{$D+H-uhb79aM%IiHpEB9}pY(uB+7=rFjL_U|~| zw1BJXF#fGg=9T#w>Sgzbgr({X5S<8q2Iv|ifm70?mp~ft zy_cVSU~UrUCuUGd-ZhUSRXtopx<=;@04X{ysB1b>7lsY{C2azMMuh|iGr^F4amJ&D zl*<9jeA4G54|b`#IBg~$wZy`Q*B_O8h@W7ho5CR=_u7`ompe7*1HN@s{Q~U?r`o(* zkvfB5=W#B^UH)uTWRG3h1)#QLip6n>p?(g*ydlYk8QEG?XcM5Y%b!t|@JT;kSa=$Y z(WcAx-teqg*8OXJc}telpid1C9qc<%w;~uJ#xe3(*7-h}d|IqYAc5zD zdq1x#OaRxKl1C{vr!Lk@9f!HUWE+x&6*0sJc*+#<#QC0Az~bj2hPZ8MoM3t`OUZcO z*}9406x6*&Dw3?R)O8(W&Uk)ER?7x1lu2+voKc;_?5(lbP~wTs3e{G^;#7O2ozCk< z(vmfA^QPzl%A~2x{H)to>hoSg%;Fs=t}Sb}Fw|9k66o(8|Gm0>MnYHL4Tw5x_}S1< zrOdy(3N3@U34;Tk?4I*Tp1fks<2bz1mxK9N)4sqEuFx4MS>OBoD%MWNgPZNS4foc@ zKk*Jdj8T-=saAH-hmIP=-;$y)F6y~R2oixn)|?my-)+b)w#I(Ch})f?eXy8iK9CFZ}B`M&Ne}6KcR)M1h=1DL=3ai zG~4;XEr%a5>HbMr??h ztTI;li9fgpEy(2~n8qBHD$V{df5|ec%Cz&+#387oRb}Yk6?s5_TTs0Dfisg-4QQqTH76ovv z&;kHzGp2x+2+opYtNp1MLCPD;Q1sYi@Z3amGF2p^j+Y4TVH}({9pOl@TFZ3ysd7h5 z*ae4527GI$2n_kMaKD0;OaK_)3@V+gDS`~jcjPC!zR!nWTd%Y2`7(-(mb2E?efQza zNM+@1{_r_^J=qeW!pKJAYc>k?sAdBHaT&Qb$%H>eA@q85aT%qsP}!q@f^yL zswkjU$S~G{>VNB@@4xj>av_G(?w-L_m7ud8n2wu&;uM9u1)_q_h$-b#qqx1$Hhp1< z#~!k&y6NfUf*Cr|JE0xw9F|l00ibh+c+xU(VPcrU24=;Eh(5D4YiV7fdGvRLc=4}N zJ`H@$AZs78VYaTiAPKcGa@#<)t%dF~&p#fHL=cU#C5rBK>ggB6fTIB$cYi<8CWD7> zw)nxHySR82#b3w+Gvm61W-B{V3l`*U4X3!Aa<~Eio~?p-A-IG`8CAGzU`L6i^h|ZQ zk?XdJd{`jr3N+r-Cc^Gqjksfr>}cV7t>RhACUQ*e$8 zM6gNxUTJh9a^n;UA{lWi2>Z)0dN<`k4~~%6<5!9AESc&hP8=pAyrE4gdE4&&Dg+Xc zdl~A=2V_zet7SLg`aavQ-^Fgq>XO}!U0h}Zi@*)0`X1-70Qnw_)gc7gkOPy;>PBWD z*e1TTv&}zLD^BqV6d%sB5ieV}suSpAZk{2q02z&Q= zjuJHO2e?T>dfj|d{k3s=%@XAa%yh0I&4^5$8~A3`wQD5L%MGkz11D%+aTn8=vY`}|Vvgu97cW?@ z2ouemt4>^Uiv5<`e|e>2A3E{5bb&I0G7Y(JIi;+ikgns(Z@pgSBx_dL`G%JG_05H_ zc1kr~?z|A;8KF7Tu2j(~l7yuf#1|r%AgOv9Bw^lK65LbyXg4&JknRCRug5fh-Xc=K z4IJI%3JFp{!yh|cM{O|`WRmVV8;qQLwYbO~CrlA%c3#=O!J`rh{AYQv7N+6NL~<39 zC^{@1VoP9wyHA##F~uD0;~@FUME8C%-WRvbp*e6aaU5F~JpO^Bjbn})xi;xGwEjlo zkbxBF%U55h`x;e8u+_;^C4Y9-^5%3gsoxgQ>;0S-O7xo90Js(2!~pxR_E*3b zPm@#$3&b$z#-y2@P*4E)2k-%CY!Fmo6@mx~{bbWr@D*|WF80o8ISSMsKZ`rmLKsp9 z<)WrkgZo4-#nUp1ir1PDIIjKEU#imjZDP_cAQT}t2$1+VlkxwA}%_Xr-E;X3*-iPF)N=?YESodEqpt|)-baG43& znyI?0NrJ`Z{c~B3eH9!Hulb-O?yX}YKcNl_>4ZXx+ zYy(|%!pt55i1Hf49bo4Gogk8QC|A*=XRdx{nuby_6ahPe~!A&cL`jzBRYn=lf7 zm7E+Yp~f7LQ$1qjVN)&pxNw|q%gI4{J;<@`xs=at_(pUyWm}QUsdMW?cV5~7$oK$dLRZxSB-|_ck$;1pZoJ!CH zTYH|p>|)k}=res^!y6xOcm-I^&h7Ed)Q{1@Ym1#<0=fp_Tp>A{8VRKhXU4)3ntgC4cO3&3&V&VuHDArw|Li=A}8ITOX{k*+L&ZwQtN^ z>$LW+>Wo#~uIc%IM7?!XRNwbLE`p#^BHbV_MCtAn0coX?Eo+yQXKp^IpI8S-<=DS$Cat&$;_Ndp~>chej(g6{*7C0H#$v~PtaY(B4)pM40wcT@fyixc7)Rv&<4 z1)zTs1|#FQMK*rlWysZiVagd5yqIT|K;!=AIjEU-lv%b~oj2W{%e6jORzcy0W!b*H zlp6M!=d-vHo9LBr`sXb1B}D;}#9}eggr{eF7&$eosa3FSvx@)cIH59rkn^*kh|3J- zPW3Bu9fp@>J~}i{WrYhhCtrIJ9dLhBPEbBNJTu9Qu@lIuruNa4Z`Jq`cQ>${+vVFx(LS4;(huug`H_XxD=EE$&q}x_PSafNI$SF4HgLWM-59n|< z4TdE11%f*2{3j6kcW2bmL2OwQtTA|YIVOn{U#&!;b^= zw0s+OeWXTzd^9$K=cw8^t6*)Q6VzP-&!AQE2yZDC`p`=|gek}ix4GINr;d4&)gbXy zH_0lQAD=vkrS;pFFf0C6kKgUNBDqCEp8uRWzQx1cDIOH`#P>nvJxmGx?wSI_uGqdx zNz3KXH}?JGYmMdw6v3~!J-s~f2n2u}s|b-cKo7lyK&Y;pCqcbfNkkQxt89d-n9aWX z_L}YX@QS}LB?a4B`{0%uAA5a(n#$XPe|_s|R;dWdCpS>ca(xH>XCt@dqUI-6@4TYBZ|9$N zF%%2;C7_OG%$sYt#b^r2vBS_ z5xh&IQou7Y!V^0=fLcir3MGci>m^jPc?xV@k zPnFYTZ-zX+y?2+#O2cjBC5I2hc%7vfMAWo>W*PCY#LA*rhGxX+hESc7H$3h~{8i3K zFmTa-)mTqnMAMZr>T$($;-w#)dm>+5pc5b#H`}p;{v{T8(3QU-O)aWldUn3nu^%OQ zz#AaO$>BY4-2c|PR*u&T+oTx9|GYHjtAj>TtY=Q+WC3IMe^)tS&*T}dH^8gnpyTr%*}tBu?_T3#w9&Z-~(L~i{6e%<)x@w_iYn1;&eI~y1|y* zHQFD|togt|wDWs~iSdMMhgIaK+xKj2ejR)d)Q%ju1fU2DO0R04NwBwV?SD0QJEwyW zaDXv}b%6f0&WjsTf@RatZ5ZZ0Qu`WA(aTo0L5FvqQsVN@sAO!^JiUG3vq>utkFVls zl3qkA^>1wk$ZqmQ9+UElwj9N{vchspwqd6dH;1uKkl#6B=tug_+DAl2YLptzT#Z8p zQ1wmg_oV%YVpR$nYC3iA`@WNgKtap8TO1;~K@2O3pK`{-2uHrW;{d!5p>pmA-vr(F zajA~J@gUbzOORAiQ+J)+TP|OI7bmeKnHTWsVx`k@_C`p&Zgi;gTE753_O>p_e=&}b z#3XR8K-zhqfNx7dR?=-XOiAUE0r z7DPDL`c|3k{_6=?l&T_z262-YcAq!o@B(N~_1^~4?@^ur9SQ~#VBFZHDfZ-l6ZM^@ zK9=Y4fJf~IPhtnPhDf_b#`^cFAEcy|>3`BjeqU*VWyF17qgCcn#`a77!1PK+Di+Mf zCO5q5b>~h+H1auWPUagwOH%QbCLMi;Y|$;b{vLep?%PrHT}?#S+sPY``qwyqFKCy{ zqh@vsC5eY}h%#csTRK&O|5nJLdFjCcn*(eIyhc_^a{E5Xjb2uDh`mTDH*ofaMYOaF z*xyCqosYBGeUtfl1aHtmZLLV9HBoyS)^o&#EfkPq%hgxnyw3J;C(q!tH&`rp`3fD1 z`nB{W$L#ajup5m0+6{Ebdr{L<`ksn2hV{qCvU>48GdB94<2pHExwy;JQ6ETB7Qr8PXhMRG-5?*y(CpYm^2uaKysX4rii$oSV zt`6|u_UknO7r0g5hWG-O#4?y_4Kfc>^80a z2F8m1!e~&e8i8sKlG|(02TXQ6j8E{vFP61CmQhpweS^I>zmoNo{Fma*LnfzrD=sjH zm)hs1i>S0qd!dKwXxWEq0=ZH_%1W)?qi#%XT)>>nCF;khbb$B8#)&L-=p{YpFQjeK zBuf?7hxhnBN|(q;fIr~gZ;_fW6x2b#Tw~UV{8q)=bv1B_UGj=*83@szT*2*$VGb(-j zEt~`f?E>p0f+`=9L*|5%WYK#Sn+rT*)!kd`7MDAZ@Mb69eyb^D5hMDljOEMgf4g~0 z%Hqj>+th){l2w)JC(W_KR(4D-9<}C2GK;@h`l@)d>eWvxubY66;7hM8W9zZe8GT21 zKX2~!JUgIyVWUVbjrl*RSbh+22U0J(c&cyg<``^^%z)WoNj%uptzlg|<`aS3-b&?# ziuCpZv0TSjRI=-ys_SMd8;76UnP!qr%<|v2r9!$NwY9!l;7Slz`N@wfC)QXM8QmL; zec{>`J?{+d(@0jBDGl10IS8kI8XlQ=()8%9eSB2K`|&g@-=U0b3%1#JC_37MvnJ)= zd^{#A(sY{AUMKmo4sa2=R`TYb<3G~zVbpY`>j`IaA=6>T2PPV*zYY?aXj)J<%E?ta314}ce?jC+U(=7Gv56rCj|^tREI5@dG9iUO@^;sDM1Y| zpmwWh%#%`W)k?vUwW zVU;Cy3I8zSz~FOjSOkl3b5AR?MUTsEX#@KNw5oxft5Qxyz+SW+;Njx5uID7KAh*rx zJR6%j%yg4ghFs^^)HS;v1;EARx{i=}QmuwS=rsiGbUPwtaaGyI=ZpWeFpFLTJ=VDYj17Qu-DSi-cwwgH~HR!9i#ypy0VDtPM|rw6xe|rxUK7gA8JEE z)P^p`v}7s;{wK@5R~08rmzdj5Ak+1bz2_h`n-}x_kbMX|{O}@w<6gxLI#E^EZX1kP z@-FZ*oDNvc*$i2YJk&g6@Pjow5LbvnKA@Hno5}RuUxL@cQ z2X$~4XQ0m^0JQ=x@eTFc7s|=b5 zy6OV4rDEzk`($@_y%+rl5IDsQlnt@S44SMFGrP*GgOvIL;XIe9VLQ3iW-Cy(2_R2g zw=Q%dDAZ$hI7f7&0^&63$XQog;`v83DEKRn*q`sWZNvxR(ch=Ei8-68zQ^Bv)@&dJwBe!ZgB=Ho*RTX6luGk`Fhz!J3b~wX+nF|cXXNy z^MR@#tIho}~eA(pf3InnW!s#L+FH zWlRJ&@kt#KVOrd~msZazZ&FmLkgCR7$8PQ}WLWv3nfMMU`%J7Zj3rZD8i zwq>@GI}OiIHPdjHI+3PC$A?6D^*@C$@tYOmd;X|khA8%dC*k&GRs>Q?p@FGDe37>B z<0>7W&un3X43Ciqgr6A*DiX_!>77f;1j+*+={;WeV0it9ZZbv5o!iWV^Cm^}{Vj=E z@U)m*Qp-%O&;Ll0u)B5m+*n=?R!BuxMBMMCDuc?E>3g-=w75p!|BD46X50iFcFPCo zXz;C%M$FRjLlNs*kQt+O73Q1|Un1;Ns1yiEN|ChqU>Dg2JH$1FN!L}dPxffo>T3-h z+zo$kJ>xxGSJy)4N#fL&@h47fL5`fxdP0V}U8~)bI&z7=Rvvl-hG22Ifa^Is`l^=e z?*xqAN1yoMXuPQ)e4O#w5i|#-D8OaiZ z3Te9Op#2;bW#vNy!i~uI%Cc}{wnCvVY4b=8O?|G5ylKF`$x=7`uNiq zrLF#GM%Y90()NFcAt?3Jn{1Whq+D41(k@L&>s zrO1Nzgv2a^*Ow#*(#li6R}vrcnHqs$q!t*G-rH1mE-YGJs>EWf6JWc|Bu}QrU5Ee! z`^!wE+4kKUapO12*%9ZD-d1z(>5Ps({5O~S+NMGdfK4&5y~u^x4|cXJ0wI7S8v;|W zv)HoWOL~ingsoFU^i6x3Rt*D#SdBStZ`}l{ii@xA$b%!l^DBz+rym>EC(6}*c{qg( zbmFHSY*hbswucrszD@FA8R69kiuj68)5SkYQ@lGPODkv5)+~T{%zf}G9^|m~qU%#Z z#>fs*47Se7<3BN^7b)ZWk~)8<>i4$FgUQ9`PRBMwQ)(-qyC#ObGF!5E#rG8r zQXF+57|7-QcaG&Ep!)?aHt)Vs4yJ8jQCv(|Nj#lrQtS5Ko`R{1)q`QHjPoP^mi}-l zC5x?-49iqTiaUbhx{6T($;!qY40wnR zOHIf;TtOxldn<^lN0;-j<{vSPetMtR=j3_S=mVEhOPFOa{>l#4q#EtF;UDo>fQkRW zYUcjutJwXFRVwOc62Q6JTz@8!_~}_-&)zP}Y0K0RQ3qg_BT12Mcbw&X8x3=qRQ{F3 z9lQHu*-XtOoASmq0C#pxLdIiTP=>m-w^tl1#az8$X4c;*OWnG$y8Cc^?|Zq@T1n)F zd{!$neB90X=8l*GbV5NCUjOhlij`*T1q|D;e`oLtd9)46LEPB4taaP_m8pNS4iGSUndN9ny9B+BN;`%}>ByH4W#ViMTp&{gOi zo6F#ko8)j{F-sb2`xrw8UB#*GaAlRDBdCU#@fJ{vMq?W4!`A;-GR zn<5Rn`);A6fVyA2MpREl)|HwH=FNuHm6|Ue)@4y>pnt#9X6M(C7UYo4<)@YvW6X60 zskX*hFf0db<{`S-aDe@TY(PPM{m~Y{8@gi;SB)S?l>KiVJ^ku(_$gTSTJ~op9Qe}^ zb2c=8VV2QzT8pNQ;ZEuD3)}LHzv@{Y58*b%7p-56UwFLjHvH;_Y^#b=t;P%l^8!FN zSFq|SDL~2Ne2DDXkxdmo?5~u$p^0|)8xg|UhQ#oLZ!NE1)2G<&*w7d&?xMs9M!N%U zsd>zAG9XBl7zQ{!X;EK3t$%lS*n77^t|fsnv1obi=+*g#+pM$OoHo4nu5+WaX`J*_ za`DLzla-)<%uJb`xDqscruFWdQ%?ph>cj)s#czJWIy<>^|9TzM;AZr^?@?ZQ#+ED4 z?5g;XbtIVxp8q2K3MPB9sQz7)L_#a#)chxLd?F!L!O;0kSIEvoU7a-YxNJet{e+bR zGpo3S1Q_1_jL+m|v@q(s;MwqN+<9f5Rsyk}E3A@UU35E~wwT#gc}i{~YKmA5d}DEN$9DFWU56bMA>zRrt#;xd+YwexWY{(Z$px7@t{-?)Af?xeJn z-TZ`d&C{ePS?|its;l%!LaIbQ)0w1Qhix5gzk}hHk;?MJqQ%scfE4@t%&C51hzcG! z`s6uDYfPuW83jSEbVm)-nCxnKotvSEmJ-*bP`$g}Ka*DXv9S>eBxK4caP4<+&N|SS zctb#-)nCAbvunhV$D)^FrR(?e&e#^gRMkK}0cuBni|4#Gg3`6Vw1<2~_4YtU{AkdV z6+i7&m3GHpd1+l%82H_?JR)~Wn1BG#sd9p;*Pi%tv;`jSX=!U-;uJZ{nkp1g{SzSO z`uMwE?ixkzLx=KftJb?c$jwpUjOpw zc6Px9h(#^?1Wcb7n+2N;8NB~y5Yrz_<>)SZuii8oE_)-EcpM$Rxw;(rCR264S{Ge} zROB1+&{iUxH`_fnyCqDu;|WMGj6y5g1u-;iHHmYN=86CS|P2e8ST4Ujd5a7s1-WDJWX&7bh z{~-VfISk{E;NJz=frwU3E)r?~*`0=z6bbcA=8yVb>j%VGP%#v?a0x_=)}c=9F}=BK zJvY>uvPYi|u>t{d=m$W9*^jv6m+c`~3CKem^^D6+nd?!v;KM^X7`i4$l*!*6blK&5 z0qx1`eyGC0Aw3nKx#zqE_jP3_oym!Apdnm*1)|`5M{y| z9qn~E6?Ec-KAOPXT|0%M)6%pgyqs0pSxr{^(?j3Xa@7bQ`ycmd%upl-0l#Pfgs>&E zFukxw8$|1L$PI2ZvyZ6=H^MX$>s{I_E2~)Cbhd#S4l<;cHrB?rxqilFY#JoOC+WL3 ziI}4To8J}mjH9A5wu#RL^F;+?fI-VcwXu1O%VKXXi}91}mdab7swhJvD5^b_&$B%v z>Z+kXRd5j>J9Io#N>3GRqCKTyC(~w~dkNvAT1KB@ z`^f8FI1)or!H-I+K zi|zDdu{}M@F}7i8;Vxks{T?2yJo!+FgnwNNzWT{{;Bz}($ll23%a>nGXB|BHVANNd z&v(EpaaH0tkpyUl?kOfA!-G6(T5C<);8+&ABGt=9L#rCpu)lo9#;a$zoE=ay#h>j^ zM?+f?9<+ZhHx2FvOobCtC!W)Qd*#w?4+eCizbv4J>g~#w+%w z8Q~-{ue91tU~Pn$n~_BV74~M=ONu?onc$PX{0X?;HUadUbXu6to-UG%yO@Z|>_*nf z9@Vqeb)F4?($Ykgyl(ZxI=#+omN6&P0M84R($c_1N3X%P^~yRdQ`2qOdmkQHP{Fb$ z2*e`lnfZK3TnD!6g>manWSst@ffGo^9a_ zZhayW_kF#qh`h@eO9chgg(9M>d=X<$Fn*AWJg|D!T z$PIG=WM>(z6bVE}0?OB}{qi9<9k(Zfz@wJKQu~mu&S|HqMTEvhu9zDyr2f773sCck zVREpwSsh5Xt16J}1H&Xc7=xX4^{Kwd86|ZnkaJOBv_QuUa1Fz_>^FzvSw!vLFPq;V zl}RK1+FW|fpExn=gJ6k)_5+&>dOm~qPHtH4tL$?|+~Lqy!7Pr~b-g>OhCS!uPHtTR z6Q%H@+)5E%V7+4^Dadp8sH5+2u+@$RX5!f2H!E{iI=nL>zj|_oEXCy+1^s z9Ln|Vg}GUHqcH*Z>tMrs#56A&eV|ES`O?DIYLRX+#Gt18B(7q-OTmmj;VE?irp7D( z9+{Fd%f;7o1$U|o9w9V;>xYdGFJt5P!0t2aM=i>!>G~756TFg_B9~iI7Urr4Q+Zut zu11hBLtsbetSP;Y4`Mjjg;EL<cGZ?+0M>~-wVjDPt zLou#pQ&dZTw1yQ55i zDvAg7ZrXySWeY2~UHzObau-w319?=x_vT`x>fqdb1vKF&sq}FQNA-P5@n4#=%Ukd( zY{uOG#RA^bJNLb};y1SCe`5QnZlS z?<)I)o)G$r62*l59lw^_QZJwXJxjT5JH_e-xhp5kTfw{=_FJ=nhqOGd-2Eof*sWyF?T(IQq})t2Ad%-jgQ}D!P*VxF)VK}f=4MoWBi4_KYSfmIGCMQx4o1HRPS;*_ZRH;|hce`g z0#vlBiAcCMNv^e?COSa`>ON*_TQTmJ;j_Lr@tYChyUH0x896{^hONACaSFs4Qde>sdfESo(4y(sM z+XVO$^IX>iM+h2pd6mdpF9XeLMU#(Io>juX6_EFjn~#;oc@13D>f|lP_5V>fM~^^I zlg5`-ht-k|>XaoeYe59ZSp+DZ+%fsC_lIz8dR|7!&rc8h8Ms!gWSZVNKaN?`cYG&A zr1^HFj9d;Cl&H+56g?hSOdeFOQQ|r#au9#iQFe|vC%niR{yW`C-GNYi&tG+TM6Sh4 z^nyV8<_Cw&EsQT{pFTa2F9gPX<~PFzW2O$q$Ys`m)~0&Pl$(W;q@aIFYFFa{GQeaRqnG*n;yE4f*9N+;Eo@WcA5r^XuRP`3 z!hMSKgm{H74Wt-sNy{cD#J>AkOqdYiyh}*lVeAFXT-f6Dd}1dRihloW@^*IH9F=FU&TKlqdn|b_?#z^$T15QBb1*D>C_+u_m@*@a zu9^7M-nQ)Vlkm|JaonzdZztaDv@a2FCwlMaMt&Zr&?U%S&!IGpZLvD-bSLZbWbqRF zJN3kdjiiR5L{y$%W<}SSz zP68@ux{5F_gLI+W>~j4;mhzJA8f#0dTzN?M#ePW^$P$-OJo%%Rwbi*P^^Gg0E+R@(Lhw|+b&gp;hOkNoZ z?pb*?vWriOBS@m>XqCrHy5F*QbSaKM&9W4%ejwD(b{-HWa-}2C4cl{l5!>}?P&0rf zv(}ozv^1%ql~x^Pvry78^y1C$^frx5k3x1iA&rL6#|H~eMvjF@fBXh=d!3`c;~7XF zM9~n_K>ePfvPG*y?&BQutNTv5)j|O}*xztfr>OYXA|v8=0cZ|A0i(8D+WZ`XQL<66 zOpq74n%UFSCva@(LuTD75HQyFph;S9KwLRIB}QdDLw0IzA@mxg?>g`jr-9&KTgJbq zq;YkZ3892xCh{)*H3md|)8c8m9E~SVPDCVk!F{6X9J)h+MIK@=oy%+no=(K>CZ9+- z2G(s2<0AMN0{^pkt#_3icsUPSTG{D9vw^|TG^zLU2e2f~Wo^xi`gZ#6ma!gtOZRer zd;8=5?J~8Tcl-SplAoGWI6(6`Q}c$-zSq8YCm)W|jUHEso#}=Dc%+moy?8Cc&(AL@ znSC{U!60h}S)P&LGNbg{IwcWWM2bj*tvX)6hnao0Zog)OYh5p;s;<<6( z|7n=R)5p!GC1}+0)<8DJDT5?fr}q|Aj_}|=_&~J>Ut}l;ZLQbO|8Pzr6A5&;?GLvp zKj{BHHMi}dQ}iD`0i^ruj>pGoFXexV17bns|ADE04K}7|zBn1ltkA@JsWERKCL@lY zNkL1iDlJ~*^$SI1};+ z@W8}y@vDYFC8X4`gtV4`;N5f+gs1?9T60ycO5>ev+0QQ7xhT5b>lXl>D!nr<2y{Qf z6E-9zc_hYE^Dd7-#aS}lu$h+rRIb;2bW-i}TY?q(Y!Cf9Hcf>F?4jhiXGV#biYj=~ zL9G+qvOh>!wK!OEnCg2`NG(3|CbZ8UGv&8mwYpvY(4ehx!oL&%Ij9siJ8ZQ1OiI&9 zl!NMsaef=$OK-jR+to4PuuM@)pYMEuV6Wz-VUx?E9AoQq?b8NUr_Z#csRRVlZ%CJ} zux-To+bl*--$XZ&Aj|V0308EuKEuXh315qnxp z5pnS2VRu@E@Jq3`0?l!WgL8B*xf%Cm-s0f8GbGOC;EKnowA)cZo7MaN$75)o zNlY963eDmtuAL=6MU8rAibpwJv{Gc|!&^O~l}$I$Bb5lykuw!uFZGCtSdn(LvGkwT z{x^m63Mm-?(wf&zK}`&nawHRg52-z((9JZKg5fe;yc|6FG}6}u>5XImDZ@41rT*9! zG>4@wj#m1FQ`MTCTt@c5ZmIF)+UJM_dz~hRRsvgHKLjUQg5LB<$ZL^h z3*UodLK(=|tU*Aw?X+E8!RLjtub2jqJz|GH9MXf(zappb6UlW*DNb&;HQp>-4es>k zUw7-C&`#&a!S%mhL}?9-r&@G=ukaFl^524?&aM#)`6ux>D37J&+R>oFY{C+Vtk zI8U)IfLH~V6DGBf^Ab!Pr^Y+%sJxSk&rF<3<%gz=y;RQlXbUEOSdhP8cF&R#DIw)g znrb=eB7&uHiK*4@H`ITbAq7R|(cg#|_(^lid>Z(N=AMYWkl> z-R|~n=y6QN(&uOvkA2o$WS~c+e-t)OQCEEueVO^Ee5ZT}XDIhkARQuBxZ{_*XUwRl zCyi;S(b8w`SH<1b4;>fgE6lSiwlThV0YSmbN$W9}>jy$16j~JHztTVOd}%V0TnS`% z$*$0!;5Ha3imo4cX_Tz5M&=TfhlG)=sAV9%C9S1Ud*r!yxI8fFS8`o)U6)C0eNItu+stQ0gheeYO* zZ++F=4kJnCQ^EcDRe50ppHtE#GHjG(!s_F2Mg-4y4mB3#o^zbV~9i7Wki+XktYo_A2P^BMB>Td=LjvOt~c*Q{l+4 zUf$ymUE)fvNsf(o<(#y59FxsX7tVro6Zyi=#}r*z@S+8?f%tkmPX0u3T(WfiuV_&sp8S|3X=()HONk4SU-A`6rc10C0`ZTyg z51mwlflYLxA+n6EB=+&&TB+I1pNSAf2@IElMoewuibZe^&yXGV8tKC7X`{{#JV6i@6=v9c3h zJsQb1T|n*sUo7A+zOR`?OHxPJVo0!xUI?c=~_TgtDpd~o%HCses6UBNp) zow><1nqf%{97Rsb<4DhWE4AQfii(m2ivj z4aIfd+fVVTfnO7+Zw>i^uY$ALnGcSoK+yle?*cI5|N9R*El-T?!=v7+z40DSr1%mE z87F`|buDRDaj(-8tU37@)(|Juf1EG&&1F&iq^bnQxUN20Z_F4GatA6L@>8S=D0MVe zZpc2)a4E_0NGe=_BjL}|?3zr50Njb@07`dK(N9C0cDq~{ z$4n3bX~D0j^9!F>ayUzD0J4YhWl`l~ccy_rl4ygud0AB^BDpYle9dB+z!6u~-NCyd zk)NcX1^q%Y_JNp(PxYNn&kMs@VJ}HBQj!%L(na?+g$+tVm3!8hAcxy<5#r=qx>6=6 zC4)3|!nAnZRl|31g1~V1VMXx6R{2d%LoU_!)54uhvOBl?Sxaue{x91Ls_{K?()h`% zUb5s2ZYl5M+N4|kMHcZ#wvmK*D5>gE8fx0F0#Q^Zl5x^|X;OZPvOkVVPRzjVUq*T8 z+uay%##N}lkjzld&cw0to4kO0^(m#GQ6_!oyg4I3l*xLJhLkK5t;721qQD$|Y^N3;~E! zO@qZW49MLm9ew5zak>fD>dgKC8sxl?gm&tqUYl&)?2j2H#Hl zc(xJllXqPdt&w+*_qvgig%aZAdPRP=ly`Z)Y3NNRIJoz-ie zi0R~;{Z%+Gg?%I!MduDLg(K7o;_X(Wg=BhrLAJrg{;{W0%PB9qa5Lp`k>ow)5;6(O z9q}gz0{S-Ohx-bD%rvgw{f`H-&tOvy}7^O*l!JrVPddWS4bD*MAK=~d@wu-lVHMMCbfw{(=ob# zO#g`Wk$8V5*=Pse#pzcWeSePXXRv)6=rZKJ7)zzln+tUnPY_}7j9hGG`G6GZvl`93 zd2WZuS@|bJ@+D3=Vbfyp%pds<%JMF*pB*n-__InLEy%>$-I7>a-N~BkcVTO3z2cLP zgZw6E?2*>hR%hQW291gB&7d$-{{N6Oqc6Gbm0A2<(%0P8`J30-|CkE!Ppu70SxwhB zi#HD@aRs^WH6l*<5w6VvnS8myV?x6nxfcgrU)HTCS&{XjKlI+os;|8sIp30)`+|l} zb-jM=r$&qmx;nlsQ=a(P6&VUZ{+j+u%>BcMtrg#p>3n+q){=DP%-AEfD&eU;{L%U( z{#7`C?K>x$JcGQoDd8TxcuRML&+GiOfZE&o7_T@AN;Z5qfmjM1&ekkceN7x?wAu@6BZJC=%`a0EjGod0s+ttA#n@Y%0^n8~MO zr0osYeqaR$4L9oTl|j9K*xT4TZoWmCbKUXWF z38c1Yk(Qs;%07TqQTL1sPJx&3~EzbH^-qRc2w<=*@nsNF|hh^m5z6k^RwIDP_{f*M#K=&8!qK z`b1QrS+M-;Uuv}h@`C#v>5`Q2fWO}Y-0RigL)fMu9OaKmNqA7Th79li7N!Zv=1gb_8WO@19U0|we&r-nbWJ^wA$CJo=Yi*gmFDH1ol zi7S`o?k`XJSiEq=^|Y2byiChdF-_)isXoqsg-=%I;$AI1Td=VQdl;ca@W@{`3ykB7 zKt1HsfXWxa!j9J>rVNShP8D!hyyqet?|(-Hm8=Loq|2zitWGb?0Yt9?Um2XzNCJqH z)BG6(-f@hiF@DEJ=p`H?l3dfLQ%gb_)NpK^Nj^x6r%LBs;(I5J;(#3JlEY1VV}Ej*6Xa{e2(#%g^?7lBb0=uA4pO*Prgl zqpp-&sdqRcl3%B4*cxNrpHdQ;2?*O{*>n3ggC0;I*ghy}y2IskRjfLim-POdJrXxN z$#;1^u;dZr7bP)zNDKrX{qQuO?R@iuzio3yJ{HLJIHTcX`S!-GY9s(Ar0q2Pcskk5 zF(Ld1rJx*%F{~m>#h&$Bdph5>P5zy;gL8aIPI2-0@&MqrZW_MF+!KfjfgBBd`t!&7 zo%zH^%rtW*_Jn9W06Fj-2vM}S{308xV zGUBh;^^~3s`{8mgjQ}x&1z`7m?V`&low%$7H+o5GEpr@%NbGeU13?)kTH|7{kfhPsFCmhokTUo5 z8Q+YSHC}vk6CGP;q`?#!8kX~H3M3YODG!^RTUNAAQA0}SI$qL&Vev}g1h=8+5yDHO z`v{eb+oACI-iC*_(Jp~YW~TseuDTd15=LQxUiJbSocMkmPKp+bhH5cf$=4Z#|Cw2K z_$G7Jk_ex3h}tbg_EcNWUVfOk%d*U|BX=&SUk_t}6PEigu>Pc34B51mAvb8PT7i3Q;&eg0l2^TV1&%-svpH-x9Z$NhW>E&iu?wn9Chn!dx5w@w z#Yts zTp@lIa2CkxSEs}AayD@`Hx$g8meHMwy$GIJ~IkpUfI#*Xa=wM9SUs=EeL&sC9ms2GOCF_?#LL*m_f&IbX3hm&HptC+$``U}hhHiP0WvwNpOo9py2 zyZ{p&hDK4#q9>%>CKTfWt~lQw9rFe3+Y~(HHj+%kIDt(r^HJ4{@H{c(^|%P4whM}k zpGLT*Ob<>l^wzs6qzrQLp=SXy2Nh+^!9xwWis~1g_anI2`aUTO%xT_w+sFek#t-h+ z9S1}zpl>9UPTJ%ijrF4cL)4n7^nH%#{u^lbMO>^-2TmN5sNT)f=SvfPK} zU9EuNs=CVqr@HRDQH+U3N15#LaalxbJ9<2Rf}!X=*hrlJ3V|&om&2S>i-G``V`Vb; zP~C}q_uCdj)0^GP$mVutPbLYonHv0y8feL3_fd?^gsku2VkUOOn5lBvl9n4Sg7%dT z(f^O8vkGXd`=Wd)Ewn(8;tr*_7xz-MP~4$76nA$hP~2MF-QAty?ykWdLeM}0nS3+z zf5_X-eYnXz=j^rDZ?ENlGjl+py$M!Q3hj0ijf5wq>1TUz2fYYXN`{QSrybUZxO`aT z?)ER`L*mCS8@8^iIrPXsyTp{wFmkE0bFJp7mhO8khNZk2V-pGnUAQYoUCcLMKF|6{ zc?!*mSGV4xE_fGj|6AHw(9P+3Q8bCjulk~loM~z$~xkRwOwC%_3N{(5p zMa3}=AW82JVxof0y1p`XQ^x_!t--kd3xC{CL<-cQETe6W_1lhNiJcA<(w6RgEr-*% zF}NRWqE<9Vh>I55Rp^xe(N@HX6F)Ut_7n|wK9_BD4Dp_KUQGMvXWJii)vB4E4Nmpl z@4jx)WvOuKbuK_lkvkj1Mm ziPRr1KL=cXC><7io)!bg?q1M~9MQf#3j;ptf`N#?V1tV&jKF5nt6@ZlV7kI}aE7Tea-{G03>Qg-&2_RBd+hxJY; z%h9>eC<6EyFrcosnNTxYei{m@T=ZDuGPq5e?(VTHUncBnza9RIyEjPae_a5wUGF?u zbnt=)p;Cf_LB7wZz{epW(fgw5fa9vQh1@OD>l#WtH^@az78uNq@LsLAR->k{A*zW- zKKON|iGj}^RMc(t5!f#(e38ZuJ0+wI(?WoJNN9R<11pv))g2BUC#8Ez-KY63v)*4% zA_B!A_sfy+EyUgYUM5inRng!YliSk#Dm(0jgEpXP2Zu-4naYW2o6}k z5qi?|NTP9b6V#hm1Ai=udJ^12q#40}QR1DIm56}&;D_g2^h3jj&{(X^#>=^cto62% zu5%3srgHmvYnX z+DSa#Je@U1|RSs0|xk2m9+k3lIJxz_KKW9K(|nHZD8Z7P(c!+ z0L}_Mk5bA0KFe276|%>EOwL>n|1rl~Q}>wly~)=<;OKrmxk`Zex_hp~ba{VzN)WDM z(UtqJO6r;3cmH-A2m>9UkE<_QTxtr~&6`xqV<#Bo7IJFI!2)Zs`)?K07e)t#}#2CH+oS}iLgRa_`b}er_jjI(!#<@bymyK z2XhItvh82>px>S@98+18VFe$p)=6CO_Q;uWgw|OLr zly(ne;3z37D8^oR4^nnJ^!xQNuwWj0TMrC!Z`k+1uz-5!>+B54dBMRn{p${GJLP+b zgU`qmxyPnAZrQgV$$y-RC0>+`_Wm3&x7h3UxEwk5Zq++IUu!_WD}KjtSQqZJlLv1Z z!bW`{$e~vOp@mJg+999~&gdU`2Vpb5%8??zdTPNGHt)R^M|GN=?dmGvr!84JFx%D0 zMfsGP4IV*ng#Yom-NUzWWHbPN21jq}OCax;nvJYEU+K0Rtv{%GLD=*}ln=4T$k_DS zyyu^LSh_hn-Q*Mc4hVe%d~LZ4@k`9-aG5x=9ZPNhV8)RJ6#`7SxG5Z+Dt7HE)M}`Db>0S zCofR#Iuof;!{mR~RC^{SeuEjn^;70`S0l^XngErAt{pqQr~&w{8i>_@71(2Ra;;&J zeG`YE(Vh+sv&g+Q+s?fYGWNBiP*7#U!o=m!+VQ@$d|(9coB5d7E;9pv+}BmGiT2oL zY1l;7!|hq1Jo0tae&qqYxzkfT!%CPtF>%kWTGadi(s|DjjA1GMn zx4MaD!Ajtb6{mNm$I%hj@JgUd|1qQ?_mj47IXR`;8YW5Alhgk0Z~~_x3yoa_emdz? z%xljH=2C28ZkqWX@!P|VlX-#Ro9TmC?TDM2w%w^J&bI?L5|ZzR7fmYwj)fwzX=@a# z-pr+Gj*vru2mJ2_NymOTPgr+xXIx;(Z>eA#C}Gvtle>4H(-wz*We~e*k9{v#h`Cu4 z&CtfKJ?xm34GzScrA-w>MRa(F^Qgw{|9n*)U@)!FzjxtCmoqkjnk=QRT?Np?Q%Dmc^PW6l09^924)oipFnogCSCLATdp;)- zlHZgLle_g5IB0uBOiAv$is}83dwwN_ihJ$*Eh?45dEZHfB4DiNWs~q_N1l>-u3n`i z^u0K4A7f@XqfryIKpLnGAMc352)K))gl|BBtuNh%R5?ow515Q;uQaS66d_xFBU@%c@?2_hlGUHFzx}J8)>*A(Z>&}i zZ(CVL558KJ_K>$X^7g(fx|Roy*>=BNO(>(Ty#nL7ySN)vg_&3P4Svq zjrTZ|9}8>4$0Okum~(?DejWg%mmR}`U&~_Sxt+ijh!@&{i9H~R+PdS&I3&cQ5Jk@S z#x2Fcf7_t3l{61aazZXk?l@b)LG`crFIw1Z%#pfgpLZ#|HU<&b=Z8_`jvVR z#tVXhmE-llgq0!fHKqy=UBW8g&qq5Y3;fNxW;`H`^_ATM`!*{}iY@`!X#$%+NBmRj z^+5gp%bdSPCWPIjr#N-4`l#}-2nLbn73f%xHMK5Qw z-tBrC<%%+FWz-&+`jmzj`+3g~d6Ioo-}9i+2v$T#yaQ3_6+|4+|2zy(8JlwtZ$gYj z-F0CoBIdsW5S}y#lPlMaHVQioWgjj~5;H;YKC!>&&|H0>TU%tGR{QGa8Nl`D(ThV^?9A(H2# zr~G-{=)X z0IOcx&x@-i*8cSt{Pk-@dw@lk8&dp`)#N*PYQpD~|J}xQQ4~sO6*`@Cwv5m{27@KA z9gZ39Z?r%SK=EzR;k&=Ydl!1m)oVwAQc)>*Xb%oum(iL50pPzSBJdXb&cnHkCH?D0 zLKu*$L%t;NBYUuXa^;UM_oJ)k9acTf$}JD@zdu2FMN*iEz5dhP_xpgzHj|jR^CmX~Nj3~`K=b>U9 zu7gbfG*iJ~#NdxL7lWs>0O-S}zTVI`JDA03})IrzdF|PY& zdax#P4&boa?mX#l{w*xIYRv+Oc!bA(oO!eTRf3;9iY);|Y+_NWq|rfpZH|#?q~ejm ziihWax^_{SQBd0q)hq;>p$w&-Xq$_yZ)}LHi3E2y-VgjppimUt5E8&vLB~zj2t#YWfwc{8zAGEi zC9$29CgAzvd*V_b9JD)}r=q@E%+Y<5{qlAk(Z=;O_T00W3Yf_0YIHCX2RH3a`%V?r zJpS}qev`=jv@}y*V09jA$?M)<(yW@)w(vVsp;XeTOVUXytZQI%hFHfOtMxr@-ftmB z%yhn?coPRcrzk#Qbtg9QmBt7sKAROzwm_mJ$`gfjw-07vWfrdJ}cbm}5qF z)SUtF3U*xZz&Oolo`&_Vu?oVQf#_9Sw+-&i%(GcPgWaVCDAA(*L??H@m_$&Wu)bd; zBKuW!R6<_}$v6*?**{lnGfw(s?w(S~Uq16y+xr&4$`9_JHkJ8PHXA`I>cXbS968-o zA}!Ohi6bq?U$ES4Kz%gw=E$ovCGx9loONZ4DjhNuBiWzq@aC9di60B)z)9lfw#iUn z?XhkQIaS&X;bHnI+2Hj|BE6HbZMa&p#guhbBiPiB8$Y!D3jcb6xS)LjN6;m_Tu8)tB{ghkK;opyj7Y>M?f zmQ6#emS1LvBi+vLSr58JEUuSGmsqu1WwikHj*TC$qTL_g0-2YFbSgkk75?p)yEir6 zkc}4KtMlEvaW;s7@d(3*_I()Ke;z6-!n0`Laq>90ix_t>spNAxZtx&OnU%iVxFU+2 z@(c-3!UDGKj73#<7YfVWw3cKW93vmS9Pt$vGuZRv0dq2mSm(TNP{n)@OVpAe?Q)J+0C!$1s({o_ts`)~XujhQxVa)=LT+_3=+xJ_Q0QScP=zM4q z#s1@I52Tc@Mi+~LTv(gcn}?C z$+Y#ppRO7S{aj+uC?SWAgQtq?GQ_kvRZIEJ6}1T`;hLwDIR6JbN`});S--PGfO(Za z|NbKko<&AUs3DvFu~fD`bCdEE00|n`(S0AHN>&|IZ&V47)cT-5rx(BT)SgIZI{fheT?z8IF(h-cb zYl>52+vQl+4BpPuNf4W;`+Cgs`9^owwxQQ-o5SHw8p4PaxGZ$}?2PC-o?Nk&hq|I0*07a2l1H%9x}TG{CJl4OOf1t4^e=Uo1|UoWJrZ3~biZ z{+99>MF==w<2e;9D`@AcwD?Zt(t^)zTwvtEc0B5(M?Pv5(ELN)S#S2b;Ee+d8Tyx= zx$#X=JN)%T>8kEQi3&x@RrSzCC4NZjgIKW7_!D}7|K6}akxh4(xye2ujgX89&{ab_ zizQTXo#h0o?=3xFWBVK&F5+5kUB!FU@QA#G%YFH~a=;{fueUcZAtB2u;&d#;+4;IE zUV7is57UQFIPa_B)5DM|Kg3KpN*6hB3t}iidpc$0Qj89kP19EsEZ6jh z8}9tDXE}QvOg^L|&JQxtp$P&3kr;nF6iZJo|H%0huv4rx*_5y+Y^i)~lk+z(S1(CE z);^`MnU0t^d}L?_aRV#wZ*&b~o;xKdoQZVX3j=16T8)|_?F3Jh3|bGtVUEA;VGD7* zFSnSFZ)UEB+$3>**)@oTkaa`%(M&akt5!4*Fhh^Z$f}!F=$7^;w(!iA?96zDgtcJ^ z^-AThaK{c5E9=kHFL=UyY|&^LR(1>K;g#@ieE-jiYmFiY+@_xEzp_)0{_bbPlNXbDDV>$sn-Gu*iLE23rlIRXS%_RLNpbZatmgc6`BQ`<`Z{(xsDqZY#oX zG4#q1GT_JF>iw5Vj!M&!G%?;=W zwNk_wDl5w3X}o#ZCwx=8Km?9QWB&YKd!k*Q9k$AoBGbF~!3tY;XxRfLg~bmcRy@>* zL6NFZS@}u^L2a&oVU}$s84$tDWGs`|xxA!BeiuF&km0vK9^!pntb{C=KyM$gv zYIs`!G6*;rO!63E;VZoRLD{K)*0bzA1hKnpa*txS^g7+Eu+{o?l-+zUM7U+R!xuY@ z7BKDUxKQ+izH^wtH9mPJut=YYNYFT0i`>c6<Dz8k!f^cp)0^qa6rdX$0WZCpl2=hV(mfH4M+e6~WR(e1J_nZtlAyWQAs zIfgX_na*UKgvW1WMTEf!81vDOVj;L7wnH^~SC*Oopn0H8nw~{Qyx*jBqgOu9*a&wwU6`Z>9wAYAuTEzmiQp1d|WbQs#2qr(?8U| zHSO$Y+B`hnn0+-$dnbsBP0r#pem`Z8p^-Q6pz^K;XF$-~J;B@Q&zSAd=8S>xzK9^U zdbiaom3B7++^T9=$O!f%mOLQQ_3`#q>fA?tdco1{a=&}%;B>&xv4TY;6FkMbg>H&J zU-gpSp|b+mVj=Gsa=I9_7w4#ua+^`C?#+01Tt6cc#C@7xnl5gyIy_}UxbQofj$)7= zdwzI|OQ}Zx5?80!437i>SoQB?;{u#qk7A?zA)7v+PTImD3g|f}wcb~IAC~2M3tyio z-ML1^5wKqhedkVjlzr>9NvUPNQ^N3_f=S%#8Gm%EfT<9}Z_C$d#mr$D%;@}7=(sfm z*x=c1z~?6AFZ?59kjm-h(%u!^gP?--cp#H2;pPJYd2Zzawb-?PHM_-~YX zV*B?G$InU5fa|9CXet#C8ul_2F|tW0sb28&x3iHb$tY9fDu1q9H!p0jgAYS9o!E#j z$mE1%^k|&a)tmk#a`N8_N1^q+33J(VuCS@Y($O>v|Db#Ag^6A=%Q42X{x`%uZ$3jJ z)$+oeczu_aO+{XO3BT6n_N5G5mAkpq+|%l58{BF|_IOCoy5!d|F!mb6_fc@9^9k`1UsSZ5u}D8$L{Q9433fv{xX1S#B4N3#sw1aUN5v zxKyi+7~x*!sHPw?8;K>A7%;6j%1lxt1zSsYVx8}@5$o{VzVeh!(V$#7rc*kcE&+=skEB9=?(Q7oKa+ea0EYhO31~Bj)(P1J+F^Fl_> zgoyDna(|2eNr`G92E8<&Qgju&Sc@O4XdG_ z)Mb>c9Fp>9!QoC1{%~sbxwIve-6Mxp-+RDWZ{+J4{AD^``0_rgbeYAEycsS;Wy`h2 zOu0eRnlMMvE24TFGMPUc?e_Q^JIQO%dN}IP?N!?)S|a<6*NC$mV-?4huaDZ%``WS$ z+f-|wRJ5UhC9%3kBx({CDKoW5j|-B=o4B4}Gdhi%n8m>F3jS~mw{oOe@K}!VKUGv? zg25|+f^CLB=dCHX@{~SDQ(67{rj8+TOo!L`$s%Q_{?hK}kh6xZ67wT+(}+dE^!FEjhZV}l0OVB0(d4{e8l@V8wR>tYAU;HbhVSR@ zh*?ZuXJ6}mi`bkZ-^J9t4^lOJ{zEnqMDOEn{bE~jxbKp;u@ks4} z4}ET&e_44QgBd^SN37lJ94t*&C!3bTl_O~o2D;J3RPG^=%R4#D<=alS%hT@u{z0V) zHZ{_`&X5_!ESebCLN!=Z@)3&FLxeq8R+C=I^Z{F31?LQ0I0 zq5ld&3@yY-SaO?4iVt=%4`#KC(RmcdR}wA8)BR|(%8|Z8wXHlCUUJhhik>(y+A%1o2N*tYH@JdhsoAc8((ri=24!=r? zI^+-appI<$l+2-CSYIi!)c4$qvl;2=jMDVU)jh^F_Ilx7TM!4FE-evH#{V|x&y9I0 zUwLf~UZB)j_(#BGWymX@XkPyUB_zuZJzU1*2%J52D< z8(l-Lk!-sjB-c6Hv<4x$ZS~YKL|nbsKQ8D<;v}Tyw$Jnxsr6S6jWA5o#s*GNxm$M~ zCkP_Sw^FjMR6N+vOQt62i}lR@rv=bUq#k}%R8)w*Y}H2_a9sDO{>8mOn7LoA=jyigaGzt#tTek46KF(-=p6Uqna!QK*c z{AbFI!H5YQ|LjM8Uh+fePr8{>ote-L(Vdd8-V}07Ui=wl{ zT~VFiKid7VbQLdOGi8QJ%mr3SN=Z)14BG(jdD%J|Ou8U2LS#vhWsNbj;p=P^|7sF1 z0{69Gx7_GY=`AizcyE9J><#0TEBMuQ2}-AG{3b~c}1}OE6fPIAvGr#Vs8}p_aZz09VC8iS|a)nF8xd(DTC(8?dX0( z(SG+At`e?ites9m`M>A52s4C z$Los_di3;^iVWdx;mSBU^HALPe`N=Zfg6y0$i3nts%Aj6gxO2-x%DfUVfOY+Qv|-| zGoE+1*N)eZpX}e=e8E2{w1u(KxdP4Oz7DI%yd(W?tXsri`w^3p)q-uV{!r6iUpUD8 zld3Ch$a@>ku;2oLt<4+*qfe0M=_RAQir#wq<~>$1r8#*yOCEZSkWitM_4LjM|71pLR}z8 znmVYG;{0CbG}5Q=j^|4pUU5P0naEIEx}`!4Q{+a|5URAP=m_dt$| z@0N8-9%^!@ zxy;%K)cL5hWftf)o?u}xmDV?R=I=c7V#978&joph;rL$nQ62yh*l z@qRnBEM_LYwSSwg1c-~A9FFK#ny|^!=frAPS({qVOm(OohulHCuAAI`kj{N~EWOwO7s=$F+F?VL zewB47g=v@VjtTVc!-O`RMmu}s3ZxO1&ix;zjZgV99oYIYnbN&oHlgQl$LQ0VFcFUT2bD6 z!}Iw6S=~Su3 z0o3t-X*CJzMS9|^OYtN7hq_DSt2?bNuYF~UB5K04rx)Q^chrFBOqr&JD9S)}vNlm8 zFRF02{FA@jZ*>&0N1AGqMV5jKvl981kW;Vo4*(5TmHr}bU+ed%okVWK`3AOuMzHwJ zXp;%_h|$pu1sMD0FTC%?$4DAyl=(?-zDy4cykOJ;O(-5az0`*wRO(G^3&FOmp`uhc z(nNo4#S-2mYT>Fu+%Mb}XBSHKpmx2<{6wx}jt@lY5>I~S_oVurVIvNbvyEc^Ccv<6a$i`N;6q36p^LDP z%pWPmD2A{F59d6dFU`EZ6xXS6usldu3LWea=NM>GkYkh!sGOJwJmZTf`ti9+CkgZw zTMU*)$OxZeQjDbl+&clOvfyl4RX5?qB+l_ zyk{f3E@cy2VOhH3m-}7BT_&a))_bHPd2yCRpALfG#ZpqtVZHRSQ~}WXT?n6 zSbB1$zOVGhiu}p)r*kFu#UsXcsz`tG^s8@0mi%E%+sR@v5f#h#oAAzxk!vzhyIPJ< zEhdOV9!UQ(>meZxI4R6Fm)9g)w7$D}X9r*t21`tvceNmp=6NxuX1aa`o0bx3cK}dD zmvYVcWlY0gnrz>WT53`(*4$@(uXzfc+WkX0mXXjx#P*LfnImOJc9B*hBo7Z=tb{-A z13EI9W3+x|?anKRJ;Y$FO>E-L{P)`yX|#qupM&6=$U4*)7F}1iR(Xfx4S5ce^H`NS zZ^@6}=RqIumfksg<63+vCY9x*hk&x#6HCh|!ye`_NeydHX68AD+`7m__42l(0Zt>D z_tP_w9sD0nKj8(j0o==q#44}Nnl3FLH{-*I43SMLQH%Qs7eCAa_;Dxd5b-V2pf`8S zxoE&N<1c;$3vTo)-#;jxBeP*0z$-T_dT5mRd3e(b1KIS|?O8hdB{>h@rld3BNhTF* z*gS|K+VJZ1@#B|+kwF5`;Su~0BYqiY-_L_|Dd|)dxKk3UMk@5dUT$h~j?<+11;DcqJ*t_`1ScnfXO>NFGx!Q8QQ_HuuU_kj8fNt3EPpD=Ppv4! z%m)Ol+OcIQUmCpUEt`Px1nQnQA=O*I9%LO-Wdm;_c8B;88YIw~KdE>Ibaa0xL2v5O z3JKbbRn>L0f7G)xKOHcxqvZ40p-Jwj4gYlz%pAL<0(iA$Be85nMdtdM?+%ewI%j&; zG#kECjCrdK%sc%wS#PjspBnM@BSCLEeT?X}9O#^d{9d*9nsNuh*KlO_Eua<7Vq zj~Cc|!v-nx==^Fk42cmGXISr}(-&3>)Z8r$a=COXVazW#dsL%dBys&-b_|D?j9~uP ziz{S@t8a3bQ1AL)IfMDXm^fYy#Ljy3XN4nC#s#~u-31Esf6jRGF_waCd%yM$DQ+-V z^}-DsHSN)9|8PFY_cP{1?8FOsscK4*-(y5K!iVs{`lI_amnQr1^r3sZD#xdnGP~*i z@-MU{1u4$q1r~}+>i%n>$tuRS?d=$Ylrt%g*({c#)5-6kB0e%RZ}bn?!yJEbm_)?$ zNz6@7evU_F)(275i650se53YttXnbju=wxoQVhN!nc5+jsrFuWvMK14V_2*`J;KMJ zW24rTQ6jR)?{Ujh?(eC`y8Bo1SllY(n6fo9P(l)$vG=|hO?q(tu0tB_GfyCPxtf-j z0?1NK0m`!*REA^<{%(Sl#?aj0tuVXmq(t& zv(#GF{)$Y@wY=ZBEC(h)z`?LXa%)yx3;<}VZ$3Zh;UMDi9O)+0kGy)3^88Sh@&X-u z#`Hd{0CF{&O#T|IKv-7a*TqT64|)WvFVU|Y=JB7oUd(@soAVPm{;V->O>DOL^<#U? z*T^oAbaYd~corjUnPSg=U-a_#;M%|6KB_AX5}l)|$oONl`P$?R1gOsV)^xPJF^w(< zCJl0nF<1?S{!t6)1{sMMLV4`ONqV+sYvU$9K^N27J#vmoCci5D$*A)cL{Lz5Zvl~H za$^@E<^R(HIt36i2?Sv~LpZx!S7tfTxWnRC(5i%FHt^z*b9Xy-IKe`6t6vpAgZBbS zQ0j@ub~RM|yZtffnrrU=4a6hQYW^XnYkmq663~tqR$0@760qs}?e+~;q*Sjxtk!tJ zul+DPT{a*5{ZBlMC2Sts3tC{uFENChIF(&RU_LlgZD zsJ8TJAGAk>&M65Iqi_;4GxLFl*%?|^M)!=U9iK~us#9bd zkkZp!rBhJAzN5TBQ-ID?NqPE9gtG>^7wrnVDklF^8l}1?|Cp z)YaarB`K{+i7Mj0V~BBTG&`|m3I1_4^-y>3VB6{L&C3~S03ck^O*0fb;iqGz2+;Aq1)^u{4s{zW%$$PL+*F2x9t9i zF?0hGJFW05K70c_H!S4{$fR1Wia&cuE*nz zhQ5y@>yjq(@tBqy{)Q^@vi4vda;O=7d~YNO%T=DV!o}=RI(3*v#_Qd&f~Ys~dp;@e zASAynquoxf*RdY4t*ybk#7F|bHY&~NXw&e|(*0GcK2zh`q(+UxX>(}5M+rR1UYJD5 zb=cSxV9%-j8<)mAcYmr{H@aP?{K=>^Q`_&ozK>{dr%{h&T&ji}uVX^4DT*tEV%`SvL z+J{ViR8JQE%BfoV=)^t4Z>3I;orkxqE~!FU#6Qf8*@z<_pn1eLga@;kIMgW7`6aGp zPqbHZ<;N$NpcThZF>KF|Y2r!%2s5T@Z17B_x%@tvtueU071191jWjHem`|mHV*~8u zt^2U&$Su&454N}U6~~RO6W|!yd#AaeJlBq}U#CXLN*0S}MV^(kfBm4-NS?N9%fN7G zrD>avXIl3AfphD0%pYxgmpJI`Ce!Wy#gZiW8$l2&jTr(BCk%e(ug4B56|C1q|D9YZ z%xlBSa_x1Co2}P*U)5kR^v7ZnONrr=5)dG-Z05$>W^=O-p%a~ceLqR$SCF`Kj+$a* z9p(Mez&Q`|k?i9GQtt+^79Z*|T02{a*(L<-|s{C8CC|13c{| zJni;RdXW!fB_0=EY@QAU^_J+H@!y5gF@?~(hvkakysmc?rP!CYPQzqo&#df>V)L!9 zLO8#LLj|aC37I{7!*N5ApP!%Cc^&Fk5m9Oa&xOOHMGUiUDe(Pk^lq)%t*5+cpx1be z&ApK0&2QB1o4cNY*3Ra*KI7p`*R^@WmF1r8!?T)B$OeeQ4^~DmeE1E1|8RsC;I~?_ z<%=NqHhrJ*17P%qI<=07u*41J6}7L5$BZRC=OHp;PUBC|!f4qr%A3-@ZB^fr+U6gy z0uUyv{&jjwcANPgvV3w)H=+Z@Ch*V`#it~2kyax7ax&=Z)vrNl=)48TdlWrSmB||F zX}=tcntHBIXu!#3eFP2I1K-tx^%flkfC`6`2y+bmcd)XbHc}9l zk{3a*BN&LV$A3Kx&Yk%D{{g%1AL?@mH;LyO*Vk`|+`D|r=aQx1yZq0y559*rQGZ@w zhos$LtsK^RK17-dsQdYU(3whQRFo>V$SLB@N8lO=iYc$TsIU&vl5y4iE-fdX;;`8U}6!G*+D=9C9Ed6A=KC63GjZL<&{}TD+th`X6JI#Cxsk8|TP-_e=9h7t|l^r~B7Psa3xyOkCNCCh&k+i1JK z=|#UgiwauMLNW7;#yl2z*}0!zjKe5&XPRuZ-Y-`^=03);>I~ced0iD|4P+2YslZv^ zxmE(08rFL1@v}5X;L-O~DdQbXapb5bpjCAj05p1^5orQS(MVEJ5=ArQmPJ2R6F@oM zTJnuGm)sYm-R66;m5uKpIOXr%>lNhP8T97t$r%jA|C<|o_U9;2hU|Tuw|cy;+OsSD z0rbpc=b0f7!^iVj_gl2;c9=9oa=Mivj>rr+Pj%l1W zU%d^{fDV-_aHXMEPZX_FpF|N`3GWzWhDv$zZQ6TuJ{zt# z2z-Ie8?qhuJUA@BKot1D-oX+b-vB5a3jl*z}UhZ(Quzj+pk{5%WD!d%NcbdKze#pX#_MKFfw?^hEWRK8N?mK2Gt$+qHRe z?z)#LZ%1gdZ#RJ3!mP)Jx2g1EXX82kh7~<<0O-Z64Z7K~{eIee2NBISitwTN9MM;| z?+*_i5whsQrURgZAF&*uGe_w1k_ne;Iner^$BnSayFQy~h_bOD@oHVy_vdL*oz5F5 z2nNwe$uuNFZygXXb&P&bMx=Xv*8{N)nud%JR<~Zs=!cEdBdv=1nk$Z696X# zK1b|^=AV~{oQ1+c=s7H+H&0?O1Bmraj7QY}+DZvNH@u~jxHmfO<&;nX3OFML!teRE z9>MI-Cut5iQW#hBpqF4|EYWL(wGY5%56=(E=k4}gf=2bgcRIv07NirxKHdd9t+Nx% z-wKIdhazUJ`-}2OnZ&%BNhOI_toYO=$**uKWO}c{*ziaGsyX*E*Un8BD3vBR0*DP{ z)n5R0RB=B71{DD7PlTfD5({h}sz?|AjE0L}!24Rr*4Is>z7LaYTrUKP$zWmnls1t0 zFen>}U;l6#)#%Tluw=k*`*nBqc(QEORdq`t%ydXxHSX^H6d~(*5KD{G-Km z)VuHd4dvi`j3+BHU#!P^qopa)wyGGfozkR&QF(BLAwHrcq5+ZW)n0w`W^6gQr z^O7Ac;rh}Sa`44#d1hD>Imfa)cs)5=dbEkfs6a!|>e^2|NOe%d%CN3GsAV7`MeS{r zQl_L0lXJb}cHqk(`m4+R43DV#O5eHtxlkKjbb==I`8c`kJC6-W1F1bzcaP2b^!2E5 zDG7)3jDz*tlS0}G({O@*`@a-kG(SEEYnDtD_nfash+!>mn*NRywhT%$#WXT$k~g(!(kg&!So*dBe$B1_5~L&uT#!@w;aH`#gVJu$vS< z5#2F->XCZ-8NucC{sQC_CQ#WZj;2$6$o4erf%pV;pFHP0kF8oLzF~%+K4Y%5pS&a_ zkiTX7{%SBAemK|l+TC_j*9>xv-Xm6LlX&EvSoL&0&#YOc(*P3xkE@IdU^A@q9<5Iz zz3e%9G2Cz(Q5i<$xf0}Rs{~gw(7OFY%;s*fUE`>C@d1Mnu2aI!gNo(z22fCqmmXwl zY;io9jr~Qi-W2uV?_dpjrzKc9Ai&0R{V;2tm(UzGuGH0$Tk)_NFzJsfcgn2AuHS58 z>w1KsY2oCEDK}_S)74$DPWV%b>gLFLjpsaNi!P!Q%l1QJBGzSd8UvCz1GiyrLW*oV&gHk;k>FS9$6SzIWM`VO@}IMH*$rkf99X zJv<5;Ez!nrjQsTK}OJEU!20*C$};?RXA3^pn)*u_ssW-kS6a} zrLi4~dv$#|1*l&dLOdO4ed;^2bRL5~3!d23r+XDw>R z=wK)P{nDGwnJfv>(T^0M(HGWsBcZgcSk84hR$P@D=X*k#ENt1TPx=cDV-w343Mold zQNy}XzwZsUXvf>A-?3iTAiUjHcx$(xp&RTXz^e>;JqIo;(-*Se z%P=2U4`qGlWl#iYDsMdT12c2Rfl;i%h9Y+qeA#1b{4?(1b#rWJ8WSQP9Ev!n@0{Ou z{Dw7UVPOJdqR*pY?p8=;YF%Y{I2I-aqX&tSGAx`p88*Q#D_Mra*;7IR!&kBSIkubi zO)0)hrR+5|LA=Q=G+K;6ivbX1jY8q%e_B8@IssZ7sg>38@s|!*`5vM6=f$>lAool_;4mX19Bjc$dalCsn%q=b; z8$h@Q*Xy5^*X5v85od(NrF7R;=zgJ|TV2yDKu>gmd#x_5cT4me_`&VEre<7aELk2F zN>=;Z(?!Q8&G09L${_}=KspALOl6g^m zu_;Y6nnTZ3)EyzD7tCx+!tx8-I+>l7cdC z2e+l~3+X~!f<5O**EAnYEmgf=pv>9+e6?=l7ii{jy-6G)1bMhY(!?=kKVQLxrPsN7B`wDM67GuHw5wh1V-u#1?miwf(`eVRzqk@bE+(c-v z!12B$(Nh^nr8=P7x$6O810I14j351Jm?ZZ#?xKXeOG6FQLt%X{atZi|e+ZRdoDP-y zNa#Rq_VA-b#-p(vb`p~^eD1^F%XuFK=LJb#>a7%%NWjCkRZ+VZAqGCJD*KORFYsg`rML&>SItIHyM%?w>o)9Y|?(lX7HOO zinMsu&%lX5NtUf|DUY+`W4e4SF`MZ%|1H3OAach0l1}Jh;p?s7I``%u$jQ0N={*Yp zYFf&`5PIlZ{u?ygb0}<3XL$&`+ebJL-{K{$*Ivs?FiV8kBP?P;7Jj7Ie0hwyW`zYP z3RoU&`U4)lrr#a&MW+qI>PljrbnbNtDPO|$Vt2Lgc($$S3>9P$#32}zt->21@vdS_ z{pqSsv2@Q2&0dvBo8Vc#&Gn&(2lqJZQxAkXRV&ZOkj4@jwBEdOYhTlG)OWGI>x<9qgiBrfD%rI*%zbT`}}=*4)p-kQ}> zwE81HUH;G6SO(^SK?hX!5tM2k+9&Qu^)-g@=rf&I1hXa7uQ;_JBC!qg8T>g6cyyoUGr#so!huWg>5 zEPoarQ3!vn-tO?s4>}!@L94@gElO>u)WeppmyMZOQ}+Dp*v(-^8=@E}mX8Ygg482~xx2KGhpJ7?u>sS6tPxsOaG5Yu)`2@Ax$LH0W+uJ#{w~Jm- zhz=@XVfc;MX;mqkYqQl#3_NbL!AKy~gEGov`9h;d**18GowmqgyoF&3A?%hH7@^)!wQI8J`w^z9mOB2ZG>62zk#jICWmo zQ{%w8OJz-zLs|~oL-kVQ&*bG$LobFV$-lno)==RA*rVTV3vF(rS2ag92XPvx4I`kI_Jw zJk2hn0XvxPkCOshv)l1Ij7NdP92|pyqolP; z{qvT2nfMaFsZw3q)wkfktT}R#xDPbs!bkU zn;rMFrD>na??JnxbcT%9;+TtcG<(&)h;q2fTJWI;t{3{Y(GqP35FZr-q2K;*YR8lg zGF`84@1g$&oJFRr?yvlIkBW>9JxA^(ifvR9J85K>4J&@b;Y-H>rESr89&_epmi$!e z4<_koF-CnrqQM?#Gel}{6q7`lcd0UA<+X$Zh_ttpRv}0N+S1;;v()DEdxJF}s;1oU z&!STh$wqD55+2{q%|A^U4DiQ0U*7i_zzvD+^1Jq*FzXQYj`dLONff2?}NY5ha)@@^4^-v5U%!ave0RJe)ykXeGVf{U|(u9-3|LV?0C*pzbrn-#d6(A z82Q8-UoiQvfEf+G}nK=}N?){8QYGdx;u$SMz|0>PL+tVVmG z|6#`zz-zU}UE7wZjPl-Ya`tPdnv2AJD7FWG5sphySjC=HnVG&lk>5y6U#$Mj;`3bm z={;u@Zg~@K*)l=u{j2D*%@icn==+U%ISAfg>=~qgJ_k@yjXY?A1qeTS{=+QzF2Ew_ z{y=fu^8#V9^`e6BmX>nfT`DTVj#LmJXcjjwtxkNzXa7(B(rgN&Q@ zI}P>JN6P|b2R>?RU}p{%iGZbvGMVGZny0YuRx0c zw0U?*honBGu4dyy!QNY1n*V8z`FcJ>NE&+Iz~(fHrMh#!o&!EVkDm;%1UA}bi zIW-9&wXy`-7I{0e37e<> zYef0I!MUxmE4i8as^+A3d_EXJt<>9J>q(!UYvSlQHad!Yx+th0=EEkiv?Fi@-9a6e zkw^V=e(AdMx;xi8@u{+ULuV67R=aw8@3v1qfch(q0if+BYw$H&C>|ZHG3fl_yx=oxUks@GBo6!>w*ty;DTN!q5ng7m)@tux*n8l>Dh zE3oI^@Q6z6h0Gk{7GW8t=Mv&}x?=O?rFpul_Z@C4>`(8!dBj;Giks`in^2I!|wp#n^Kjmxc4{!l^xLdd{<|ByK1?fBy*h-oV)u{IbVcvCn zJO*q_&_NX9PLzV`zn_LehHM%dVZx% zH2iDxi~qW5e1pMp9$ELl53|{R%U2oLM-ab@X`zyIx9v!@EG&vxDdJEfSr@=l3e2i1 zdWF=?M0}~XwxF_nJqmurd^7FMl2qlDla7^JlC^qShk);}+y8J;A|wLEg`PIO-mb6* zeGa@}ic;Znsd0 zP(=g<07)gc{6?zv@Dn&Xti^i&Yt?dm7-q&bs;>X}-9=Rm+%%j|>wu!;N31o9O3qmu zEHEqD#o~y>c9^3$+gf|QNn200QYDz`)Ou~sh|vWCdV)-d|80OB;);HO;l$2Zyh7|rNxRV@L@ZewZVcaiyE zJU*?Yr%dIYqg%dLhZ-x!+7^EPrzXE%zg<6Wy^p1QMDrEeJF7QO9BGctP*J3rEKwwn z8n~+68cZ8*WoO?k2l% z2_;GfYdSqYC~SZIRzzV_!zqU>RDcg*BPq_8L4^efNKZmzdPDJjhN=klX%}eDfQPb)m}Yof46NnKdOS?H z8R8~3{c8t%L_m%6()Wz{(*t2^5vfTYoZ^<<`B0iekD7@!Vf>;|DLoj7x|5k_&Ni$C z0bSmTIY93?;TP_N{i*1!oRAZV_@3bHfk+gtidWu5laGuM*Wz~Nc#!O=eds=7eRXBE z%x8eHDcTK_Wd}~G;VsXQ^L(Ru0KKn!?aAoFvB9g8kh!%WUq9s9_ebvP0Fi>%o^qdp zi%wRG?nY)pv~y4d+i7x<#G(Q9cF~a)Zh z=}yY%Jj|Qa$yP6RP02f;Ze=D&{EbP=O;xLcRmhCt^1g~({x$hH+im}oc-#AMA|3o`BRO5jVrTnK(#8ojzY49mZJ6)duCLtu7Y zLpz9bp%lOV`9Ce-&E6CA)shui;{U|t=4gwOvrX!P%c7|JgEewyT9DOa(t?1`*J4ih zRe)E%cY}7&hz!b_zt#Y-`hj`yay=WsqWGDy-(eR zUMx}xy-m9Gyw)gu3~{7?K+3|&&AWx4q9KW~-naKCmAga~#upMRO{o?pN zkJ7ko6mZi9Vc^^~PSEk;z}WtlUn60Gk_+%M967>Q@+pbI1j@9y^-Sy)?*UtLp0~*& zr1@un(nS~1(YmRBrMHwCY#r4rp#O|u4RF? zS(9zJ7NJj^XPj3cHXMX|%Z0orZ^i3(gz}8UlgioKa3BxK(sXddY=yyKE+XTM1wAi4 z26hSB1UA`(1zp#XdJKG$(VafNp@wBc+!!wGSG;ko{JbJ*Efd*bd_iSon_h$xsazT+ z2mN6QwbP%A!`>jR-Yl54(K>#^b-be#)Hg(^q8T zWtz4#Dxt2kQlS{PlJTIHcIhM9OOuIN{qRS?2tgQGzv|vN~;6RZ8^2>sU-z`k1 z+3SY`ZwKB~ht_^sckH+1zIh>=Wkjv?p`ct-;Tv^K{iq@h*pku33C z==BJ`DOXikTkbA-3Yyql?+0;}Gtbipk1YO| zf71y(_D1AqupiG+r?KgE*_!q|gL>+g_wcZ@5u^~Lr^0`-EUbgYRhNB8Iz=Rvi8J`I z44P34Y9ZPHT2B9DU|L+9|N8rhbCE8>LKX(x+;!I!3FT9vhD=D&VGx~_I>on})_G1f zsxr|xD~QH3XsA1|@qMy5_>Jd5U#_nK}N;HykGW9vDdudn! zNF|4gRx*=Y%&P3>)?Z0jBMbzZ0}RT`1A9LmZp(2z!+%8pHx}4;L9oNXDQ^T5}p;F3~b3=~DbO zAEo&#G4))zSdnvqaNB6r_~%`jc48({^{l~gX~=5u``aVwOv8|TkE?BhVb6}x`o{$dXnblVKlZGCY77}NCK~j2Fkdk zs~^d7aN3Hhk`>PBG2pFzEjBRSN7?vx1xWTokjLN4L8dBy6Alk2TP&@fL`}q+99_i7 zx9s-#96L3Oz-AZ=WW1gwQAf`aR2|6W*0bbo*Xhlns8LirG}34GteUUmJKPO3=P=9` zUmV@CN&$VepNJDuOB)1kW}@!t(h}Y-QB?{*eu(o#^5$g@6oZ}rv=0f+G^Od|Egws$ zTQUSm7Pfg&A28WXE)M?^nxc@_#x4i&YcjJ4nxnRz&W9(q|2dF9*&cFf0{#>j44OwwgSCT}(c zwQLZm8>7=SR=+I)_DI&Ni|ss!f9MEsXz%(*L5BObB#1Gk*mR|Z7{U4upl*})JdqMu zKr#yj_`zTv|3KHI06-Gh@3j*2Vqr$hVlSgv1o60rto9;W_>xPY_GsmzY`wJa-%EEg zyt8h#+!W`DXdGS6zIzSguDt~n$hE)FH092SZVUxlb_&qNzg*>EirqZ1_^X@qC;#M2 zZPGTI>$NDQsXgg$*kDN?u$1H?k8N5v~s4hcD z15SR!KxG{)_UUh)$U(=xK6mkUG-6bw;4F2k3m33MJvvqU7d!c6L8(O)A5unl26zs> z*V#v2GwCWb;||xm)aq%ubnAzZ9>$+yS8sVauOj%BluAWBI&WgTFip4p?vTycxp6Ul z`M5YewW4sb4oi>;d#K%7_A$ypTWAVt#}=)5K*~*D5jb#%y!NiG<%T-+Lc!=cH|3;c z_w~TG65g=~EzOamd=XNw5#u9m;RE0o;5fDYua<^96j~OIkIoJv?rmuSD22A)zsSs# zvjO|KsP0IGVlQR*p`5q9tlgHzpk6QstWFRRB#1Z3+9?9QhpMWqALKM-U`YGq)M-b zi#Vsnc;|`*73b}piLpf9O3>-OL7dVK4}X)=nfOzgn?BmXr9*05Iy^c8ANPPtD>p7* zLo}MIHyl!e)o?i>f7(`-vK2*Q7Oy!NM42|mHU7myzYMTvXpTKa%?J|$l{OXDxah=V zT6;=hT66o=h4DFcC|4QvYS-*}{Q+uR6y|ttrWz|?@>8yHq~c?W(q)~7*9>*%_M|diq8ejy7r?hfjI-Dfo~h51z5lyD;!2YCIQOTXfx+zPxXKAI1wFbEOe=YbVpI6Ck8l@sghFq`l0W zwa80NJB?~*Z3ryv9d>-8MEh*(Kqq8`76d76x4sCvH1=$&qF<;pu<2vEBI10gt1T*KIkj9kylDGZrV zVh1ymA=?g=!p`c*TF@<2MwgaJ5(S5j5!k5`aE~@LIr6nku;#}H zDT_;&xE-R3uA#&7s@hJ3-0AE}R(*N3&1&f^+icWFOg!1r4{lnU?^jr@+&QwQhXVZ~kH^eD-p@|bV18ior+JA}Dkvf#X{v2J?MJolbrx8|vJY$s_BZ zX{OEz1eR><8IRD3G4Bsb;o8KS?&sw7AR3Jp~X#PXhABW2ds*IZ;|u zT9$0c=M^h24JoX`-*2KAJ?(^bsu&v5Y($WXyzH2X&z5m71|=Nd*ZnCe_8;f z_S@uu!s{dgHhp43;dy}XhML3M@?eXS%TNwrqs3&u*~>?FNmjiyhZrWB`gRNUi&F@B zmimL9w~_lc>osq7-Isuun=&OwHqON$CF-|KsDTg?DCTkvr*bd}R*G34Ra$(wP}bWw z`LETyYlZ)QIYy7=;cq_Fe+P(HdMbnZu>iWNWf8t*D+`iKrOX&~gs?jzqriiNmrN4u zt%>8g{gZjS$iEz9G!=W%XN&*P3ltL-zVsO-RB};7!$D)6z)pd-f6?OK`rhnAW}rh^ zs?0#8u<^~xe|`|zOd<$i{MGq`9Nj-{b&Fn*1>o?RY4eRF6Su*0oZs3a4nEEpF z-l;63I!UoZs?a?kYls9Rxd!7QghAGaA5wkaZdtf>1JD_AdU2~cw>`+?@4hXx z;nR|*NXHk1eTGd5{CFB(Sl;CDeHv}i8M8P2-toc2)P8zFoPM5f9Qa^1(sf=Q{(e<{ z;Jvd~9IxASz}&nuamP{>+K*$Zhv_IYO@3l+ke0nl`}ETOx6DFqJigP%LL}u)_CjFH2*lLDmd+M}% z>FS#eb#A@+Zyx$It`Y(Zrahzp23B-Q=)>AR>3PwC!=II$`D2AuOXvm3_hpzYDa~CT zYH13G(dmTko+pX88!hAV(&0T$1eDDP#2{|iN@5`l^}a7}Pzr{l@{-b)xG zurP*tCFuQ{qb34W;TJQ{a;P%n1r`O>hHCINcIHGda1vYm54zBX*B#ADCFmm)MhYxh zrlIP-LTcW+5+U(osjAdRph7l|0#B5GBbjAT#X8bt)9#~%FZx!+ZWf=jwDZ@kBQv5H zdST#(1JAGnX#rxsNC|EDgHBwcIf#3j_|Cf9%wF`_bzLkKD{a4wZ4Y|r|u!MX6!JLr+A)}Z#r*tU(VgJ^N~GWfyeltG5wN$f^@vPF8(^Fhp1a!h z{h+69AT_01uTt-|tJArH=Jl@xZQ&{u%Z~N9w1LRESU#>D#qHdhd@tZztM2{Pwfsdw zT~YjVHHO0TO{1gHgtAtf=hW<-3EJBq(gA-TeiyX*oUYlRTT*arh=vBTU6@_$w0I*Z ztYv@SbV$f(vG%Y0#+5MR+wM{jpyxSi&7%m*k*iT|LW*@6dw4L>YS)P3B@u)&^`*BUIoU!LU4lZ?_AkXPae^yVfWvf(lpX zgLTAViFrqJ5gt24{br6?*EIxNoZiEo-9&NHUo%R?QRaD&8|Rv~2|tcRWq=2uj!$fb zsS~@92|Q^A*Bk;n((8{yrskq6032>ogKBbaD;eZ3GQZ6`40XbA7uwy3MuBo@hH!Ou z-wJmmxk>wv^Mv1ZS%1v=O*)!aXh%b|!q+kj{R!1beu>7=sc=?EW{H zWO0@1t|}}+Bcpf3)VcA=P^^?ziP^!R@(Ubj7e!j4Wd$a08PW1Ew;ND}D3U~}BQS4% z=kYGw8@S-BlA{qLa6>2XJ5qt8%6%T5)29TS>2$fyVGpjgYcI zmq`%!Td4F-Toszeb|=`?B?y6wn=o~_*+$iI?S;+LDz<7>nw>Rrm0_t&mwCoKW}?QW z%Ji3vUQ&DZ!ck(_qFSS=>A&m0WDG3(PhO*|<}f=O5SDKxYZxcK#_C);^lrNbff-Pt zczJ1{g_3_=Sf_m3>MmjLb92j2ODg|(%%s%zQdKXiVh+LOx);mEI>m}tr%@8h*q&da zxx|vz53oJ>(gjzYXilrA)i3s=5h>twHYQ~$?3o-Ybh2WbNW*9L#dIv6=4S2~vHYju zR#ej7K~?A6dT1}p*sv-XeD1c0Mv@P28#UcuQ9|$Wi3aw^wbkB}BBlOU;vaM{RT?0R z25-|DHO6 zn{im(XQaf2a)fg=l8uhfQz*_ezX`r#bB3Ju2z?h2O7nv=6MmUlta5r+9ml@!oP`_i z<=g@rW%-63(?*kKi5o03_gnHyF+?aWWB!^_*{;DFj1O@Cs$dZ!{}EH}@aLisc;%{6 z#coXs-b;mE;OI;O0zT|wvoVRazmj+gS)f_-T}ijTPk4}UQ>f1%EX&u4wJ`G5LJH@I{Fg z=r$0hq=+C?^KL?srv7jL zgkO(e<^&UQXfmNRY6L`AQY)HZBpZEldcFDsZKs5Z(ujh*0CRv@9*tbTU8KiVvRHvSe~!w=h@!lL=s7qd74lK1bqQzLjXUo8hucvxdC>|?VsfP3|P#2#&Ye~mh})F$IvCQXVOPp5Uz&rc@3O0axM z+p^#9Bw{K4Wp4r+MSqOd=r}i<$>*c@qRX#Q`upg{{>DnJjl$(W=Sc?6+-7aDTra-} zVGB2=yFEOP%qVf>Y|}I?lH7Rlo`U%}e*(h}Or@e9ei?%71{q|f;H8+AIUYp4k9s4Q zMM%)X3));cWP1#h%ow@VxFG!gB^tkEl)#M>mr@~oSX>4zfUHHleYa*2j^x30mZD+A z%$k!xIk!jur)n+#RZp7Y;4PuGKUEd$nD5V7XZhbUzKV!HP6cS@RDT~q{L@q(;YDU5 zISqm9azKd^v-iBz86nX;h=6yA*Yk~?<{sVxi|zbXn5S_M=0-427Wthi<9vA!)Pk;? zc^zhmV*r8YqzX~##O3-)8M#-m19Lg*Wqa-^X$`@-MAHKG`exjuZN^9$Uo13ktpF*Q zHE9^5I#hu2`vH7t9cHo1JY&)$_&mSu{3lNHr|i@R@z&~`6PYHCi*-q1gj*wYQ*!%U z$q{b6+p}zXI9}cefB*|#U|#|r2?TppP@#1nDS@AlVNrL)ffsfeRCcY}FMFU|t@2o; zgZ_38OmMlw4i>B1PD`=~#14iy{GHOt6B;i%1R&_zoNbXYcKj_bloVhi993&_)`?cl zlL{aJIwNRi&+R>Z5O@58w*!mVTWhVV{0eH3Y~5sUxfhhF6yR;YitqK=d9puZV$$q+ zRozGvU1*F9gax7$$VVudIfZp?>LXCjIo!%UAF%b$+dKG z<0GBE;OUF;3c4NL<8AnIk)`6(eHo*fOR6clDW?h~QN)LM}vr!r44{%cA78@@KP*yMwMEh^fJTse_8;&vg|U%5JYGb)do+A zuD2@VV_d{iC3P~s7mv^fs7$wpn{z-tLB1G~9{O|4qPHwyjVuisA5=Yg=XMAjfxm1KBX)Z3(s)7t0n;FO6H{Ex~QsUl6DGdhmTC#*nGN^ z`@t=1r?hcfn|}lJHHyiBr;Lb_3M!{_my?p;Ei;sIlKemdm4hCF%0U%mtXg-8Xk7av z1WX#ol&KIk`;-Mi;7vIZB0jvz}sn_1z?5z2!jqghpwS(&HnI-J)?7?btUPlv9-ZabM+txVm7^79!vd=8 zbu*q@pTAolMZiPihzBKL=AK>dfG4zY1s4CghDuS~hV*FKxjqK+ zm#6*?SahDlPkU&*0s~Ps!El0uX<4|1?Uhb}odx@>!&^5V<$;(3AY9Q&tTmTm|WT?U5n# zt)Dp%zHOHZ-KCbEN&l|89Fig8X}e%

RUA5*t?7PqJq;RXS3E{0F)Q8GK<8YxW|80h+@1-E z4_hNkFw4w+ld8*^8p~0DF=4N*q*dSemGW(|Rn(Pcz>KZwnIIV?vbW{8_JgU@(*_UV zn%wS_z=!iFUnrxX@h*OT)9P;}A}iv9uw`xp_e1U z%YDr_vFp^XM77o_x=)g*;b1DzHR*H=F~lb~GmZ{JCe-yVE2AjZ9Y^+hpc(1@(i*z4 zD0e(wsqMHD`x3*jOH&=v!RTB@ap)?*tOU!FhAx3NcQS!cD|O1M&)!5&)uf7y(2@@t zaI$8h<54}bS{TjMmHU%l#!N=qIkn#FZ(h}^h*XNnXLJ#zw_l*bO$$&)-1@HzDtt&x zV4p{M)2>YtwCb-gYK$%6u1`~EQLP_83k%hT2#cU#GXK#+uR_%=RI9VsaHfS2~b8iPW)3d$d8)VPqG?mTQ21O0v6p#D&fG&hIT!3t{kYi#4h`I23`~e zsf3SVgn^$n;}}*hLA&r`6L=#QOLp=I8Hn3~mfIUftz}q3HK8E2GSn5(gAd%Z4}7)1 z2_mu0jj9bHisq_v;)=+%fwKm^^a*Opa>bvPVCPtO7VS@bpFB-k4mK(WXY@_J4!gh( zVT6Ab`p)JR>2j&~-AUq)i=?3Rdtwq3=trRgqs4?}h!r6#fx(^vh#zkZ?RVPOoNr=P z;iHn5_+WGEfxpe!&XwzllE!Fh+3$YhtNrex_Z5TihGVKA;4FmILpJ543 zl)jFy_SIso(AQ{gq#?m;62x{MDNr_x6{qUMTq)Gl4;~X=ZkOKS(D=0(H?d zGvW3pM(1(!C9{uR8H1Q(v>%t0drPn+^mXRBe(S3Zcg)@tY1>pidL#?&QS!I;=#NYt zQ^wxSqPpde(likKW-#no(sKx@O?fiD;AeX*_gf&lIz$f zt1yF|MW8{Yyh^N- z(c)5d=dEbLppJGI+^|Jm3a^|cx|! zD7wpt#`mVv1|$pYq_^3?gpDvz&-uf6`#q(c686p=bTBGsL(+TbZ zr)hE@UF%;I3McDOlkvfA8+7h|D8>RLnjcackOPJkoDAk!@2D*%DwfF3owVSYDJ zU4D?2yYFct%`oIldkK)0(D^-plcbD4UfHi4fYy}n1TnPIVo ztW9$m5p;!e=HsYjqq!hWJ0O z!-mTYs)$_$Ecuy)Kj=b_MU6h@L$$6+By6m6JARwW2->t>1I;j(z}h+FJUlPp0oue= z?)V&^`oonnP9qq#1Y;mxu{qvyX6BX=nw92XUgX}Lq)w?|V#%LK_uYSn$JnF(93NlR z=DrMWQ}5}ZIguOq<8x!t`Wj9I-5l~o5l&$UcHnC^!cPY)NRl53CX~C8ud3&yhOi`* znzDQA*Lei*-PJO5)8SxBX5kM9hAJ}#9QtVL$g(JpVXX>qcui<&@aR46OF3eHaI>De zEq!9YI!1KkSxanBnh~rKc6$#np4xTpUMNIc{Yy3`@Xfk&d}DpHKRASI2-@LdZaRDZ z44n|agwSsDzBy<#XgY#}xi8D#6m(zO=xyE&%5Q|nk_J^cIxh^4`elf3Df@Cw%1|)! zvt-dQzcz>@6T@VB%9LPG{mLC|6p*;V#_$o4<|%u1Qa$2cXexX;*nOInWpNu=gabXD zb{mWYJ@&&IYXiVaTAhTEG|XlF%|Wo5@JHA@@}a!jcNNee1*rlh#^xR^+LtIAyKqrt z1juIoPDIcFj$NN_a3%qyi|=eOquhH&=IF)1&N4oA*J$hj5ExGUm^Wkl(vgEBTUs(0 zFsU$l*b+|QV+~wsBSTl-L6Y|65~l56<`>2WFqXX(5LvgeEK6iapz3xAD^5YQ@q@L$ z{;?L|Gl09zj&NdG>`{qq?)yZ@9NcmQ!B~yr#F;$$2HWtL`|d5BMQbpW5lcQR;U-Lk zi9H}D9YpK?4bJNSwn1U%Aq8pB=TD=MF5uyi34#egcD)*x2N2G0<)&?Urc(2B$3%Ee ze^6JWFXh=O@O&bsJW6jz1E+fX?&xOILFpInxaNs$0r=a+L*Pdt7M(9B7K3m9o9uhX zozIBkh`(C?t3BAFAJ^Y^R$imum=LEQGzAK3CXN}U5|n%$gx3nYrxGC4;mHThCS!Xx z(NA*{tpVZU#hNZ4JqMWD(!>x@*!eC~_t;sw$U}}@`y2}hO{eC^Pw+4>jXA~mY?!6-naI?0yD1E z6M2re%8ieb@7otKI?i8~YwirkwR7kjB7+Q|e{gV!CUiA0T}c}$gV?=mC_Y#$pbiDf z1az-^VzlXS;=*i%cg++iP4Lm(J8K)!x|&SLF-){D_A{~1qTqL5 z>R$gt@+bJ6<7mVB=5)g_kD3j#+5OPK^?rUc z#s3~0K5A=F|?%7%41bo2@ z;j**WoCAVE6R#5scRwrg)Nc}bTO$futW67cR!LLmTJfe zR)qE~4l0(dS&c;Hi&r+0`Fx6SByOuG%r`->o)p;SUl@o$UiWmT6{HykXi3|cOz9QI zrqcpE5KI_LTkDp!>SpUe5D8?!8~TmV>w)N2MfWa`iH~%2@&txrvo{_ z4F&ax$?(*#6u^_fsX(4l#RXi*cU!W7xMSkqe=g=FlndK5$`{nPM889<(7FB0U!ii6 zThu>JHvyD$ldW@wte%2lG5bK%XVRG>8GBP#|_VcwK8C<%4pZ*Z)i2Z7JT>3kf z@7Gr`LI^NVV8$@wY`Saf`Q$juEokLQ7~;c3dE6|t4Z2!w9a<*I*w?LCks#{g6lR9h z9o|CqU;VPE{Pk)U_-tP$2R`Z;VF`TaIGBvs0u^5(Ojm1D%+g~Hj{v>Nb|R0Z0qJxK zkJV*{5dalaIEvo?(*k6>jm~F~TZeQC;_mVC33`JXDRndA$FcZMGOVMif{Y`Hl0ZgB zu<%TjIF#|3b@V<=O!E97rF>)_8*)xGAQzSjxjL1+F~Nj9x+KJ4X|U69n=Rk%K59&i z%Ta4NmU4U>(jiX&OHo%99cIowPSA%c10R41lWfK1`5@x;`DUf^0s^_6zT zAmslwP4jLH05hHLr$hGsS5XqNw5-*)7+M?c+)DLlqEtdf{y}p53!Bhri(DKF9a(mY<9ir;IynNk6$(jmoxQ5 zRa<&%JQM#PPv00`N7${MG;Ppi$95Xqwi_pnZQHhOr$J-e){br4wv)5pbH4ZcGr#AW zS+nL@_qqW+sT=4dP9kfp=ZGta%eVh&g%uYoaAdy}&9BSIkxRyJDwCQ0ngl{fE$8K? zi<$+!Nu}>(1Q$Y-gq`bh)2}FGh4VuEdtS`+KqR6e%Fuwj4F(Lll$nSJFP{ZhVpV;x zn@?2al@b(0ktm<(vl25auJir&yhLn{t>|L}p{i!jjK_tB{6U|8%r<4;g+xW+2%Nic zl478mJbH#7*IWTx)_2lSnX}YI_PkE~zdL>nIx)zi zzBe)BGHgHhirk>npWbUP_RuD=QK*VN=l*{@ZW@HCked54Jtj-=Jgkm89kzb9t~04v zW?U&aL`Zh#%u9uJYmvC2Um3rR#+opp~G0VEj1zb)+{%)|WPSdM}D z6*@D*l}Clpc>q!!-YN~|gwvw9(lm|dAGqjJHzN0HUE6~*I)Cs=Yd4s+tmNGK! z(rS-?D}PG#w@j(#igVbx&#VvvO@R~KzDX8o9@|s#LJ-|E;>3j$UKubyuG;l8vL6;s z7<0c`nP2YcQg zQJ=}8f@ACWb6)N3GG_GP&4_i!`X;nYm_l26NJ8LxJdq+IE1t*~#(Nv@@Q)=myp!^}W z>vK$3EI&xIN5VI5((;oVy6sH51eRo;-(LkIcW_hr!*^w zs;SUA;BU`ml=T73GIdk&)7B-W_eE}n+Hl3fJFm%|jlF1N!{(;okG#o}()?onvRYf_$Y z%GbFgKP9~iwBk8P)1=`Yn7?M59F})kH43jZCDIUWz?^)CN5lr@X<>vlv^RZ69CBb3 zs=vZ4PJqIaCvf_g2$v5gL5~~O??wwOND-1%`m|ktnTMWhCn&`Sg|^dFr1rL#fuq8! zq(kv2aZhp7cEO$-)2HuaG%FGPNZcOZt_s)5x6*(Xwt>^Ow>|GK`|kF^4rPlY5`y9oYv~ZyE{XfS;c-_85Fv4?TMuj41qS_v z?{Z^m{b(e#?)OOXD*IpO%~wZTQ~e=i%cbkTd)!wjtklahqus_#E`D(NdbM+`bV7{D zi3+4HENH>bI8gqIqiQ!qPInF4Z3Fd6B|i5ZcYlu zE*_?$GVN7B=AJV?Wsm`~X;zF&NOIzW4PiegxvvX-U3&Ar*GjD|YB)j$K!qOpQ900T z@WjYS0lvCOCA05A76jMiw5B9Cf0rA9A(nIQW>wy~A0xUB%kOsV*{aU*IB# z=H#^*IHegkL-n^Vd6#^TTy~NZY+>&z;J=QQzIYAQ9k_7c0`;}YT+(cQD--qypDrw= zDg(7+TM)2S+&lU9L)lq&|97jzcpqTAI!GpsSMx>taLvc6P_yvhrANs{ww#m&Y4wS1 z&=6!^i=tBo<(XyL1}mf2Oe=7|ArH`TEeq5mV=|V;>)7Rf59Mh@FJz8W`!#HV(-ClV zPCxT!j)RU$h~aZ#mh~(|M&q*=guZBIytDTzcq(cP=x1`tYk;Ce&aMy7K>vn~Q_TSh zo38gu>aEAh#LxYgNEHP1C{{T>r=8V8cCUS?#I+$ePmkVz2g_V8PHUC!eDM;MCaYYn zY8h^}Seg#aW}EP7AJ|^&l93iLpdHkzeleHn6~Y~GYA-_ebbTjkZedLV%XMC<0K>S> zW?UK7B|g&ntpe{{>B$N03jZHE!7m>E4%qGFB8*;%bPH$^7l)_}&dCNxB0YcWGy zK&Bj*-daLb?#2jzY)6$hxnCs#^RDs2)9oGJ%twINwNFf%L-k)5+Ie_lx@l;Zn}uMN zX*B~g?mI_cI9l}PPo(BX{O_j7D?yb+)7?%vhV@op2XLrODInFbVKF_g13)S{e5dw| z@0!1#y^>uyt)$a&Y^n&@TsyB%4L23yAQxdKKlu;oD(0l+xkr zQ8v&18yBZd;WVI-0}hHaV07-w<<>MX1Cy-1AHip!Kwn7)?U$5o+6sssPM{r;BaKle z36pcFeXHqTEo5J|UPd~Hl>;nbVkF&$3D%y839!4jC^xurDj6rP&PE;Swyu(OX_q>@ zw$#C~M-M9DK0hGO`YT?Lp{v*4vc6=!bgN{&C^00D`*~+{cEdW~Ui)!JMRygLGo6kw z10jkMOSF%j5Eia!%m#s@Lb2=AXg;o5d9oQ35Rhg1O?U;UryLPdL6?|{aFnupHgU`1 zO!FUH5$wfrpbTyI7=2%oX_=uGoK+m-5Qs|fGt?+;=7?!ksc0E%*?8v6ADWC=bw@{d zZ{izm`keuZ7^E&D!6|@095jHRoliH@8bms+;)(j$@TWd^5F%L4*$Vo zRJhdizkLkV+Lf{EnAIDDK9V2TNi0ooqRHP7hsCVK0rPG%v3i}lCGnf&0f!AaYAWC1_$ug}MPil^<3su;rX5;g%@8PVzh(toN z7xx*vA)XA%!GfRkX}#6l!4&z?Z0VKMk&IfFW{ssB6R#>#j`?%T`L(fEv!Mt%h44gq6e^Nzjx8;?IjK*cFKJoyY_Bar6vj8Z3nk- zA1`E&=tgimgKQgaM6}(}_l@2@5Hw*=DyfQ4@cb*{aG==$LGTs=@_(naEOmy^-v$Xh zUhYyeoDKI=*XVuwyRExH4!*DTe`7)5ql<+>dpJq-kpC#6ei^b@Vc`gSi8{N0v64Y$ zOdYE9zf%kKXR_#C!*mQ>Nb)k7QBkZ-3LI+#V)}Ig_^GG|^fLWAu}b}OEOHcOC5|$e zIIfV%G^qzWi-~J_Rgh!S6ZEA}9=IX^g`T@CjS7=npJAL${!j#NgHZ$yCZ)pAQ6D=L z0-CgtN6=07nRo2BLMsthk^9fr#$oYtw*YuAkCNM&oB9o)_|VYFv-{E$tA+Q2_tezU zc=5?*XqDGA2Zr`@uGeYLlq*CIS3&#J?N~~NAsqbggQF-=1utG#P^i?%9BkLz9Q`Kh zRqCCSuh=2`iLZ!Oe|-Uf;NXXc6C3&iAF2j{T1iC*33WO_Ie==F8_EU0ECiOkGP)tX zM~W0{uSOv=Gw?O55=i+mkdoiFkci|4?RUh8F9eEEQ&axtLyV2Dnu z1CqpmbZaI3EZfU}O+U3AFQ#e#v>hC`JAd689c~968oCyZd9Zh`3vU#MjSf?o=cP|= zS3c>!Y@MpkGT5?qD5!xpk`2xn|dPHjjuEcZ(MXjN< zy091^ai57k%>arJV%yn?skQ;nGtg|+(I(^0#x8Q@%1(`;JNuE*VNGI?gK=#V$!y}x zFgilkO|0K-^If9G`}pwsjyzqwZOOaB$@US$%3RkEXWRSIQR{6;nlT)u0gvayl$%}W zHo#g3`{>4*ch_&1nl%1O8yeqx|6p^6oiaiELCq|3tCIg>0aa~J5$x|{ z10i^Xbg3+?t%hzNZC(~igNjKRphGRLW}|(IIoZ~qFV^eG>4<~X346prd@gs(S&j%` zi&30AI3jZJ{1;2rpVK-8W6Jo%5`HY)^!n>wiPmuLiv6$fTMjxFKfqJPUuu1 z$ks2vvA2z!0>p|cc{U?yfhbH@V5*p%GF-CFWDq!CNH)-OhGscCCNgJ@474FAqcacD zMyfBp95zsVMt%8b;<^o53t!oHt$}iG=F@XHeb}gd4!d$%ubw8Wefg!jL6F5=@6d|R zkl}H3Y)ou7ve%}=TpoMmkk{vnF6&P~TG8PD>02DnRXZM%8QNS;1c`dpdSMD5xB|n6ky-ue`aPEKdA& zE6Gyt;-Z4mM|xe5ZHpxL)0784qwn|p+T=ME#kHRT3$Fba=1D4k*Lw-KkSx>3kD9L5 z-Q;Paqq;|XitJvy>)c%)q&Siqk*_gd)659(l_)Q1y6Qj`%bQtY40v9qb?XuG@Vf1x znV&6aizc*u5D90M=`iTF@91y);^WkvD#-z&41h>k9q^x!hr`@r{dieKEQJO`2+a;n zbv!%redZ^CB18j$fSqBv5|LauA1oMv7YjdpejoYJ%yN2bqlx>i5QEyf{1C{;PKcP_ zQE3uA_$?tG^$w3Z>~KraqbW=-i2>d#4=d*u5qHw2p|K;1_ra?)F^bo?4)rKtPrF8$ ziWQ}HKJWFRMqKXtL&4He7*}iOE;D`o0{d#KHjU6g{Z8li>e`^jKr;|Kc>I9v8A?Le z+PF5|GZ}{CesLw?ha-aQsgXOy4 zFN4ihnopNkO+!UaIEZ9GHh^tQ6N3#`Jc%NcpQKPL|KL~^;T%)E?S2IeYXliHQElzd z;II#+?>gID;g$8mgS+Rxs0Z1J(aD@M?)?`V|4+@rvOS5)3#7VC{^rCG%c_qEN4c4q z<8BG8`p>nQb@^$*$d`WgRl(8OJmJjSU%^{vjN!n?i>7Z5k`mQ11oe zpBa;ivyzfcqJ0*Ac*%T#5~I`h*U!BQYGC@d*CdDQRu4P;1 zA*LD=`-7E-Ai*^kq^wi2yQZ1~`G`D!qW%&G-}|7Hb}XlQ+}k#%NHrmxhRx`CX47!~ zwR06%j%8`Y1mM=NE2BzRT;qDSX|WZ8N)@s?R>-3BJ8xHc6KMN)je<`CTD&zvhlvU- zF<@^)0mZNIRvha0nMmxG_^aAKiTTZ9Q_FJ=lpU8X3B2#yvo(Am0?h=pcxtw$BMb*N zQ9Fp1UGwjUx0lh=2SluTE^3;rn)@eRVz5bT2TD9QyzW`ljBrhSqi1PJ>>PHuGu&nE z__v3{)LViAeKUj4So$(^H*pp`0D7zK=d2j7ZKo8fUQv28^tGfN!k_qgf@jW z(2Gxq2R;FIj+yg~m|C;9?k$M9$l<1m-j^UnTnZj>DOey@BB z?uz|2Qhs{M`1Q3u9iqzZ=Gkx2w#YTb*|y|N8kl=#O$`_@3t?1kebs+1E`U3Timk!1 zyWMrc-*_gmj!v&o?8r)wTucfY2Eo=uXmsEt-cz++qn1VHEs5o?k7UvaJe*gy>S(fs z;}v>3Q5`Q|Jf_O;uk}o8*AI8#O~N@fqVR^%>A4N`j&qNB=R?Ii@61CxAML$5EpH|= z`8+=>b=yjCcN|oxw;J~@4GIiRAT}n#cZZM)8lLtTut%YPMb~z5D3_JPrsz>g^=eYw z=bI@iB#qo64-#-_!icqo$5jRVz95WdE*e%|JzD}ULv)iz#VhuH$Fl;=0~8BSd+l){ zpVuD{vb^^o&6*MfP(n;P*!llgxy5!6Kg$tyIh%1H-SYwKAPf4NqM##P2C#hs;k@5uyV}itinCSJ1o*;S zw<)8>#l04(Xe^M}d%jo2*g7alY;Zi?9Z-8Uc<-Rcj@eEH1UG*K@2_IeUc)?!s4dgQ zj80ib)XO@C16uUe_G^^=l{PQZo?#HaqD>TKemR{^o%1t$1v~ZS6)-=nDA48G)A;7l z!Jm*1llCB?wF7p#3Ovi)KPs-7Ni~sj*#2|d=Z7UIeNh8SdgCr7{{1k?@igBcPRa~@ zt2izDPME1_`Bsl7Kwv^{MS^f>&(5>N^4x;!cdQ)#ju9!ii97!hH3O(^4#in+MV7HVgG8i)#-A-sONvmbKBQ2gz@v>PWhAevcc&>5J&on!%b*)r%l^uB zi1(|FzW)p#@F>~hW)Xf(DHJPZJVqJZOXN|FWW;KWzQ-(D7pKB*BddYt8`=ak3Bw;V zub!AY@KQ17B>Gm>^vf8A@{y2_d*>&s+rG#YEq_bP@Z&ezo3y=|u%lpa9qi!dTAxVj z@}bR+7AKOLAne2W*&AWo56vydcUty(z)Dx$%ktDG@MX#iq7XxR)aYpRh2Ew*X9kJZ zLnG1nTVqgIdfzgmbd&5wLi%-JZQ^1(p0#;HImH#B+9Kp4U;c}~27|XsL$*n9q8n*k zbd!O?%<_WjHS1mnDS-U>R!*>JgvBEBW%E<}&Et-8imJR8c8U(k^=mEA7rn6B(gpZC z3H{~dEH#>m4>vX81Me1)J3W-HWBYbKiri;Zm@mE>8Q2cnK4N5r#N>S!EUH7(5yGsk zHkl_cZN09gEd7ob^*ZaP?upR9oKEJ6e*XB`Z}*^{D7hV53SKj6nP&)orop}Bpg4FM?v4%wBifJ>AJ8pcwf?m9m zUcfhDDA)X7!R`Ki8;B-826k?ehM5D~(1od8JXG)%08mt@oTW7!Ji}e9|zzj#cw2vjr!@9c`x}h;_-! zGF6Mrr^DxFP%gH)8qAIzU-xrXD(Ce^x9dH*{=H~u%VEx&;4@FS84pJKVdNDc21`9; z)3HQb5mY?~2sCtPt|7apJEya+i>T+Q;8{2$!jG=arbFtsLP<0Gf!J*xDRIkZf5;k5 zZBN07Aw)Uc{v#^jAV@au&P;fO8vaHkN~eXY?C3crFZuL@7RIsM&SY@#h9(-H>J?Ez z`IiCLMo!@}R@RC30Mk(-YmI^K9JB9t)FEbFF?;^sqF2$Ia>{e$NMX8D7^!R+zRs75Vl8J6_DELS(pNTNt?o^IOR`S?j2dTvN$_83JT5=1V= zdSGG27iBlwTN<#_SQDdSRIhk^zW84vXWDB&-v>i|-czT14_oC)=H;JXTN72;OhtZiksvu@w$484-8eS~k3mrLzoHw``#fuMf zraQ%R?uR|~heLJaSHxY(>;vUk4MmuzGs@G(qE(OH<$Ur%qngu^)9@=44IWb7cnN-8 zZ!Z;Bk8Y^WW{*UAev%KJ`#Ubt9~OZf24x1vee<#An80s_MHpw&?FlcEYm!!lBP7O{ z8fhW=(wM(obEEVAg|;azcKYDVI}@(VAr22ZM@~l(wv7p#X@VR<8_g&Tn9EZLa?|_u z6+Bi25@HFTz>O2x!yGMjob&l$nWj{e+rdRM6;L1$mk_A#+7wM>25MQtoScz1Wk%7* zFmW9e2NS0{Fy#1~HnMO>NF_DtEBT+7_*@PXfAqu)lJb=db}$c$cSAa|f8)+iny{>c5|k4HAAn0N2%k;mV99tc)GlD)!<3Rd zv?1ZoU@k_|^ya4e4o#fDBS?Z9$vjj$L7_{05_m6WYhV=ePciE-|U2jHOP6o^NcLgbWu5;lOE=oV~9UIOW+( z!Ae0Z`INk`_HPP!+!UipbH{P7zFOAVrL0)ycLV4T64uB~T|B^qdW;)3+4@<}Nn;WV z9N6gFj0+j+z2W#pKKM46j02zJRgOa|MS~fT__Sfa6}nmPFo$%RcZBbKspxy4tL=UG z%_8gJqEZTDiid5pt*^gT4ehs>E}a#y}Jj+;Hb`S;7h65AC zZLk}V$#5`@8CAr@UtVT;&`=(5IUQILir3x>>*f3BC=uR-=4gWme%w!62s z6QNryGSsns4v7M+us0uZi*Rhf#dtB<3QKM}MZS5V8CfuzH(RLH9!XvgPp@S=G5GueRrc9~wv%LKpR+X06nq+ujRzQPx6ARQ1m_GH*a_ zT;xvOJO+F=CYB2_ARwQS86Jf3pl2s&)M9V^7Yq2C%1Wfi!|tD1lVQaIO7P_553WBo z{40hp?&jCl$$3>UqBu8w!}R-+#;*&2uKZSs4SKcJt$I z%X6)LYaHjIhEwfZY?j;H?J3@SvZic4X7E$gGDP*|Gc4zInFFe8YEW|c>K86|C8fSj z*k<8N&{@xpXUjWVmM@azf@4NlBe2tf8tj`QgaLtq_cp3t2FrCRfz~JSoRApNk`~4! zY56`AFE;PvaVvRINjkV^{u3Inv*Gp3k=jh41VXkPO#G)PaXtZ28p|n^1STuG3E}C8 z`&3)txN(|MX3{N_hFS}GPm16u6p>_kJgCvuhj>sOeHRW1uf1OZ)uj*J)-?w(+gr!K z8ock$TBD8$;}_(ix8FD@lLD7AF-#^67OGajE?Z_+JPL3K6dboTsI%{XFvI>O{%Czq zEv{4V@h(Hm9?^6Y)9v=e%m3w_NH^krx8i&EBG>)3$Bn_R@QP|x+3j>PZpg4HLWyF% z$b^ignPgyB!;5-1ukk3vgtkj=7K$Y2N?ocrKfeA0KL{Q&Tyn5*dcJj2q9-TeGt9M5>Nq9lE-}}L+YT+ zPDP9=iAIgM)gv%C5z>&KAw=m)`Km7df7*nIS*;_wt@n(6&Afs^-s~CRLTfzPA9%N2 zenrfKo^WtB0qGoCDeKUeBfXJ zj<-~RESyVpuR&dlqEHCY4SgGfQ146{60>VRc(tuF*Zw$0>-jrs)n3*RcuG6cB|*)+ zXoz5>*l6fP3MI7!h+MaC7)N4o1v&a=bZ2hJJP}yfn%-o(8uc<8_7d@phRstRmL3jM z2h6V2gHnEw&?<&4Hn0=MW^Z??D$AEje#z~Pz~?2$`?UUR+ZDJ5V6~~^@!X5;Jd^oK zwGBn2^xMFs7Qa+e_atWBN+-JIa7$L^BvwSXw`c!ZV=Ce)GoaBF#apOxXKu4oz6=8! zk{R>#Z$=FVlNmtwGGlPX5SyTeqqQ0VPCP}?_;XO}8%*E=^W(o*ukS1^Qn8~OVG1Ta zmIHHI^tEgjYO`Qw4fE0njJ!*osbOs37#`*XsQEiJ&A;5(8+3yLRJ%e3l?Ex`!3k=w zIS5aC$E6zvzQ;ye-^`|ci|JHu!SRAh7|!REHO&Z08R3Z!YCMQa-^JXNues&O81g{G z7q{|{;*7c|yc_Zz83rmC@(lV57^IY2pF^%OO4JtX>?%mQ$9B@*qwf_2|r zb)UDdprNSJ`pPk~yF5Pcm~?H+rWIK1(B2X&5*;QI@ape`2TN_mP!eQr2Tg#=p;$Z* z3I?8(&P`2~=&&g(cYQ%;Zzak!)rVYd2Ey;lDA%LG^FDfY%?5c)vQb&K&nJ3(bQe5t14M{nYV;WKmo zzJfaT&U=Em_bJOZk>1J+1^1x2uYuy#;(l#q<|tuieBA9t_GB<_k#i8jj!PKF?F`OC z!9a%9N|Xm3gC!{#Fm=RY&Y09}a|*I@epybY=^ogJeWx`cIMbYx-r=m`jhY#74EkGPMdLx5W$L97s!F{xU_E^N&0Ks#8-9Kw_ZDKJ=V6~ zx@JxdTIBAUq(Wt@{(4czpa%{0{^5berii2!SioP@vqLQz2P(Lo{0&-MpgV6pM z*X@2?XFS-1Ka9g|NCmvZ@JJ^=#xWB(pzR^iV?I@^Gz_g4CQm`3?Uuz3IY@(OhSi%2 zT*Pc*8M!H4E{j%N+-$FO!UQw*CJ}RF^?0=i= zJfT&1m&k%i;5Tl(RrrLcUxV*45p9Et`T>M9Wfm^ews!Y80-Xt$3J@#n_a(1=R-cRr2(1BQTSACOqK zD*>hyHvNmZyY5k#a2+s?xoy%c+jPl_Ixy;^lzkRD42#%`BT-#W6K|2-HyfSPRquSW zn?B^yR1KVMc^;h0@wyVP;_=Sj`grDTUVqAStzP#~;$wAFQ`6#g*xj7z)BoI^*y<;$ zWy4iN*Q8r>{!U25UjOZ26zDOP&m~NQEIJb)cdHFNC+}whO;mNwo>>d|9)BR4plJ9mQb^#Qtdyj0?ofO#D&NoU3CZn1 z7s*2AlpxWGRY4g$ig?eLY?6_4L_-_vk?El+q;hE2OOTQoMjVz)qpmBqgl z-ae96xNly>7Az$VF@+aG5XC zo;ILt<33fA21d9Yv+)SW#H2l~2%>L>anvoF$qdS#4I88>M-BIf%+do!=JaIIdMwL) zu-uzFa%Dasl0cTW?K4J1&BV6F8(Vji#hZZL80Y63i1y~dixsh=K zKt6KHK|j!GnEs*4U?v$zjMP$NJGD{2d0XKwwr;6@bHqG zhAZf|&m0OQCT7Iz`#IlAb17!!;=+2s@P{&k--BQ)$c2qA$KA{GE-MAbs?+Ty@9W&q zl)xus>;2kV{OWBQ0k8cj#jg2qLOfDRTz0d*#o=E#6`rgp;|;2?dUQWmoS`ffKs9?e z4tBGTC<>vsBl{e98=Unl^{{-mf(u?uk=!%$3s#!agOr(7p4h{IMlSqvgy#pCc}^e6 zY5y`%&ETjp00RGxFW4rE^<(+Ce3|lbltW%NbUl%zJDd~kQ61Wp>cqRq)*-dF{I;ZI z^gOJ1L6Wn*VmyDTM+6MuoT@*|EH0nlSppTemaW%VMUn*h818n`ko%SqjhW3C_ix4-3!x+c`AX+zIF%7DD9ySB;YlJb2L$i#s(`S>%V~u7#c=jBxnA^ZW&hzC6H&C3)|p<|5K{yNF}Bj z@y=l-gI(1MYdV<5QkfSV#n*5DlL^*F!cPZ|749#lMH;=P_L9rO3hYsYy&s<>7vg#X zg8+ib=C|e8JynW2%$g!{NnaVYi!Y}N7vOSpkp53P=9To9aW((Kn5F_RO|aoM1c5Fe zh6Us$2^FU@iI_1^|((v!87uTwp0W) z(i&4k)R)TL$3)M{1}kFWR6Q6?0z%t9F`kW_ZjsYvG~c~zuv;i)sh zNUL!BvR0&xtX9)=FO(}y;Ysb-uEes-^VIsSIEai}M_3$(M9Y^Nz8c&f*l`U&^X2DANB26k62wVgC@kA~mhntNN z@xRYJpRP<0WgDxN3h{U@>>mDoSx2n$=7nuSNz}`^&vs3{ROo2!ZBU=S3TYIlY#?r2HEn5}m>z*YCd4XrnKJV$-=Q@F2v_wM7{aT233 zGX)5b2frb%!2nb6)>+4v@N8pX63~#veWP)iKpG*A(;7mF#KFCH*o+X16HJ}_ zu=m&v-$)dlh;LC!Z*&GA9eFon*wi5O;BjcV+=y-=2J5Y;2|f|< z{mj3y-o9e_&+m}w<(+Y|=5sbNW|`^RWRh|VF(?MU)L&PK)-+mg7-()01>Y2n!60ga znQ;EMgh@ZQO?BUU_UH#JED@sm4;~z6z<4J#cm20hf+#(xYSj0e_bk=cGuGzst;k=h zVTAcZf&`@#8igt!IT6>+DYTWlN5&lIFk*xKg z;J~}#OPLc?+&n_db%nUM@zcq~#pF@qC-Di*6xH3aQF=%^VWtB%mJNY>tk>f+b%|B` z#K6U@2LHHBUd}J3k?}T`3MBoau*fAQJ#NTr1gfYX*Y<#rTQd>eYmQ|%G|xXjFGG^$ zw@VXbI%4@S>d`jnfZ$lHwg1HeE~2`k)47emCyHlUwuH`DF+ zZE|;O{wz>rBlrKB|2t3#X5$AHpU-1`@f9DyTOpG58Go>>Au-))Gn_?3|=-Ib1eKWNgd>i#t4C^+7q)O{`X zz2D#ZnmD}IKCr3K^*EeOpMunY8MG(qXWA9v4wT0`v3M-Y0xyFJ*HK*%Xsv0?w!bT} z>ZoU@J$LCzvf@ToI`_rJBfOPdbx$=dbZ7z6(_Ev5|HvjQy_Pu_6Vev)PYn7tMNypt z3xckENdVJ|MD6#UNqU^c)4OIy%fG3v=}6RM#j{!mn335Rb)~e*Jw^_|5 z!t|Tg73A>-81H17Ps`?o3Ic5mkj8_Yn9V-6%aF)cF~x6KuEKVS^gH(7 z&0BFI))sS>?f$INVo8EA$;mUiCw|5R!(Amx7_x|(q{_bZp@@DfU~Ew?jt9AsfUmwO z^`D9spe%|x%^K2WLM^x8(0Ok-A9@F@Z*n-kjGIcx7Mroqd+nA^z2A3lcGZozw|;Ec zwmw~XRc!^Uba|V4YS)X2+x^97R1_h{|DK7uO{f9@T6c!p>;AIlCOS+ zBsk-wxN2|#FU>_RS@RVJ4`eL1tSPU?Q3=HRcQUy>@x2421T{m$htue3hI1<9Zn&}z z2d>ajB zS@3EcbzWCfUoYI7j_gl$H?Nb1{CBq5pQ$+tiHk|I3wOF&-S>@$trq00Mbf9cOc^c9 z`7pPPbU4DI5f>JkO=W8b(oHE zjEf(Nv(mjA$hFa~#Cdc?28eKqwIkbzUe;P5_!R>Lzt+ZSzhaS+TD?}#oN(Xc-C;4* zXPh9fVp4el8ZaUEG*t3>wChY9{wxfb3 zusPAs@LBcz44-Wmip4vbDHziEkiOw=yZ7+}!36wTSDGHD(-zRQ|` z9y2R>oVo04RIJ2imC63vcXV#Xfh3o~>}PBSw7@~&zDz$JG7UUL=+P1YA};noxTwP6 zQVbi9I2MBAGGx(56%Kw{f}JTwSw=k{kpSR{KI>_cc+GHKgCN9%lwO#yHdbBEe9}>P zgQB1bFB%Jz&Ly)6_?-<8cIVyi!2Wy!&k7m3V;^U81$Y0tO_WT(22Oq%a=w{b-R0Ba zc(Z#l6}J`ERRbIAyO;OmbADQn!J$aLX}{)8@S1mkqY8o0{c_t;Q`5$FV~;q5WLCHD zZ4mSQ5;E0jTV|Lu3@m&Ac3V3Sd*MEFW=$_s#TPmIv}^{sDXdaLd5Q`Rsw1QQFU+-KawfVbFm zb3pA^EEjIYP*7o(;4}6_<~GN0&#S${mY%!Zw?ikteW!|Sc@S7t^wiq5V}C6{7gd-A z5gRys+-S{RNpE8G927218|r#Dz@6P7=Ei+f5=X=h41*v*Xt)hvPwB_v4r;--}a24rpg8MbF#S>eDu2%5?xWk|i&^!ndB)?FU3} z1Q;}E-yV69iM0+y{Eb3awxSHcy3&a4yKh6Jr6T`T!=b@*mon23xGK?ZS;TrP=|eg7 zIOepYV^`M8R)oH2g#rN5(nAU?;QZ;8@1G9O3zmTl-L~8VA+n03c+fTy#{+2$@B>C} zxL7ff?{JX^dAL%U=RNZMBSoZe%Im2+d~ih++;kW0TpI_axfZ)gjfRCt57T+EWdDj> zlkZD^&D+D#`hIlPmRf?}NyR^;w{sjHuznPo$h_m>`XfeTmZy$U)? z+d2};QE1Z4JNW4|+}9)|Cr}1&nz`TPjw}Us4d8lvg8==V$Ryrsox%pFcYI$g#=ErF zh}{Q}5E)|Y9PxW^ze#U+8@K$iR1uvUAf{Jn1ugiws5I&2aDPq=(ED_fn>n&qbk6!J zwN4jxlBRqIE__S(AnD%*tNz4jm~{4wD)pbaNe4Mch4=P0!zzGTtw$%c@BHcfJ$kbk zjDf$g(t#>vveznw(DjsmMDPZAWce_;_vHH=8sjq-9dEj`K3j`(;rde^z7__AEG`Kg4fXw4xwmEAaQce?P=4Gm6L|CEor} z%W=aR)dlS^_OY=jt3~cX;7KX2SP`z;m4?TzCsj9b!+ucmRxfK|JfDDrAmeSxp(V{Y z9x6VRWmLmd70g!DnQsEkBU=tnWzI>$>{=Hn}=0T5;s> zMR}^MugUIi7>W!sHykizIE)x`JXEm9D#{XPz^r|LDs7$+UDH~xE_6|&?1z#jwknOu zwu}k)iYb_3b7`=GHJ;vB!%$|r1ZUdJ_loalBCRQORM)5yKZ?|je*k-zJ=n+hiQ%39 zVz$}4ja009klycFzWwWUi$O;C-b^ChtE5+N7HS2abIAN7gi1_0BPb680=31M57NYn z4UV~Cb3Su!K<>P@c8NC9;88&_K zCRS&r=>MU)iVySYn^W3yZ=Svluijz33NewL{{e9^HQneFY_n7*xs(|kMJP<8ox^{` zctz7mOC&yH2s4O8@1~PL1Ff2WfYYOMx)ViwJrZGyU$0foR>dyOH0#x zlkf8f`{&A1sI$^G&Gzx|O*^`(O*Az%D1UlC4Z~jE2oAG*Bn=I<@cAz`lH%0-Z+l+h z`H`9w6E0|vIgE}ZA`YE9=58=-KG8cB{pv&nR+K13y}Z^aR_bugV%Y?GVDi3v2Yz3-Aj=%X~l)lJVHo3Qj4t3;F?N@F~t z*!Q40heL#kHsbZ0AsK%y8Xq#US4_!cNqU;;qdSED#Xrc5Bc#quX+gt~N!H)XN5LG% zE-{+TF%L}%en(e)NR!;NvHeU#B=pnHJ9wF38~N~e?JZx&QmOt~6sZBcrNEQG$R&wQ zr%b8z{%t(BN~{m;C}&+X`%%%=`(g7}KM3$8y;P)s-%Q1K-x>lVck>ux5sMn)4D4QCch+0p-PA!;llpBoT0moGjVycMOt%oB*L zQIpE!!OlWWwQx!1OL(b_dU~H;*XgKjQzFAwB(&M>)MHX{lM%>ow^333)vi;|(`-``6Sm zG!k#gk-j_BT2Y*!SeiiM{`u-+eN4|A9TI-3iA|>fQa!Jc%I4tVC2E11;gatd{iuO@t#Boh}pWw#_GZ}be^Z+xLQoEDE4)N$nIQX%R5(%9R&bZ>h zm7Hqq{tfvpf5U*U1xMZ0mS@&0XFSpS7lijujITBRgqnQVOIqJO?yi$BFMd@jHX2+G zuX9#v%jzR0JAdfjAeK-Qc~qFVTb)t2E^~CU<%&h2L%zp*$+?{1rol~$|&}NHf_sLCQ#A)GP%LYb9qFSp6AX$H0$$6$uu@AMK;i6{9h_9LToi=CZz}#y z<-TMO1%LR@U0*We=On3%KB((Q2DJr!6Rt?3)B3%P#)vEgWeRwH?j9br+<7<&miW3fKW|w7R{r1zIg+1^&X)B&oR+&EK4FYO(D| z8L@gFMMDqAhT55%mBcwo1rk-*bmilYO3AdBV#63)9L5+?FR}>zlCb;HrusCo_$UER ze5C$fQ&49c(+}bE*u&sY&^Ir;tH0pbxi`us|P$&E9(BK>?tVupXA4v`yDR=zHQ!C+*N#3XEZK6} zm}z&5&kgl=;HTY_B*;*ZR!n1j5lC4U>v#Ceu(v`&3O#nqpH}$ZUc@rps#LoZ413Me zs&11-*BlYc6JH#CV7xEmCaFaGTXM%4ac%OBcblCKW@1q=rG-Y?D?=k0HCWS(2;2vz z1*Ql@sX%56`m?70Cb%L^R8(4DRw@nduB*d zVi}m~h5GPcg8&Dw8--z+?uXk+#Q0`5S*Zm6EwI>2<|lQ?i$=(f(8%4-Q9z`yKCbv zyVv{g@2t$Rh14EL0>{nY@jWEnJ!rzB^U2 zd}NzZGl}OKx}y~i9)ybLCBNuLUqxCNlzn%Trtjs`-a*v0ljHli9QJ-P#G~Inwk&Wr z!4Liz5^nan`HPRh4EXA`*WY31^5^*eUl-K2v4b2%Q40M%1pwdsi>&4;ia|jHC2~Yt z&jvcowqtPTR#txil9trHSHKZp%&V*iQDlq4m(-=Az|x*~B!g#SJTa0sOG3&)JG7v? znar$b_~6NWJCYJpF3$*+UN%wr=imZ>+N2HAJnZRb(k7H_-b*eV3@~k0tg;lem=BNV z;Q@oLx^|a7=Ljw}wn>X`qGj1X4$+wXZ)?ti#rQ{DlxPsTOJFmW+8lguC@N5jDz0zT zQzTM_a{U@W9^0_}&69^}nSAc{NCvw(rGTg1x86sbGUcmoyW?FTX4l~yzd@fb#49}? z=D!0ne?PJ|-lP@2*&Qv(UDEegv60Qliki-|0F8@t#7M=*DLltHk;;cM34YUqo?aj# zk)9SteS+az{@(T%7*xG6yJS9w=DV6xQ1hfrPB8XI<$&z3r*JytFfBFsUeeF9cAD3{ zU;-aKXm~UvQSl8Tkuf8~cluSnTb<2dCi9APxktm^&VL!N-nSEBb*EZYSQz9&X4g6D zR$i1F?RR2lu8Qqr=l(6IWP8|G71`2l(N)eo3cM{2Y~6U+bf#ax^dlP7#q3N(`1=|w z*fq(Bu?zLqBh4csOmKD>335SOJ~KFZfSqJOkm8fPmt}HDG`Z!pC(&#??aPyT3lhi8)5i=0z^cSjg@_dnTKca5+yLOapDUo&r)vklNP?D>viX z2|W#O%R`Ulg788nloHrSOm**&({ffToOr}T^#wLMy^f298hKc)Mz-dwa=kA*$U81W zX0tZu7qdOK#K3&lgCx=nJOv>sRCHhfGg%ZrDsjW2cm5?SPR>!^q7yEN{Y>4#M^W}> zad>g-Hs^tz8W48Yh;&#ey*KTE5P4>@ol4uoQ?S7ROS!#;o?wC6-kE~S+5X7T?f}fX za_5!5lG2NO)9RsES_Id{7IipNf|EDMbu+AbnZhnIr^g`Ab zHZzJYDwA4cJMMVFm6r4Mrj-0;f7C#z00DcD|CB)g^>$)n0N=l7MXWK^usCHpHL<4b z>+>Ibm9w}E(P}Eo)mR$Fv@-yWJ_#PGNp+OLU(5kdggxjM^fbDk4Ns;UcfLPTJ;U5K zwzpVFe-HUZs8WAQw{Sy-x0{y(ZkghE?IDu;Z^J6JPyIqb@p;pIn_nu*jVkPUgre5G z2wl%qzvPWBgn5vzUW<8Dpl?*m7xLZso7bJ!uI&-)^r!|TNd8-|TZ9z4!Ku6m`Ve%F zxEc8?@73e>*K5kgR+ih>6Y2LkY*^ znj%i&hWl44VU{E3-lvoQT(iv+>(w}JL(>5a={I)iFrfNoWvwSuwqv< z2w}2pf*A6^eb8S9&(ha5+&N+t(`WNewMewCu|l8-!=lLwb*VT}3E$#*Gl{lAvNKQp zMS#2lgSA*QNq`JxaSZ-<4AC7-YhiP3+5^pnJ*V#sgKrerQ5wcOd(E#ixS1Lg{fWyh z)lbK{uk(lgH*#6~1E5j+k8aGhTXTJavhf&v^|;N3b}#G86vNx}@Hr5RCN3LT9BK1V z>JM?xYY4g2G%mDVKLByzk2}>P?I2F+kNeC&RMIu94%aEXtR+eGZt$sZsPXFUzu=bF z<2fT4`YL1dVq})-jnaY-+==lqe%F2`C9e7guNqiDng>#p>fYwW?}<$}`YaGduhOnT z?XSkP7LOpc8EEMFkucg$;)L~&w>|Tb0s5cEC_(QM_{mp_oDx8IBp6b()5{RWik+RaJvkH)--GY>qc%hOlVL$`E| z1F_B1lnqt)O(IFmdTHytdl0>+1GfZaNuv*`8MdJvc>+!#OB!ytm=qzhElOu-{TOj* z;1XdA3|LeYeN{;4E*0 z!cwrshLwrUp=sY~RCBzp;r%s~s4OCTKBtn(U4))Td<&fh#EcWG+^!jeTGH1{a3C9|#7s5nSnWPylw_buOeUA(gN%F39;fFZC2f2^8pjYtp&Jpv+Q?B>= z#}!#2$MMLU#)7`{7a31O*MLy!%uXl)bC5lD0bSR-@bUm*9UfAbK=d_g0Fcq-o#KvjsQ3G(mHtsi^uZ6BlH3>U0MJcFkXf$PW3=ip6% zH3j98uK)Hddk>YR{j9$ePGdw zWckwMa2%*@=zeMq(6e-C<7zwT-f(lQV@HbmXSi);Ed4{?7-_vM!ybVzT@ z@CNn92-W601r|g=L~G=q^+~JSPDQIQ{ht*9IK)QS#|eQ?f>@N<#St;`_#01N5&Gk_M+9&7JP43elO6-%5EIMeM8iwpqm=JU%HQ+n zQbnl20m#Cm$DJhaL`8oOZe~;-Gy;6#+(qJS)*#ZzX zNx%B@AoNWSU&-SX|5NU@Xd&51PKoFVJm4?9mu0E(XgcZ&o1?1NERfgxn(9Bz$riIv z5kcDY9jb4gg5NSa(O`J$P<}SL34tuHuZ)`MDFnaRA&17lE@p#qq@iw_=f`(|d*44v zTMUBjnaf^Vpe@(4I!xujIvcO==|N|Eo$LM1@lbf9@krL&+#>mVguybeb4b)~s6Uts za?u-T3barb1vgi_+#aDnP_Qr*jLVoxNB~n!ZPRLA9?u z;FxpfO#U_Rzh;W@XY?9Mpdbp{-NoogQ?+4C2mK8GQ}a`yg(z!cO^r!^&Q9Rq#x9e?ofI^gF36Bb>tK>0 zD9ekn4;K4H=d1dDtrKCtv-5IFRFlB?P5XuF%8Rps1Et7nHz<}G{SZEQ`Lm{yjl`C- zjzq4T1oX?|;MxS=#1ZeK(4bxaJ6?1&AZ>fZSuE!9%EHL>d~RKCbjUbLuXFqI?c;Hs z$M5B|*}%qN$z#vA>v{+5rxm?LO}BfsU#DcJ=Qpv`WI{SFRc(S9V=K=XW&z2=?UmT5C zE2Wt(Ib}kGjd^fRa8S_9*z9)oWauyNoYDWzyd}&{ZNxG@gB@KoV6^7?yf?&73DA z#880zIw7hJnmBsUw#6Qy6=@82D8rJvhD%Qd`$&zT@W9}fh;vhP8+Ihl=R4H!5O^7! z02zQOaUAwnT5ozkL@H+;=Bj<*TVK7UbGz*r|FAo#4wrhN(}AZw3!6V7zSABlu1}T7 zH;8K-Rc0+l)8UUD^1fa8B(?%$jQ%I6h&C1RH4$6}DkmQ4hs9tl2F^~es{yIEi4;wC zjZU|VJo1mFqLK**qwHJp_7klG1KlPkaGofMnBwB>h#Jr;9 z)27AvQA1V{q7zUV5%{na)EouLdzs%(oLFmmQnok7J!^*kq4Rw#9C;M)#N{^<6Ok@Uvo)5h{R&227QfBAqJOY=f z!ajShbS+Z4@BfyS-XFVKZ$oDPt#@Bd3=X70=6?dLp}|A493JUa+013b+59U?wP+aS z(FzGN=C*iy8eTuyxY+AZ@(EU@6L!^^Qpdj_CEAPH)Jk_)jt>RK|H~WSwIF%_0ki)| ziF4hK*<}&nhoxvLggQZEOalJTC1VXy{~}P4U0+q*H(%e|>@Sp5dtRK!D~P>;5Q$3E zm^CM<@N02mn~|f5$zJ;3*V)!!NGD(b%N(k=1<8BC(u@U|*Ky386tr2k_@0;SDh)@H-O9_(!I$(;1|&eg z8u~@kugu-~>YZXKL@M|t*j02XArBn}RAkJgGqCNy@2i}6=Td zE86{vzzH|7G3CZor4T}D0eN5;QR{?O)_`m+pF$( z_3sl{)v4z6F+V1-~Z7-1gTXXgbD$w7}k*~fs zUZdYiIFznD@NKV;k@sjBuN?ANit<>Myv{! zxQWr8*Hg}Qj2`j@(d3)Y@Gr-(*e=dDvSs zmG37tu{DUJbPqUEBsd+FMiU~(Rmh{_EwEzfH}X_NZ17DSn{j10X5G(s)=Tp#jk-l9 z&HugU5I+Th+$Y&xBu;CGO0W1IwLI9KygoHuUFrC#yiG*TSn0&G*%)8ELJ~u9`o{D+(E6t?5 zqo<+^50lYvs`c#Ux1UPz!i!wKbj)dsIpZd`Wim@b+Ke+~9o|H3ASo*=i<15X>-kcf zOkb^L;i=8fEE%JO%X8ex_I7mVW*Et1RpPh;HK^TD1HE*nOLhAca$LVF@ay~Y$M(kJ z>yW+m7hliq3gMT-oc9l*_p^^jai+gTBpdCncTeMt28&C7w(a!)(4hku5eg9fCWm`0 zH~c*vN316k_jWdrM`AV%mj@`|ReP?Xzfo16U}O)&9rxvR(YKk%T-F*JX`kcs>>C2D zI)4foEwC~(E4(}YVIY^?Pu)=6RYnRG8gq{&ly|n?{y}@bDaoD7W6Ln$`R(%GrwkL? z!GeJ!#@zbIA{gfsRtZI1E_m#kSu?UL<6g#5#`-!{nWWw3N%;DZOS%3PExzm4A~7D+ zI0}>F33A`n?2oIC=|q8>D!|7-VQ&w|#E$`*1si?A4&SHIQMo86RI%t%71w2%aCL3( z$S2De%vq_O{US5}Uz^K;D?xnV@3irmziun17hDZ2mo6sTUJF(aGRzxlH5vOl3>c#r z{XBJjQ!swHPgq<0oZ-<&8`jXD_{I_~xx3`#&Hq*)W4AbuW!J|3znOFPH4& z2P^_HUSh}iacVr`5shM*F8CnE=jH1cx*y>B`Maa5)|nyS$09!g(DNU6)PU*|##de1 zm=Jk=%mLfwB650H?cOC>tD=$py_J;}O@pqln>Aq{YF;$uLS3`a`sdhXUsDph6oowO z>~znE+pf-z&e&2LX|2{*dS8WP?mLt|_z%IFX07d+^G!ZFiWaQl8%rz0 zvcE5^rORroX~AypzbiLpBXG==P)bG~N{)m=1Y%MzpAQI9D{};W&N34qOaz~&G(h{~ zkom?dPba9po$YDc`s3jN;5WW<_??Qva08EqhDp@oIc0M?QGh);4O}e)RG&Y#$ed7jg4D1zVR~{G6`I&SqZd{^>oc z(_scgJ&aJe}Cf|A4(#qJ=tM%zvp!AB{ z={xeNpE6p%WS%zE)dg|8FJ6Yg-Zl#-A{-t6rvBkUnh=#>L{-||k@(lkaA_-6(k-o6*d#FtwF;-u^=_>Wp)o9$#zo1QNY^steRs7ny z$R#0(lP6Q*A-)+Jj%Q6|J9)Nb>&zn(`un`RNhi6rY2692#0qWt8+IO4x^Kr1y|sPJ z`8>tmdQX#!pkY8HR4?}DUo_OHV(~KnVF#e8ZSIhm|7%#+Ud#Tq2f&mCTjKmB{6bi4 z$Ssl=P;OfM*dw$z@n6e|NVR;9LO*~mK#>7Nn`KfiEY0TBmcmqdeb1H4M!e~Us?Z6Q zGJfAmpM50#F2x=UeuBCV`DX0AqQwg?G$cp7;iY#LrelEUa;7(H4uj(OzEoMj>Gq%f z>qs;P{p;150uHTD(#g(Om zGiU-X=leNx*3{EumKN-w#Vt6UaB}*GX+ONG`1hTA<5WC zl9W1E?%)2Tc?R`a|KhCpERy+eQQjdJV#(=XSo;F;0Z;*^{YEcw1c#wW@>;@(rN@mv z+W9R}s^LNUkB2W&xp8 z3FWDMBVkWYTY|T(si#1bYP_?eSpO%vxI_6k#fb3^VFysZYLs(aC|PoII5>NFBr|xp zc-WrniIIh@<9K6wriPHp%*AED)BpA2Xnm=*{%Tn1?XL&VQr7fDVWy3~Z>;g*blng3 zS)9YqBhM;!zmm{JttGJQrstf-hvS~^0s#<9MXsG{P9=Q-s zWS~c_!VLCAz7+aU|EzYiLEP4JuoA1$5Oom3VEF|i0u&8#UqB+MI=#%ul2wF%o8#HY z{4XO2gf9D0vn}sG@?m?tA#gz#xMsed`Maa9T63lKRgIQ^!H zf(xd5jWZT{VQJ2ACJ!Wva)i?_Fe@6+#RW~DEv){2LkcPWKP|wEIDe9HLIMmGid`=i z7XpaUpE>(x;LAeTu~5IC(*E;qsx0hxSdSOG*OBzc-%cfAFd-?VmBqhE_>Fp~2l6x5 zQ$bbqZ(uwhwz1z(Tn>PB7|t<0#ONpcUmZUKB{u~K3B=ZIrlcO31KS3{wESor3 zZMZZiw>K7XV~S8c5&6Z#Pga1Vs0Fj|=G*QC8#^PeUbgX<_Im)_mG6=2oD{AAQ}4`< z6UL#-FjNa9;5c(U^m;G(db(et?{x&3XhFy`x<8~gUHaa-E_3>-1Tkvwi$g;CtcSq* zy821Z`h#2PDlpImhWS`wqPwcGJBw$R3X}^8&P#zoKol+0LAcGi;}$lf(o<NSVGp4&fqZRO+j8T;m6Iqv7h~JzIz?HfbA1DWzI2 zT2)@&&$Y;QwF>`23AUpv`)8dj9Ba}cTc(ZCFc6Q>thQ4O|ei(j$q!A2QJ&XcxUj8OWQJCx*WvhAk~a zAN7_n254Gl?Lds8J5+4^8lQDO1y}W){W+MG@6C1f&0j-z6F&OIVC2dyF|vj-;yt+T zP+F3%_a)$}f||zoU@;(AOfLMe1dcQZNA~kYEObrTbaMP=yT?Jzc?@a|3eTjj?-8BQ z`wU&~0gkSa>m%f-5~JJnq_fm;M3oCuYWKXFih0Gzk&~(EG;*Ag(j9@r49ANo(X2zL zOACJEI=XYg>^T|2PDKRexFX*poVF_{%I$+cd^(Y<4w(mQ=Gb>r^*jH>H3(`7vP)4J zb>kURdKR~r_Ot?O)z3M~AKd>uyJ(|7_TxjV65wD;bf`pU(#AXNT3h%yg9h{Z2O+DK zxuEuMwU}I|duL!e9*r|DJ9CtTiIR-R91WeLX%za~y`v^IjS!WbuNnDoW=d;%%8s5m zweHtB%d?6((`S1aq>{M3oz6p>xUW2cH-9$qGr2k++bw5Gnk8}ALr}qCj5ZRx(F^F zl+z={Ikqi~AjSbpG2f$Xmb~u8Nr|8<0L=x-e>{U?n5HLU6JBCH!oLC-(GV4v8jWaz z+Jw+-*n|u-c`B+*!|1y=ZrYbQ5c5cxu}wi6UaewH($R-+8MD-Md;`B zpIb>V>VHX_n+35dK-6Zc*BUtliKLhGyx!FGbaD)p+xB1antmGtntDv&xOf?w+3Pi{ zaT~^#ZC9pVRH_MvPZg1T-zJWJ=vD9QjeB zU6V(CcwGybxFaV-!?!%-S&T5;m;jWtoaa9IQKhu?FiH*^hcBtMR>ses={iLY`c~?C z8LjY4y8fHK#7A}SlOC4UKM~d37ct|BeCA5z34U0CY)2tH&5+|r9*kUTak?KFmzx~w zlp*1ddpqm$eKrvK7XzxVb$FQcUCjR2Uaz^4|7Uc!M4}$s85-@LGvmjzPaJTCyZjH) zh$mbqHXx7XCnn`9_eEC#Vbtfbq8$Kf&+~XojHe)}BArU7B(Jl}7}u!5b++NY9TdY2 z43c{yz&aPQW{FY|=d6?F{~fnXZDq_t#rl4M@C*Ar(O8`m3BYur zMa}rcF?scSf}u7=y6X>pnCls@SthWFV||SBsCVOz)uEor-t72Ss(2SQC!@UL6dg!FzmeabU}7`=3Do3ZK^rC=R=n2&dL5nN}E{G$6fHzsi!O6^a&i zebVEc0IAVMdD`N{)ckQ#&K9mlw3xeo`P^%R*lTP*a$I6rTl1w%j{8kr_c+9aUR z2kLK&DrWZ!AvLX)e;|+p;5KBk5jO->zD|MEFTgD%2@!D*RsV~co^O%8-FLeK44V$z zATgT4g-=raEqdiq@}V<9sRX55E};!YPqYjihS|8Q1T+5eMAE8;R*?L8x_vH){0-GB zqttJnXH$^k1;IGqK6o9=rlv1ny&M>jgG!KpfB*9$OA85+v{FG>5ir z9ZXE>D0?8}(L>>b?x{nS$scUR>51$V4){7#@8(Ct#7&(_y+rff1gFTU(d!PTA7@uF zUnK**fZ9~MNoDVs25G1RVmbcFs zMa|97lXoFPN@t?$dx99zA>xCjkaac>awq%h6~-n+Yu|Qs;q{U0+h_2u?q>H~;}6Ml zKFqPc8#&`1Tf5x#LRdN$j>AYe?HJVvgLG*xxtZKAk4RrC=Vg2b%q|>(8LAt z`w&PKgytdY;0Anh{@pCq3-#uZW$+1g)>-9H?>DQyN-cX#?bu1b?XC8`c2+ar!?|)X3J^rwNakv@cCmLQ5rH?)zC#cHutbLNk_-?@ZeoyZI{MOazYnh}o z!o2zP-1JreHqg{beT89SA`|xN(?KRMu|PSrhC74J{s{~zDr&sMvi(twntr;%#|qzr z%}J9k6#?>1=-JjnceA9!&bl0c4W(9f+2)kEiiaZahg{)33{!aX z_}rSrz>E$e$6_m`_drKdNpKeuMQJ$(jzcFVa!N|}e=d=;rrT_7b`n+6%M1C>*RzGW zeywM}b>Hr5dcz_7W#aSvaH_c zfopIw)=S#_b}mvsqD>pmYI8nn`J$3F`s0r=$Ew@>l8$uFgVo0P%Tl`-BiJ&l*J|TD z{X5a-zEJo86P)?LQp9W~=sAVqeAz(`CZJ-j5nx656*$KhFinVDx1HPi@?V~SgY+x} z@n=~g1{~zx55e{ZF0f4sz|#qqGXE=F8RHErJw`>dg;<+Oqz3`txj=Ji+jhvXw|$O& zYE1HzA=&OKqiO?hmcJjGoCj;5k-GY@;tOVp4#?~Jj2ENU8v^qPW*Y(>H9Qu$>(Vy$ z+dKehv1|Da2Rhl!G~ehD1fRDFWwX>D=ZwvhGcJpl6(dn3>3NCkc0_xBK)%wz2 z`j09=5?||K7rgiyybu~o0ngegK8AAzpP(24oZM6MQe);>g7i67V!?5$Tkvi zYF$L%2Va)}zl2Qem1*CalN256j8F_!ELJa8=2HA1eHlMG+mH#U(6sYm*Ex`N{l;5Q~iG!>Eoq=$y!nh3c@U;H+RP-%UY`D{T-+ z?CD|r4+hZxX#p86UgilN|Jh;`*A6U{cZ^+*=V{H`x?MWqAbNyBkMfY!^0ijKJke=i zTfFj?R;3^Zud*%YeT9+R$KqR}Nued1=@72Uxd=lYI9nl)E;bQ^ITcleX(^Fn z8`a~_8TNKxOHtJ_a&Wp}MXV&Yp@F5@*u~E<)iYjEWA#|wXtfJ3hGvJ7p$2XD)eL;- z=^)$YYGS5cJKj?<$K%)JWT{%-f%Pr$Mqv#%lRGSpo$*@!RC{<;qm`dmdRlOs#0SI3 zPemWn-{7nrJHx@P>NRv`PxhsS*n8D3N67ScNGDCC6EM3Fl?He&>vFnJFmLH8U#s`p z4D-9}U$uw#t#po(Qe5A~j|(I5z{4r1ciYAexIl!CCM=?s!UWf_WRz>xq zMZG4X$GS@};IP`U=6rVCB}Zxb7r!7a z9R+I;T91Z~z$pZuGs#z1HDnZBfDPnlZtqXn=5R@=!ZQvZOa4l8}BK#g|7R)~*X_7TN*Ni2dIQk> zxK)dlWI6T9koXB1xtp@tx*`EGfJ@}a@HzV{96>?G7&Tdw5rBLI4#ARO3_(Dlkki*@ zAaBksx0n5nyK?j62?ZqRn1fg`?D=Dpe$v5W+Er5Q#@6YcF z9UU&e9})z?qDB*KB*C>kGpi36-UZ`}VHR6zMwZ?>iUdNN?O49&&qQ-qMbg8kN(#2mL}CXA}p7)$y97Ps%3{lFqA>`SM(upl}#*JMwtU|I;id z|FLTq;O10O!<*lPBJ*6@<#AA#d1`K4cB#V;!KNt*+|*27$Kn4!AgA+-_r}j!u@a)| z1;zD-dM_zeS&@jg&wYhXJX04mJsw|T{LV3#TAFKJ+Yez9#v+@DTs(Q=w^S~pqbWlp zhNzD-vso4IyWmJorf@;h>1=(xP={Sb!KGB_60wpQlFF~4tR+Qz&x&U_51Ny+t~3Xd z1)2-m6Gow2+9f-o4M1anl%a!kx%y!HEDGDUi_)Z$`Q&eF#Vj&Zw^D$fz`ppzS4)gW zTOYLoEWUvloDx`?m`6%jF*qSZb!?-nH@aEf1lH_Q` zL(AslYl;8!;*dro=w-9j>mH);jo4EaXNOuvMZ4CjGd7upRKS8Tm(>GmQWxkKDj3t@ zYqibpHnfvcm#^F1b?6gqi-%A0S3NF2GX_GgdP75|kuy)av1@DFgoSV(&!W%i^80tY zb`eX1Z3)U->O?;c(<2oS4nr{S|0l$18j}9r43hU1cZZA+h+@y8?R1T-OdxjGVnvF zO54Dk-Obr`9Qz9a81m8!o_|vc$uXOIfwewFBnT>?{8kKi)6-4Jffhe`a!r(D*apfc zfZZoVFs90jG(rg#G;*{Haja1%NOt5oJ0byNZHB>}(n~B4(<#IZ8Crh6rW)K)I{q60k6*9)5jc%cW;l)b?)k^~l z-O28CtizaXVvlW@OJW^9GDY=v#~Ac6Rf`0CIptidcbZCOnu!m}gGc-DR^n}nhl_M2npGfn5?*jXbkW~FYRLn9W z&IgqjPCL@M8<~G{#sBSY;R8;j^Y@&{LNe6G^izg+ z5pzGbz_7XEBrC7aAyo!~AD&Q=jVvpOwn12$gU}dUlaMa2M^3MeZ;^8RMis(GP1YQep?ckzuJ@J5?4+ zB0|X%qSuKmlb-obxg(X?#nakl;W-J6bLjgfqQEh$013al#Q#5wHk21 z-FU_V-#pJN>io^ahomr$K0*xL!&RYwj8DvwFV+U)DexHB2Qt$a?+SGQ62H-xFWptC zfYst|W)W%S=*up37dZD1f;lMnWla9nZJTl?@c$a$mY2iWmpmibx<)Ix7w^b&V)rD> z#aR78k-M}aJq8r1EBE{wq?%P!L{!#UQ-l8OoIISDlbv;AS#G_BirD)i`YRFVwqhi(Olu0{SS?z6wS>!!L z4fS+_#DO1I)8Q6q<4NkIB9u94`@80P`Ef!WKCm{VrJ>$X@J?$ZZ;U^}znuz<)ddja zb5qWF5a=5GLaPdI83=T>kYAPy`UkDVZEpnDEPoVHChH=+aln)l-={)dZ+I8xYdMdq(vRsr) z*;luA;m5B=8CIl<_FSIYNdj?&lO0ZGo5Hc-1bh4 zH?rD>B-3@13~3rXNqeR+`jrnY&>(k>5OPN|7zLjA2?pxPMGt|!E@u*vIH)3uz~if| zgLUWETdF`4A?~hqn#bIWbmhRf-h7c2M#ZBk{ajGI?_$u z78#bG_$9Fio!7Rh#}%t;RdUEV;Vsh=x@L91ZZkv$%~0KAI8_iqnVH zu<>U&k)T=!O_r(%N^*xKJIhy*qA0V9-MR#uKUIfGym}ews#oPg8X2fq%D94Q9wua= zSrcl3*idO83WOaRlw+;Rsaw~bg+bs!s?ZU}x!YZg?3aX9LbX$KDMZ`A#M{BgA)Edy zA51Qq*qYKnvUwpHCi-IUb$ZQQ_VBUeo$n5Mdy0aPN~jKn-fWHl3UahvuG_Z-tC=Hh zMmCB&j!P_w%VopjeeLGI$cO(@EKAnG7TLRAsq2s+H zD+YU?81O};IO*j?&iMxU{Aj@C3+)<17?JIthzwe9%Gy7*K>{rQ6^jY5;Yt}9p8L~O z2!#5DnK~7Pd7H2G(Wh@iZKx+qE<+UhXITSzhJf-w3m>}CG3>TZCbBD^tt<}>5ji_O zU(%5!FXZ#=q=YEJhC&|)GrGCvE}nJ184kV~Xl%7x2FvBhb7lEs^=Z39m~rVC zh}NSp3Xt**bc{`RkoMvP2ZZ?1V=%(m-@b%DTrvrNQjOiM`@^pgYZTBKdt=_yx%1S& zC0)mu4Lf}S8G`8WCe20UA*#kQXHrevCz_LKKa+}OkloAuG5%wi&Vd1+@d{I1e>20_ zOkz8-c_cz3j$9hfkgIBCJ4j&ZnQVe1?Kp#Ey8-v}tQ6u7kfFK=b_+@(m}w>v8rV`! z6>{;Tb4+$B*%bDjqPM2nvRaF|)QspfGU>?9v}f9o&*^yP6%TEfLO>+!OqZ>&VGh*1 zZq%>+y5r6!L>1;#I5_bscmrfd(V1IT0SCUqa7U85U=0Vj#2I zB_ho)lut@PJpYo=Zd6Ab*SxI?XJeYQ(R62WJ6A?m@IXzdhAY5z-$cPKPIrfpG)QFH zVF*XWu++7S>mItI`Q2)6^>UTXi(4SJ8*I2%h>0ym#8Zym6F4+oh|F#{Z808c^UAav z9?^c)ML40D+|EBTf?T_&x=FWw!*!L&#FT9@an&QCMaM7T_Ark5+Urd_p168gm?!kO z5mzbftl|aT5gkiiaw>gwt)=QYLgHStg>5MmyS8;D=~h+n>-PG=(Cq|HucS(9chLoRAnCF6M7VoYDBkbwopOP_3bX$_Ysi+!LqwDdJ}tQamO9$o_XxplDq~{kV>*< zlX=h@(03PL8Q@ptAq3)} zLEO>JUcs7s035rjuVeMg4m{DEC5E?rMZ` zJO@2d$axfG``t&E-vzG0-V1Xj%lgYh7kB~e3$poigpZN^-*Sd?1tU(NQ09wwOcl{e zME`F5C&i#5MG4IOIDJaln0lsY*d!wV=$-`hsE7g&lbuHIkb zmCHr>Ia0A%#5pWzc)>+fO;tIssRtcmQ5m<(nVl~&_Ag<=)y=JA%r_)mPjgiMZ@c_y z+zm-n_Xo?UCFE2qBVPD(?R&o)vB#(d>hxxoua~=41Z%=dlSnduot0=kDc3etU^6e9 zv%B&0G2f&WaAv`#FT&Mm4;Cwo@~dAf*6n3W0h1n*+tS^G*U~Cx1_Wx?8znHgY|6e2 z!I5<$ob;)$$RO-P#=dja73n!WpYA!A`k>xkAt~NX{=tkKD}USLhgi!1A?rit4nGqCDjjU>;(@bjP1<|s?n>B#iwTN4)m`nrYDW1*I!I!&W5<(?w>sXC77C)+LFzY6 zXxC0;rv8aI{*l1&k@#09EGRY)@j;f}p|v_**^uye)f~p~nL;}^q?7D{cNZ(Eg>u|N z)&F>u|Ml`OR|RLl-uF8{ZOcO1lm1^Z+bqq&7FKO?xIYF6ly(<;GsIB6P71YuH=$r7 z3?K~MhYYiH7rpVdm|I=xwHO2rcdCJPLw<%e^yJ0T{&lGEuqCsianqs>Se0En@t9lp zh`OoQdR}4pDMLFIi>TEFzpR2iX6Vt>De4Zd?b16rgF`K)I(@PiR=>+l-{Y>ALQ;Hw zC-=9#T(7=3|IG487&)^Zw;Mf50#gcu~P!M8+AayLlw;cmc!bCtwQg1rK(Ydee+5bn?TSdjy zMN8Wd5=hYCE(sRgp>a!aOK_LQ-QC^YH3SR6-QC^YY23AO`1gChb1wdyzJf8D!5Vwb zU9;+`rMyzmC2yxKf4l&RsAVNJ%0oQ!yMrYmZZSd&v2DBWXd1m_scuB;hZR@|_7G4% zBKnXeD%6A}CV)KB))I9dsYrA?_&o`NUv}*_-?{Ym8eOY}jKSnp1{d+kBFt_@3 z;v#AE@iuR(SR%pM-Vp`C-n zT7(`P)!Lxq=>$9Lw6W6h@H-WYfPXhroNQH8yq6RcL!q_te<1katnGf#w>IsfSJGrm zd4{N46Az8`7I1wEjWJnpL8616ryOfFQi)ETfkj z3j4wl`DT>@JC-z|aL2!}z{dl|?7VM1Q5roS_d)7E4Ox>oJ7VyE6>x}Au~l>$1;Hzf z-zQy=p~9Q_6a9xg2m=OQuuve^Xyr+O@8Bj3BT4|dOWqfSAkzpyE(SVp@*4?{V26f< zE7MvoYS`(jRB7c}kkfaj-U$ssCY!%1GBwS5hp0>cuBQCB-ugVcTcc|UW&U=&l@>|N7y4%WM{LT(R2AHd&pYUD~yC(9TvJLt(ZY;+fmoDR*XE;~|uoE*od=6BF+ zt>gnmJzCHk+l2O%h8f*Sf}m6m^z@*a>?IS}?kq_L#4Iz9(R17GTflafnDwP4E%JSo zJ%;@B7KrNi{(@_T4)wY)9LrGK=iSLE1{#tZb(_uBU~x+d+Q#S8>F%w*hPMDg zp8=2c;Zxhz_Upw7@9pEaw}DzFcK#cne6L*hnYL0E(?__PjbQ{%&xKsX!#;b7WoG1W zrME%mpPlUhq+cT!?~U@I?MU( z^Sk`#e(V(dUG?VF4Lw!Z=F&8Pkum&>aODVL1*T7`@oER{Y(H6o! zT42tcxR(|jc7a@41(BnRF}8;}$75+9p;(lfgezI7R_$U;jBZ4^AbVtmed`;k)Ntu1 zZYHgkKhoIW(={gJWj5wnNyMpoN@oX`I~f}+<_ZU?!a{bOs*$aFH0Qqs^pj)0ppylB z&m@RY#JRuhUfX;gc1wGI@XPYY$XaX>vrA7g{7y#EqRIN(L}^qfq>~jMA)m5P0>Ttc zNv3AZym#y_P#nFA!n%qwX~xY4LQZ}ZE-Q#$3Y%}=AvR3$Yt7(#q1(Qk2Y~J*)E#5D z98)P|3jhaMiaPJJkXiR5 zvdNSvEvywjc=kJe$Vb0^x(~CB`4qPp&jeE)g{vsHE+1?1B6o8!28$AO2k&b_^XI=` zjguMKx~_?0xe+xteE9zL+}~`+6d-fWwna!=*loAjk4!!JZ1E4AwiO4sJ?g%(Wr(?zpBk)|w!2?t!y{+t(m_Jg;(dvY26vXDzpw8s2jDZy1lQPq zvtz94tlx%3)D=?}@sr*9HANCnLhG)nU52$;)27{s znh5;{x{y70t$Xi-J_NvV#28cACZ01gO&{|9Kmnf^@;X{F%AfZQ*>ZvGsG=$vYapJBoMfU3q ze_hBPd9@^l+L5D`zfg~eEVoUULixpB)HGZpztFCSSJjGglg|eY=AmO=gZisA5%D9q zVkdrMN5iu~ga6|-NR2(v$ho{QC#$ePhg4Zf5Msji*BF5+%a~Q$^X~5I8(Ck7P21tC zuIt^_N{rn~3joytnnhx?9*&w8Dbr*B6p^kiHGc(IXR+K46Zvve%xgRZ z6mbS!cEjcVCu+&+#!1tDQ>~x(0yqi~;C?bDSfNiCTNGzs5t7)r%==cY zm@8X$nQ{K|{^F%62j`#YyMrrRZY7sBWV3CzqkejWTlXaW@u z0NwC^%EO-eH+?;mYmks}68f?*SdqhgfUX9_=>F11V8>h^*yU=Yx@}!cZ3)8z$Jj{7 zLzm=-@ps4iLU(L42N}l{C4I*j%OvN+K`E}`84~N=Z8It^>3g7xA(SLOLnU2$eC>B+ zOBV|$(_IF`nKB^Y`kR`8ZD6<5YLw{zzq{74r)6Yw z;3mRqjL<%mUmdZC$OcI!6G1rR=EDOIIH#F{*S+I=O|kh~c9Bfh0zlgFb^H8{MbN^| z>f!Y5;K}B>rb2p3rjwZak^yOiYhZ>&CV!}N!S z{!a^d+&=euh`aOh+}{p%{fgL5MM9X^aWrMK`+>)*2*9F!87TuQ z8t88t5%_g@AK@aqaxo(V|Ns4AhOLpb;^5H0cMX)t{T}~tod{K_EVY(Hhem#bVbJt1 ztysJbKUU-M;f6`uH^`?bgnf*?P9xEe(%I2W$&-oPZXT z_AnMdP6!|3sU7&v0oi}GJ&2xrWD{m^d=r`brp%edm;!GjKUL3zMiT%mWZjuyQ)ti;g;K`Oc`uz4Bn9*y;QIjz?lk~UBp>5Bxu1B=+IWHJx`%c=H-5MS_?FQN zZ@W+2ghXh!lT!;s8Xo-cq>A@cOe|EQp0cEJ1A2TU9A^Ecq?ZH&c!fVhnRzfGaoEK3 zwyZ&1(R|VHfEtx9F;8A(=84jp^QWu(^>@9_^E-U!5B+X>q!Z2@=bK{j!FGDKLLmKK zgXm@gPek%)r)jLf3tsco2lVjUOx0UOc019u3iONKCq3pTP&Z@QP)$F?*9!zTBFfKv z<&`v(e`ib*vTfH18HA8UOB2|-Vg_W?gb$Pqw7a?8M*oB`A=yM+1d~41OTuNa*G#S- z#sFot+4sC1vb+#eZB8aZkKL05DOs7dZrd({4){*P@=*+-QwlPpwQskm;EhQy_|t3WwF3_JXx<@P?MY5ZzkXUM|My!?w- zy7a@?Rkr#Ui%)YZ2!z&jFbI%k zf&f<{v*bTkP6Y50WzE@soY^gb??`8ZK#E7dei)RoT8jvLh{EBM4=|I{n(GLsQxk+i z4&Q)<2Z!wJ2CyyKGM3w&I7b}H^9c;%5%Ii8;L%eJnq+y)*!aM3K~tG$D^;@jxrRz=&*B?S)CEYZ z8*`}rpB>-zT-^L`uoxPfom%v}A}|)YHFHM5M))m~1=o6w>p}nL0CLcCGVVI`uKjJC zv?*g{(bZx9GUq9${gH{J4thBJPz1{VMo?2w`0)o7pr6B9cy1fy&6*dW4=-|ozd3{% zeECW7J<1K-qtu{+JK9pLA3^%^D~2CYCO< zb8*N(bm(gqLjkL9*eAGIW|^rTt&2%%qCYUf9C`(b8Ai7G)kYSh=S*{oTXu$m%pS8} z=CnIMPWc2@1v*V1AiI#CQRcEQQOCDRG%&G}mw4f>e*wx7GDkX>V-=YnMsj;MFO2Pv z$FTh0ha}KbehW%q7Ya+jZX-NNnGzXpB#eEK<@qnn_+`V;wSPh^Q&8Fh{426}rMJje zB{9uS%_feGp(~Bcak?hGRr4%Zy6tz<#C-puv`IGJ6S0!c%c0=&Bl-E$TofCI^UZ9- zy4%JZgo%E`lj4FS9s7KH_!7dk?sF6D0lX-;H##Dx6Myw<@gv`}xM=X&vv|)BF?Qk) zPsQSm$l4CB*y_>MjBi2~6P2`SMQfH1lxm~9Q9Gzo&9U7yQjih!PxQ`T|J-lL!Un?P zod*ecC|8{zhTZwuB1kOaw*^%77RFtx6OMfs^xrJ{2s(_Li6Oc`O}qqcUMvhkJ{BQ; z@sLR!=xT{g4`FvA*tWnU2{~Y?MffArMTlwkr!=Eqmq z{^|V8&haovKCrba;)zj?g__hY3{VEBX~N2ly*V`-T`p%-Z}#t{qLJ|Z#wj66F zw*~#4WgmZ)b(URRS#R`dHSmksGmWjZ@ZiOi`en*eqYCNYn_W$@4%<+Cjjlzfb<50+H|BUg~Q$vrLx})swAqx7OvW z7ARyk*#d@x1fllE&HZ2!Qu3&N%SRJ+$;&LsTE$llB2M1;dDL|U6qkcPnu%`Fl zJi3qpc}A@)$VdHGhMEWDi0`#kg2Ei0 zla%TGesyA^dy}D9UIA5MSTJ}jzk4@hJ*s`W9?1Y(w-P+UCyRimI17F}WdSVVh|Cq8C~tYc5NVOoof+~94HR=Jf>&fhwwI`SYydpN64GLm7dC`(Zo z+t#rO%OP2(5x_swd1p3594VynhS6ttwdefhzRl;(V`1IZ+&*J&Mc#A&?UwpNnvO0c zrc4*~G>R*Dy+is;*xeI?qgveb44r?t+$#WlsbszP$VJAk@AoWz_d!B4*rd|c^1-B+ z-!_8>;%r0pmrkx=fH(uFkU6>(v2V7!QFC;PpLhD6He1Pc5qo>!GfR{xLDZQUiIJxq)j>6G-1JwdZtHdIoy{~iNmlEAFcGcbWS7q!ZrLtu zIsgeMn*0&!vU+~170G4^+P(pTDa>Cco#|6{h0`m25#ciqg!UtPz zNh#fh6FvoF1$ffLKz5JfTKPF$xW0jfk+pFX4_8VKksw{)q446Q(xRbJP`b^nk-O@; z4`-zHT}NBC-HuCd-w(f@z8AJ zxMt`Z5{N8UE(i`F+*b(g$$^9}tF<;eM!?m*BM0@EM!`O`+B^ zl`h5@rb0@kFs@d9y0V(rFW7+1(f+5Klw}5YavQ5MRhrDjl=WZpqsWbjTyj><>v4xO zz?0#WbhwGwsD*A5t4;{M?VP`Ma53h1Uw7Pj-FZ#Cp{5Ce)c5{q>NIU#Of6(L9{SZO zx{&I4yqF#?_KKp*Ntk7G$0cwwBc4(Wes+ONAN<|kRX)YF9}_L!#ZP(@$&EreNswu<1V2TVsy`uK;A9P<6}j75yZuBJc>#-~%z$RzQsL&1y01v!?YKsGO=wxaZ6i$4&1BEMy`HFOvmIE*)#V!MI~2S>>N$S`d2lsW zom*-*E(T()jWVb-_hJn_Q{NQUVr(Xt`h2*&G?QoH{5RM3A9aqA0OZR#ZfV?CZhy{p z!p#z6f4-vl^cE-aZlhUYtATG%?@W1127Mr&))lzJ-+2kma#iQzFCd;9M zH4AM~0EJPQm$ELz<@?EI(&q)R%FAjK3E(dn-CVq#eV5z6pg`opqQp%gdXZ^Fw8B~n zo!nOXbKPB|+hw8G0jn~+;g0WnRD<|FoK?e&S4;yF%{ZEHSu9~tx!q~8MuUIo%*)YC z_tU??&@Athhy(*DQz-i?3SENF_q-@pXQh4Xd~IssYIvaA<7n+SMS{tD&G;PDLaPSK zi|2O0JihHX+5L+xbXVq2Te+w}uIRF_Ck_f%Xa!SR&)^za5gk#>GCF<2->eZPud~Uj zg|gE1;d8-tA|I&D+dSc`yw6el%KF1V%yWOogUu@|R~PBM#oM#fo%dZ{$6eg%ZAq>T zPjVEsf!!PfiH=U&(u`}XlbOfyGXTcAyqD^k`ZzIcctI8Um23ln|0X#z>;B!`)O_%c-GeaT2=h5Dmq6{@$z! zz(!#{!$^J?R!YE;2w8~kfR=46Tk~D;%L_ao%fDO;hKgC)50ud{X>q?9ouSuZM>(RB z|IEJ$TAUdPDq9}4ZK&VZc#JMpBa^k#gen*wFy&XjmZ!>g2o1C(ql6`AYP_szJh?9L zotw}6T6c)4ALA8Dwiq>ZR(wtS;{GFAbJN;)(Q49O4(`W|X-$fH6Cvtt1d`@etVM?= z{6HpUet4RHMVOz@e8i}^HQ9QfO$C=3kU!YvA-=Qa(Hh}&mYhtR&_k|rk?%23-cywE z)IL7ttNWgQsGijO*M(&jmS*N}$loFv(o;R@bBn{QHlHT}xSPKmZ39oO-8VdxR4`eA z3P<_D$NH{BA}r%KtuQ~^Yzp>ytgd;LHui9z!{#Afe0N6SU9gc=m;<~>Vts}tf4tQ8 zi&OWk0{+)5&;(gxq8V1$d&m@U=NddI{bG)ylS`Jc0AHO}PE2!4s^OCPZJyi^RVfS7 zd=Q1GrYhA>8h1wD17~`@tJyM}I{iSC+_ELvj_}ntTRyI$x0b!zt9uaR1^rT1B)Ynh zFm9l$#&gg5fao0}Nr=1rbn~B75uk-S(tdowRKE;es*jjf>gY$MfQ!&-6poANhOouI z;0z_erR&a7$_5F)+&<4vqqsi;ci?Ais*=8p4WXSsrIC7%`M6FjXINWmt$kJ*+!})A zD)sBz1(#STjGKIIN7Dl{wSc1$w-2pYJd~1mCDQ+(*3*TCVQ1PyWD&4% z4J%z@JK81A+az2#Q7KtA3ZnHCvw0Mz%Uo@H+ujG9DPOa8=O&Hfnx0|R9q<=`2Pd!UqF(&8i zhi`?+F>r%Fa{99OOlhHZE4hCAQ+zt`zujPSt)6girGWIBO?xP0D=k9ZA81EL)dLx1 z)HEZiu?p&MOtlFaU()7`|i(9)c+?f8{|U~bDSkbF=*SR=VPYo6CdVgWh!&*%h^ zFpGm-_@V{y%XYiuG|1$(`XG7N(#$1~_b;&dJ-BQ!{RSlkxW_1FloQx!WDUvaxExLC zF|Mvo&xN^iikLu2CZQod(J3BLcWess{j9GHax{SGz<254E7`QBz?H%a?4Eh3*q+kk zO@sdXTstmb<=_<#sx$0&8(H9$Hj{}5MOysawUB@v;OSBm#5$(UXfchlINi77Vnr@% zBt#!D&2uX=v#K_>fb?A+mH>HcWb181-?AuU%&w{o9o&pf;FC8_eBJdVGwQjK?fZK1Tz)!^Q65%Q($>s`ctq z)+#kEO#!zzVrr5`udhJkWIB6%P(;X9oD^hfY1J?$`wjwNdaX^K49ri57%3x4_$hA* zlJs|psJW*0k(}cq3|2lw1aVO@ugNi2(2=n{ej9O*JTI)rI)bVcsxv$x>zxF@=4QEA zlo_#_TmeLbI;Xl;(Kwe|i(t0*n5H^@ZsUf&hq7&t7X%AWO`WF#H7GLLNp9n1Bk@2*O2p zC{@2a1KZNWbnBGQ%S?@DYSjF-4*Q_;Njnv2QSgisAVKI<0`lsC@9u`=EShpux2XTg ztuRX~61QGG&5D6|w?(Srhs>#casV-JcPE3>t;T_(Y+i&-3YA;^F=UU@qPuqb`rt&z zw~>|Ited;gu*0PO1@*|J$`hp;*gaZ*7mVOij3}kNoA+lr>Q;TDt<%Ub$fx0VoU?pB zh*sESS9K_qZWO|el}=p8N&|ChTR^1<}HEKV60d_Gx{_knZ+lA{JQhMt|9mHy>mcng?s z9lC9Nj-}rUVi z!_!i0SFUXK)J50zdn>`}I=kELrr<7?b#*`@mh7ncSr4_XJH>HgRBG{PlLenDkIa6` zZhtI*KIW%a)`=bY>?ang{m5?-d;5UgC~vZUY`jjzaE)Y!phBehnH4{0J5pJRM4SL! zYqde5NwrU)tpbsk4~yf|hjQsuSrI1hwEq$9V+}!gfFi2n34;NHM4vr|!x@jrry%vl z+W0lMvq?QS8)(_mq5yj4cH`5gBRfpBvBa~|1B%ORzz32uk!M~VS?E2m0wuT|f3oKg z*>T`Xy0A`4QVqQYu?IYfVX{Z51{V5jR*5dV1~wHo-ix$DGx`?}x}T`#=9jp0=8EE1 zkm_;A!M-0AS!I6h_ddMm7#F5nM;Yh%%vL4bAt}OgiY*X?zc2=3;CmO=nDokn}@eT&#|wE(|tZM@+^fcxs|btR_#L5xdE6Dhj=a(1U<;rXBq zu$$nLc)b>c0Ro~9+a0htQ_4Va7R_Zk= z{VuVH!xW#p6fJ5$jRuaR-BtSv&O)*@cz57+dVeC*>)=?|W6#0HXVV8vI6>-l@^;wJ z0DN05fjhSgUInvLJ&*6~GSe=!7zHs6D)&nUU)-lZofwiZM03?O4ASSU#}Uf#e)Q z5I}=H*w)>dIGqwtcVOU0?wH8Ft(>^?;l564B(eJ`%Dn)`b|!|t0FD*dDG7k{C(aC7 zJ2sQM!~au+KNI8fvI?YaJ4-QuoxYq!&ET4^rE!{mC`kw-k%n+Y9t&N$RGm|)p9q>m z7qgJyjFDJxb{NrKo@;v8zuEEZYCOl{yC;1WG?mD)NwJRGNacu^*9+uCFom%1c;43;Mk zX&uSyjBdgJpL;NC_K}>JFQQGV+J58eALETgfG(+0e`P6v~R!T zv8jwMrM|q?_O?3(R)g({UDIg7m0i-D%b)_bPP>U(n?c58LniyiQ=cwNUPVCf`9o~B zvOvls&PdNXwFl5?Nc*cUL1~A7LiI&`jtN2g!N|kn?ELE4-whGZeHPQ7y3 zp|-{EGkyKEoWQpMp#LDa4%V;ip8b=l^nVR=KvB3uByr<;gR&&tjmH4H5Gh@m|5!>k zK|etuuaU6FHi*Q?JG)_kV%l0=S)ewFyv`j)04qjo_ zwquD77ZUM=ikD4`#QWXwuAfTYb(DL_<6E`)`ClhDkng zfT+NdOYbI38h=R#6>kx*;;?5` z8weo$;E_=;y%^~R$*l0r`njNn@ z1-Qwo^&&U#+poW$mD*%Ixajh}oVW8dP2?^R@!xi4VfqY&d05+xAhBeGSZlVt)VEl_ z<+eOWciitppp-$j_8EN+>CGNO1`{L2M@FbkA9{zU79O+8vZ9bOGWPYJx_eEdLF1-> zH_)lt#V{+_54EKy7z`7grCCUR-(|U%`#Snm9A?D%E9Drt0dWBwm9t=beyqGJfqon= zlXlu7ay=#xGPO<>o5!!rEgo(OSKwe9mrNc-AxRJ5s77;bU@B;~i*4JUM54Lw_Sc2w z9qqt1Q;Kfs!VV~yLNiHtPHaS+avr?_%HuAhS)sf-@|{@&hb597bV-FQY}aICDF-Q z?0k*Ao0UVmUWr|>YRgBa6SCZDND3NZ@dHzU?OJ!RgJ|cW03@Ln6A&gJxJQp&m$Pld zn#Wh$p$*iv;3s_Kh8ItlB1xnVzTU#99n~%O^FhN+_8bHERjG)AeTh8<5~cLc1!-S*v@ z7UXdB58Ps$LyRK3V0plKoM%aDdPxd;aY}miTKMoiBdNnvcvQKaR?>?FKI-M&CbPTR ztkwLn1?R|@sC}_<&Jm{RTAZJ>|8dN>SSk}O;sm#BReAypdRTRG%xJNlEsvhHK?=hv zc&$1avbLlxYeNs^Udhhu^Gf)Oq`A1!gk`obP(PfB+uQW;vX3i@k)=2a;%a1-yL+Q+ zT2$auzO%juWQN$%D$9WUZ-C)_ZKDvR&9Bx#-mS>2nRiW-FOl3X=w0y z_Dml|B|JTyj;s*w53Jxe)H7Zc(4hz##fPUR)w*RA5@p{jZqD;6zd7>lYSCNB+REiNr645a(Jgo;z ztD{;U4V5Fsaw-8V90?8opkADim2B~ZCI=QMQ59)I8~ByJlC}BI#!a-vG~*5CFs2B@^lXL#rV&&!|$F(Z(kBHd-M*tl@}!)pgV z^Us&BK*d2Rd%1lHC`T5x%OTlVnF(5kR5ZPev_3)Sn0n73XOd&qKH@NzJjt`Hi+p?6 zV%=49-sxqvz*gbH>{yghe9`rqYya+-gqd;$-RXIHoGVEQOHPiCN{-=pBEUhrc0i9@ zy<*~c!UC55p7y)Ja|!3}W5q7(cH5^7i|23B1OKsnHuxTF{F%HC3u?xA9teS$VfIQe z+o_@d+BSN$vm_*oN@JjRrpnEEC&RO;lat^>8W2Dm~ z%dbIO)bH2zk`ofV)MS0^E{QOq`R~y_RGH*Qr=1-nwtUeY+^vWR0d`4D zY<*@1@|HW>RY|*;A^w_2P_Rv#TP-`S)ugM}{xf)@?M4Bzu;_Xg&#oA&m50wk_1012 zU}SRr+{;#1<779ztb$hI-cjI%IHZwkOWH!l!FHaE5+Pq3?~yh*3Yknc7wqxkAt}&; zA6&qj|7WP8gi*iF>V{n=E@brsFhM2x;>(R{L!L&nU6^%oXM>MbvJ&!rRdMT#mBH{RRq8khX*16#+7mb8tn z>MBaa%3a60;j>)fX(gtMEtm0@-9fyui=$U)TOH|y`jt~z!}XcUYX5s?Qh0>HS&dWs z>Z#E_-@nx0mSPTNId@&@^OKjAJN(}%ctim+9sfGSZaB+BCT^!TXWfXd!|sGxtbe4n zkH>%-T}dI@f-a;6w!WjMtVD_`%(PUzH77j=HLTJ7%*Zc9D5?H{1x1jF_m@hMTiKl1 zKjE%ivBqVIz2Yjtgv?KysnF#O6juI2W+An>+Y;bmQ&t?MxoRYYPMjjjz4RC^7xsopZ5@0Q;V ztaw!$#=Z6)9Afxf_7ZeA1RUlvw2++h3VOKcCyRUTfh)Wust63Bx6+1gHJ-DC?Hj~P z_jj)i-pcW_f_Jlh*K_XH?$-|8wvxwNlm$MZSrWyNCuSc}pE@Vre9;K8=h5PO`*Axu zWy?}7u2&if=$iLrpP6$idE+W;?R&bXr}~mGG50?^Xc9?i)4{SL+e-{=*k4~FSa)ps zt;Dom!fVn%o1g0(n7poz6Wq=I{QVnNWZCs?9p!2TGo~Lv@kzF^^O`hvfC+@ZX?_wF zc#>z(wLSV)#jrwR=&sUCZFKxxZ|OFdYd~FGO#oZUN4Hd~gsOM8q`~3Tingq*NO}G| z&YH1*#qP#*rpVVfkN$5%aHN9a+AwO#zOdB-*|_Rr$Rc2g_kf!woJC!4m#*)AW^%ub z`NLF*FpHzXL6@`d8XPc?n)HKU8hkYWx0kEv619>v&)}#x)ixfhYTTp{JZNhyZ;y{O@EsVA#(0H6-f3EzX9?G%;{uW2;JSH38>W9bD7T8#`Dbuu@>4MhI|a z!zzA;wfGfINJVTDOO9_g*5}ZhPFPxHW}B{d9~u7OS65}CFLSdzBYOTAy7@cKZWmj@hV$m@!{fbGikrD&Bc4l2{y{b@zo^IhTFiMDD^8yH`fZezjeqvWaN2@9(sAKa?18YI z^hRgZeZJbc42&97i#edDY4#OP7ksk%&6Y>VBg*7VOwaA3SU?t$*aZ6FpL61VT+p`<3?Uo=6!3P9ciYpPs6vl;vuN509*{sLDbc>$ham zkz7Mg!rGtVW(3JB&LLUe}7RHgxdWK}kFyLlD{0kpDz5s)ks(On%R&sUaVi z)~7L95HP}(dGL~G8&)fCkK7XFi%DRHfL#=*cf+LqZ4FUbC zyQoB|GKm;Kn-9+nJY^))xJN~xH{scngjX`-aoHQ*gl8x!DY3@%m{WN5nBp^(G7$4{ zYw$H!R+jRiexc)$u&-s-Xn88Mg&#iEHu)`6?R*$vGA{5ux`dF^cF}~JfoTXiTA1L<~d2|IGc9&JcrE^wF>WyH`#a&_7zEod`-l=apB~O&xdb-yRLQtevYHdO-@)(RFiivKI(QrNWEC0IWDf3s?|%={-K zqntcM_vuzZub(qH9jW=&lkBt|(MZDQM@n#>xBrZb7f4w@ID4bkWlhz}1uxE4P*qbv zG_qVA?o`M@G$H(svO}^vJ&7?>%9QCIrkq({l)S6_{d-Z1etZ+W#61>@)hMy$x%Tz1 zX->BR`RLk}3+Hdme>hiBczsTzy7UL})PdXou6W~7sQorg5x$0$yT!eMsk}P$ZG!EV z{t+JbJCp+^=O@Fua~ieTgQzPP?E?JIU=waH96Yg4q3_Gk;|Zpg6GN8Lqv*`Lh%DfM zmFS7CL}@sW3%Ml3DV@Yc)B+z4SJaJP$L;G!C+_0gvfCQ#msK85BmJ#O;B|X?+D=0U z>FIm5KdG!Iv3#53Lvc#`>zjvVZMExjyQUl3NNz?V|XQ6jCZvB!eXwMF7W6!Qse5-|0Q?>hbhvgILQ8rr^^nwq{W*o9bc zP4-fYgtZ@d$_el}jx6W%i6SRH;(tr9c#;yG2LZw_)9YD^3!@co$*Lh8)muZ2-Iu^Q z(Eh;j)JLfp@F)&m6ccYcP9;>zJs~dNt1L6fRv@;bOgV-Np^69)u zsZmz3By5T5g70cxBZg7e_6jX!tTm@_*V%1kD_kianrc+KWyx&&jv1ZS|EC3{%XrWD z=Kk2Dfmq`aZJVGl|C*Kszis{D2-2&4fqmM9DpNSQE#xD=7<#-P6y!{V|c> zBpu*})RhPN4&sKJuwxb!prPogRxiA;j!8YRvNwubv*_q{9k~7 zq|bOyRu1LE_*Y^vtn%+SL}<@%n-{zXcmCbgEAoX`fmp)WG@B1ZI zX6p4;80vPZ64;jP-jx6e$ByeBK3y><<_&>h z-8{&x<8^j+euh4jMIrHO?!UP5ejkRp9i~BTI$J=X`a!)Xg{kxDn6N%*wsEuYmi6r& zgG#hmr|fW?L8$wmzTF<`wdtvXBnW0hjAfIdb!abSGF`hn;cnd-*k;JLUqgFbh)OgP zhxp;t^SJx=x)Ye#ZE_w34p84^L*htvt)2-o_8T}Scu(<8p=kYqz4)dYKU3S)PdQGN zg^$oP;in^$r!!S$l!ykZV&_aKJtR0t#G$Lp=}j-I2LnS_jQs3LqWe#=UdcP!^c`-w zgTQSre`iPBF?+H<=+?lSYof}y0OL&m32>;2^6s6Qiub-MB0a~<)Fehdccg?ii7oJrfeY~`@H zpJFemv@`><%pk#fJ0asF5Z(kGym)2{7TcgVqgaYJsgc%%;=C7%CEK_41s!h37TciQ8mI&mIt${&t z$s-OR&!!aiH9|&(1~(1@*$V4#$t}Xi&sbgE3!6o3$&_`5bmNtAhH_}o~nsMe1QK1S7`@w-5~OgQCrci%Zv z5sY+qzl*X~<8g$1=U8uIy>yIhV6wK+3gs1FG|7LG^1W^S!v;FzF=OT24j_By+)Bqh zn>VAfd?2n3f)YR-6}C+y0R(eDiMVyGt>fy~vv$ihmzdA#V7D{>&t>3{2$W?btMCOS38n}hdh3wvh5Ow<4VnoUdv5&|8|w5jB#7{a|z0ejF}q$?UWswq^LO- zLISwi7mqFyH!s;|3g=nL7EkHn5mXFpPqMo7wWY8HXK(y`?gKZM8%;aI87GprKr(5< zNgZv;M&j+;YV~x{{h!mA+_jZ;>*eQ2^;j+eoxow`k4wVb66;UNH5qXUszu3vUNS|0 z6U`i1wO;E;0`j~=x>)-+U6tEu??fNXFn9}kugC&k99KP)k0+msANl(?LpN4qr};jy zefof-egW#mP!?19RwsfGi+ICQj zzIJQuAE(cT81Il6y)eLvUx`u(v#w*9s1dGB$b`H?&hbu58N@zg3mqivmZ*-& zjE68M9v85dqp#2-Ft*P!^|JCX|Hfor5rEo|zv%3+P&N7mr8}1;|6AZ6`|Q662W}o~ zy0?uQ%4(cjLEKmBJT?g|WhCLt=llP=d#n9^_Gw@lg7H*u3O1ZG%MflUTAB0rm>FX? zETW&<`}~4V^<^d6YX%|)LOC)vra~F(!fboB&{dEx-CL+~A9FejrkgZTFh~`XiSQL5 zmk@xPt<8?*f`i9CzPEO9e%tD~;s&d^zdLH}ZM_m)IeWmnTE4o@^r&0jK3cgss<~RQ zs%V`R+AsZ1Au9daeK4F<>^nz&>ujGO-_mQ0@C46DK~UtVhqy=>$te)nmU(PU!-z={ zi(yiAA1(;$YyVsbeLq)jPMlK}z#07;4q4Z{(Ci-hbJlrv$-}+y;BVSW{38NP(kLX! zmri|9skB>qN`6v^t%~DY3=8c`nlPVnE4)rDD>n#R4N;Ys$07p4ZW#6<^IA;>=8F?s^aY2;nd$>;htJ3Q;7eEiR)}hn=$G;$${>Ujz#l%f!H3?*sk(inW-R{t@(1q!eg|9cpFEG zm7w-ZsSDeX3sCS8wfi4BTHsofWtj1iBG?=$R&+Tx~ zcRQ)=9PG0juo&gLuMN5BgD&64fcb;dL~oB6DZQ^6TJL<3HfI?(J&?PBGqIb4eqT=C zTdPjPJAPMXy=~QLy6-@Y1&Tt=_GiD(`I}2*+J<>9=Vy;b(ijVaW_{ed)QYVZb!7W=&dho+ zBTdv54H8x1%e-6Si!%Grq3X8d_*=?g#rFH%6J=rTzX7U zxkBX`&O%n#?O(>VGj_vVp@QwhlK*ax$_G1WsvahmNTEte{P@ek*X5j2Hi{szz)~Mv zYf^0Cw>ST2O;)H!+lUIkH7XkzYHVgGw%8NUYOc6Q4)paMsay%wZ=`&g+6Ns6opUUu z$jg7z)c%r~3Cp%rf|>e>80R(ql+6wDc#XdQ92)zeY7q(_OQZ!p0;(XY${*1i>{hP# z{zP~?66ksy4A3g*HX%0=!OOg1?Rfmoj7vVdD*EoHD*87=`nN^0QTpCzQeZ=h;XgHu zKc7_EFAo`?yeA2KcV;dCqrUg^B%-H*Z#?d9twzZDmYTe7_VNbp+^=IAjwZe@`CN<) zTM7HZhDjJBG*S(x)~L= zg)5et-5-u3tQu@vLFg1OPI31hg*^pIv&Z)3Y3uG3&*}{0UJbhBZ)dMeRm|3mb-I}$ zV+EpQ_;Do{4^C@-EDj}}d?8@AMHvR|F()S*c80y%& z?_cI|S#D?w4;fx*LG`GLIu>vn?x$b#b3O}~kJQ-0l>I23&5CV0yT$QaJcr+M(CHFS zxKM5JCEx}vcpwE8fUvBjy~vSBOw^l>}B)>aeIy$N?d9@eRgLweC{>c zZa1FRb43&m*2z(MgU9A5TFU{W<)OiAvfr1{+v`R{&n?SjrscATbCP0<6kL-tiD0!` zxFNrW4}t9hPVVO0&AeTn64L49 zq`d~AQ`>``gh2(LRhv<->kI|o>x`)O<6-ebu9cLEr?ZNdlT%Kw!wrb<&EzP7fJr|0 z(Q=db-AtWs@0j*1*Gjq0xenI*YD221ETicZHOY4K*PrO!jdl(q{>KH>0`L}?E!fjc zP1_g;TwHflr?9X#ML1HMwrcdaps-&tmAh)XQj$@jAIUhm0?{a_T3$3jvA5=|_UtPOR@8lkkjeqzX% zO%N2H-SwrZOYQEU2L$NR3st-K)6exBYl-R}Yv#C*0(3SuB-*{P%qzY8BS{-Z@Y_Y@ zz{>U3k)|a>{0-C)G7?tF15;~wgv zY$;Nx{`^~JpGhBAtd!lqo1v$pOb@JvI(2vB{4y7|`hoIHrR9jAnK+{wuz#V|*%Zw7 zYw2iwE67?H38)uJc`5d?Edyipq<_cXTt;jwJbETL><)A# zRfu{cvKTpa-Mzs4mTT$zZ?cnocAHQyRG_i%<4~Sd`NxMWu;^I~IHU0uC4LIC{E_>; z_b5vFT3$J$0NX9OubH*Et?#-$z8PJg?Hj)7V+v&Go zES!ODTZbC8k@}b#;DYp_R3{}Qez(9Jxskx+v{YuX88lPXdMOian{Q+He#bM@1GV(z zb{4$yFa>UTn4sNo&Jt+5NB)sACaE}$)89;M*w^uwr42U%*YAh%E%teBCkVmSMoQ?1 z466u*pLYlwsJtJcjib7Lb9d;yVWnc%naw?z^-%nVN%QUkRu45DsbQ-tE3!E$1*xo; z3iu1{FMszUP314ctDge9t@!^usUqTJ0Y6N8C<9@Iz_pgQ)1=L80S=r#p$x9#Rnu|$ zvqM>14)~G$k>c^conK8%zY>-R7Ep1%zHl0U1(Y@Mo>vgu(DYYa4nKa5Uf8wnTl>1B zmQ&C8PxYG6RZOKF=R1cFhiUkwYff33Jp=<1!IKhA)Ii4zaMA@)SY$Du*}I~-@Z*%_ zzk;BA&+Ag-_Q;1H|F&cNX%C!3cSFHN`wJ~~Q!@t&?;;~I|#t`e2cKaIp1=qgg8Gc)sb zFLYB*KG0L^GtueTmT3l|cOX$bO0hng^J+hH?eS)O=XH^opy{Q#>%6|qas&m{dOvd} zDihF_nof}0lhS_9%D;##$wN}XJ5ge^M1z3={Aqb5bV#a+VZdu4M~%yND6{LhVVlK(%t!K>hbcE9Czg{ z?gj9aNQ}!(^ulhGvSaN|jQjvSscI*KILCpBQh8db?xn8a2)eQOO)GSPkM!s1Phgok zprY8*pCZl4{#w%0ar;+$AV9MdrwVY!*fvrlH{LBhzXoL(fRdGe}mo7Cuc3qgf6R zbw#swmF|qkPqlTli7$*8fV8>`Y&k4P^vp%LiS1W-jTQg&x0!HlZE@P~?y;xfJZxib zx*z+XQ7-CmvsS>+Y_b<+x_43nX@A_?F85uNdJ@!ay59u*=%UJ0H>!2JAJk9jez$Ra z`%B*mx#DH!vrCe>=uRkldLY|=!iSYjFfPu>fzyoa&LI%#IDNm@rn?=PxI4i+^}NFCa)Cp8 z4<-tJFl%>QucID}n26Z*x*9o3ONA%#&7%5r6^J(b?YP0I?$$l#VA_yvc?5$%s+%L* zX#QuLovU+bm`w#+P59&y?`-{T_a-+1IrWkgCRLDtr1n0Ww;BAv^+9*2gD4Xeb2ZzR z{Y6hD6hFz|R~dinuU$!|ouj?|SihRj$4FXpm*0@=_dM#1?grjb+?@=Vcs)fYt*tu- za@PdCzv4&#FldpakQq4aXKp%wuWXBr0x7wzz%0Xh<2)~G>Y+@!hCHF9c8 ze?ypCS=S&jV4&guz#xstr)vBf$5-GFl{=fAzi~w5_HXr6%68-!eb0i%VQ5BaH&AF~ z@6e0dX#bqSHX1=tsG@|g%!b2>&%Cy%`AaE?e@@?8CJaPjv#rKbAZ|uT@}T^z{#lJg0CjD08WSE7s8^gXeTaO z0C^(3k?@c|icCi5o$JCH^X(&G+xE)@;R^4-iVb9ffNtCE6e1WR`h37}n}4PGt`nBo zdRb-WOGedxn<%w{6ggf9bn!YlOrpAYV^%OY8As)|*zbGozv6OtJG|{{NiunQFZR$` zW+iYSN0sw0p(Lv1aIeeG^PG99^?^kMDZ13NVb_%>OORsE>r}8s(Re##tl)c|fkJ%n zQLov>ijUm#Bp%z-+MM@OB#@`;8vVNh2=rpfstqFSu&zojf8Xk~KP?O$B1aYL!^CCU$75&Y>vO+9()2=t!*2GA#CxCc+WY~ zZIS}d^)~OBDcqidG{ftcc&M`aA6hCk)sS%}Z38b+>pvXdRS?&mjCWt zKQ5#-Z9`$c>0}&bL*xhb9^7f&{IA3+p>Cs9fSTzy>mX{%U}7lI+4d}7wg*RYzN^Bg zOn>998)h{g_TyJV?c&Q=(*?Mr3N#l5f9u@;_1+NTRB~Z2DZ0N;19!RRH4Cr^`!U~0 z;W~v+k&b^e5?IG4pyf0HK)FLU=3>Fd#bg5UHq(%GLC`y-?U>^-USd18WaMm!AgKG2 z_3ZB?jDso3qyr+WK>og^xuW)bJqS zje9}ld5=z=X4lg~2&19I9^Q2t00N^yksj8_@>hk7VR>QfqHiUF^~FeBG?@b(vFWGc zUoOBLaG6;UC*3~z>2rEz-<`9=oqdZI>9S1e{UpX=?Y9rm z&4+$dodKm-C*29!?d?_KG}whTOFPtA?0b?X#3krfAOZZ4%6ZfT^J%TRQ{%m6hIraJ z*{7qSmt4^qS&Y2D)XPK{t4wO2EP*Plur4lpytZ1pBDdF^qeWO>YFMWGrC09ATt<;Vuxs=sy>sw2U|5xORxDQY-N>+<2Lvb;EuE$IDG3 zV!n4ZyFp;-1s#HI&2M)(SG=8Hcx3X2&|dcpZC$atvZ;a1^j?b2uC+BRO97 zDH>VgX_x-_K-|_`JohovdZv!SSVI{2ZEH}6@RVLX@VyaWODRz-z{W(TT2? zr?19~|5s_A@5ldH|@hbdUbdB+502b=O|!>ckE4&>)s{6kL)XippL zver9^v~>&|&=$5}kN9H2mI?&cm>X2viCecSQfObehh$<>rvKhxW+C1H6=Qf=jw)L? z*}LT{k9Nc$9i;IiN1S*&Eeb~oRu%_?9awEQ_<}TjgKG{u?su;etED2ZJyU7)LUun< z!MFujDL8xe4|>$%fI*|bX7)cPopsUQw$SfXa^N2^OmVMUHQ>oNbZZb8oBp}u*k60*B9BA2x~`}e_JAk{N{`)_Rr zt23W#mt%KzKq>ZU*A3CChFu$SuS^4y;of|E^5y~#1GAPx6E?M-@me5H?EF)(@kal?9{dzpad+#Rw|sI$@R-l( zy|w*#L-KgZQL~FeePh~`0Qvo!qxumyViHHuXMz^Hb6`;+Z|>W(J%ztTY#3zbE4pzvs<0(T?4r^ZswUQ zAlcb7r`}GVm#7q@3Pm;}N4foEVyEtqWMYkomm{bQ`&YOnbA3?QI{3?LFF;k65URLndD$}JnNQ^#D)BGO4 z#>F|^8*TYtCC;(++mPA6=e6!KT=Po$2bP|$r5U#owVtQ(ofcyDj&_fX z3-RF_nX%^{0N&*gS?t53wKld3D%T!mH{{0qMvayuctAe&VGxMpZ41D>P#b&*ERZ0F znc}NwyLb1UnVR=|-PKuvZFQgyj@yXf3e=U%|EH>ez9*TUN4#!7KO4=szbf&)G2;+% zMeGu^ZLqhmwKB>_lqlqRkrA|CRDtg=?QZh*@4Ta)CT7L%cB3Bd#qL=d16OXn+m9)Z zpH6a~Hl%D@Hky1ySG?BhNPLhuqYqb*xQ!pm?Phe^Zf#CyJ&P!|&}rkwz0Ja?VBRKQ z&TN2@b^D-+JCfEhs;X_CA!79ei@~zr=iPSd4lv8n_>T7d?1^FOdv|VW=91;O@jnqY zj9<&_YB+}m_P&)aMVAMV9e(`fxh(7Xf{O5l3+XTgiu~kWsa>$@eRNyyjr*g4>NWQM z?^{+P7lYvr?yhz+IYCgYDhlhd#wUAQD4Ts7=}@AGtB!O7!hp55BTB8#iJ_+Jg_ho# z{@A2(6cz>(W&T59Ykk(!0utKD+6sjJTL_7zIBAyGH ziolS@H)txNkmk&@kX3_jHNvziWuW}{8Xt<_yKP_J3$vcqNN3ml$4;g>a=&gJjfvBR z8c0fEBv$y5#89Q8mbI$}dmA7I9@3WhOaQT}cq|U-`G=e<%YYcoEEwVA&zr%_etpEi zh-r(;*brryLWA4Q*Z8dt!#eK_Ig?`E9Mqt3(K-a9O5Abg+YoddvHA?w0@xiSwllNO z*)vbo70A^_+D^?yd~4SpKLB{5klYrk%8<4Pm=PO%UTp8{?UG*1*ropKOTmm^Zgsfp zO|osh%!>;~4I15u-~j-*8CF0m7;hqw~Xj~4im(1s(urzwrhr|WI~>+6~duPyXq z^*jbf6}I!E!`Y*y7T3G23vGc4g=+UWqS7t94DV3(NLmko6EJv8&uG3C_aVRaQQ^eC z0%9(3{DNSZH$>E`!7%7UiA7mGOtMLDSrPxkh}lZxtn4Vcqw!Gi$=s^3#O#)4)J;{Q zcIW4YZL{ek`S&*oMDO38@D~OMq=;GxnhqST)YkcT-}x;Bk;Ay5b}!Zdar{(LlUHu? zp&8jZv8!EQBECSJ)2lPj&0f@q8yxvgESZA|1zPA+do z_vLH-2Z9fWwA(&Rx7Xdb+|~W?Ihd`|-$0%Xc2t>s&p-<-H^D052%YnE(!2iE-U#x3 z4mMTOM(rylkgoo{&VIf0M?%^tOAut~KGeaT2Lu9L(ca62Q~~rd9qp;NR|}WlRB;V= zXRSKe<8+MJWXzzNx@V%3{ap3t=$G10&pvdZFXpFq{*ZZ%%5LNbTGv~msh0dJB|*lh z94zB~Iw%a~V?eQiIhW=A(9hhnk|R)V6l3JM5*V%Rj7sS^@we`W(r_~%*%bSrF-8LR z^6mmHoCAhCy95`R{Kt}HDh!N&EANf3h#0c0r~Qz%)2GoQL(#|IE9wW zgE0NOKb#+*RP<38tG!#`So5hd)aBoq*WJkQKI0R-`J(fWa4z=zCXoWLdJc7seT+&U zcIo!JX+h=p_3zcot7U#>>^^YtNLPPnXQs0GjZMcXhBI#s^=OBvOHXL#q_d9ks6GbKpOe_E)KSJr{^RrVJ{e;86@n<% z>5GrSjk)07F~RoP{#!Lz^HsL+t%iX3=B<7UfRZY}J`p=)0SI(}e-i{T42ngpJ}0Rw z7xIm|2&rK|A!$FU!5K8V;Rnuy;Y+ay(K#Pj-*MaZ2P$fLTYd|Hhak|rLX#u;F<`MN z&Eck;+}%p*YAP9T{!hylWfn!xNZsl2-!X(!EPW3FSnL1#>lvuJY||$}v+YO;7b}~t z$x7d;yo*A~xfpF;qAnt45v!km+$`;3BGS3lPhOy)m7l}W_4D@T1i;URN+#hx(dwo* z^FGPHd-erE#aF+2rp`e4`K#jNSB`Ppt0(v5y7>5EA&GL2?_g_fSbXm=aMBM4VS*sc zaY*O9s6&I~f|+qGbx$UY>}iCwdHm+o_r6DAeNHjtRGw_qcNO8bMn2y|h}Y2#M6sSiuL*I@|6w@k>DDYy<{z-zM?dGke(+aFW~9pT zt``TqtzlU&0f`DBP_bdt^Z%_<9>F!^M0%R+Pm9)Srhj-?05^j2MahWU-zxWq#;7_LrFNYm>Feox$KZAYCXZob5 z&X2n@d-%1aDu(F3N^pa5iyp!YLQJsh+Al;Qt}yM|L`upQ;$WlcRA^|yjrbpm0(s0} z;-~N0{QIn0HqcVT8!@#n#U!rf`p*85%3)*GF{D2(+||O zM|r8kK_@!PZpP#9W6e5BOp?K9Ya(iumLDNKh$c|A?GI45EZjB;nn1gACha594G1AO8)E$2onEOOmJl{#HBR6)E|kM-AUw zM%7SkHLt6qGGPJzInx=p!yi~-T8>>`uQKgwfC|6VvHn9edDWXe8~@a@m>p@99IfaS zYEEZ(M;yk*q8Hbo3tVlvdQ)8B%_gApmpYLz8%qnvmjf1#IP_U~W=t}~f7+(`3fIKT zm`<|xq36zZ$Gk_-%Z7cvR}R1wt)<;hv$99ve5Dz>=|hL_+z-ZqWIyNZ2*if5zW4Dg=Ts}A!pSqdx9$6- zg?Kf$y&UQa3a0{;)QRw-YbwY!3tj#9S!1+0?v#Gl`0lld57H~QBW6Wl^;Cvf44?B33xei*bRf?_)& z?qx*q2=kApYL$$SG?C(7FT3yyjNYLb+;CxeW2>SWdOy^HW(DFYnU~`o)j70Y!h~?`P>Y;6}Rvs53Om9uLpJ)z7 z3}c2;PepIYkzjg03>cFu8jY3T+@(4Ddp_+4b`OZZzsf<7Pu>gjZ-#oMkj_{c51)a^ z48h}|Q;JlV?18c#w!*5Qf0P-H(TwkuZz^&Mqh`HLiXcu0ukyF<;~89Yj^@q>iQgSd zmSy#KC`pC7>o4P-{m$~)&TbrqDz&R&ndM_bc3+&?x|QRRZ!Uy1&a7-NM2|D){MG+( zQ%YtKkP;Zp{OmA%u}8lJxgc9Hc778ljB;1p4xrRS?@hAR0nYpGmAgFOTjQ0-m}AkV zZ56SbQ};F}yM!WKWtGS9+QVBzb6q;>gAYCGCGn_RsP-CjT; zsTbuRLcVr6k2}dK+5NLn?|rl!irMoT@5l6b%^#q4 zHdL%ZUe=Rk zz2ZOE?-W{={oXcGub`beX7;y!J^b{`L9d0ekm?)x)OOcOcD>$eU($7)+zSsvgctNH zBxZR92#jl`VIG)yryn9Yf;cFNPdG=Mtv{GCF$zKcpBD`y|3B~&XO*R*GqhvGi{JCh zh%*t^%aH!YXO)xO=t9Rpito7B7M@U})cJ$M)eVl9hOX_LX*~NQgnf^cX0K5(`JtaBRdh32DyxTN^;Mo+v{_@e%=qp`Xu zpk6boQ}xevhp93u$`HgLv&WDYUshXxOc^TrSjAEH^$b4bQf@ZXib6uM>PPC!EAC7V7ld zJonv~TGK@E`|k|s?RCDch&3sVIE=*+?T0g+*(SEfb_W%956sog@yeZu_mHjCiYoCb zkdFi<{$aQIl$^Hn_LEK15bc9Sr-5Bo{HF(!lU}W|U)(b$DK$v8)3i-8xIJ15fs%$> zo?(hoIrcj;^-&4dn|zVjCt|fs|8tgig0p6Use7HA!}PNfad%RCSN_Rt`BA3%(q2@| zc4%)cAP9iusbBEu#6Yv6!WPSD29a~vMssAJ0FN3ZEeU8*#%)J|ufKY{Vx(Z!Sxba5 z5F}_2H>0@RZEFB)i&p@cYZC4v&aytvi6^o zY)8_vezoj%ZA4SSUYt%kF?FY7X^E10Ea~!pEF{(7vFVL7L!f5K$o@`NW6qAfY!zAi zTDdE;RTO4E`Q-i#&L3}KbSw2z+dA zPH7MAg}jsCFb~=1dI#c#e!l^eR4J3x&r;t(Ds&y@iivsxffCt>aEm|PzoZigY*uL1 z7`EC}y1%bztM{aU_9_r`#SU_qwj6fR_kLdlm?kz8oQ}DaPKXBwqZ0pA$Oo8>t-CmkoH2VS zbuQ@?#qO|wM$D3~5gpDx1aS8j=S+zHk{_?)7Dbl`riw2~T7N5(c3MOhVR}h1m*$ZX z4s9jpMGvX`vWa|WoOK@(bsfU_8p8LRwmiPCWcODIPolBFkI><3Jg^H+hL7jE`oLyM zb&GF_@U!EBu6VIiw*bE`j&wN)<|rD6dbH7p%aVg#wlPdv0PA04 zS+cj}PUBbBg|z6+B|2AksiH6XWte0mEn222uSKbv?&s{Ha&QymAfNk5a^i;}JJ{7~ zDKmRP0GWQb2`6eN@t>!a$JC9jwFSpJw;T_Fy~|Ozi`@?KTF(-EZK8MF-PL!Vv7#pV zo$Aq{;zedtEIfDaO%sS<29Z^a2VqlcLhLtPBF%;$IP!uCs$Gkvxc4tFtugh)NZ8kz zbZa9VgEJogv#9zWFRoC^lCnAgLqIAzFVPp=@YoE0M9t0-!?MUn^JnycYNL&4?4saM zd@&{s&K}SIIG^DRz`LiO z6c4-Evo=SPQX?1Nn{7X8nm-T)&3!jk8u>(ycm zjwSv~Y<1PN1ji7XdMPi#;)3iWAJuS}0nRsc!nCETh;+j!W0rK2LIr!*!5X7j%*Y9y zKO27W(iJKPk^>zy&|Y0rK1*YkW$cK$Ka^yJ`jW;1dv+3pxSsg<%)3tZyj1|Ul?CYo zNrd06150_%8;1$H9ygLu_tPKF}Jt@qv9w;1%@c5UPNIU0audVT(jgYH|v!ct% zpE*gEE}rh=>`!9r<0pH2z9)h zad{QibzUr@hN9e7F1E8Na;DMhCb@S>FRQiQRn{u9yW0>pgibPk3=I6mWR8`P7=-pa zYgF0OZVKEpba!|3fY%V`AUrhr;|zGKZS1wjR#_2!;EOEXlYd90=#8s%eI%}6ap-7Y z*lW)g%jOY_Vr*Hu6s?y<+<+K&TmBK>$jvlf`c_{H%atdY@V>oUxH90p_u|@mI~0b% zJ6z$)6Hq{q_u8KSzp6=3eD#FcK#HaPRkC*}eo+3W^!WNF?WD-3b}A4qhReiS1o3t# z=ia)?+FKclW$CJ@@f`>2c|-4uh4uBnNS_}PD+NfbcV=S z0cDU9JDL5ALmtPF3r{GnFl=}wiyzrsgM!K^LnHA@s0zx(f7^Nzv!teeW;=A`6!Y%OBGx;=&+>dlLqQl2$iw!18LuO!1%Uj~&<|DOu1p5! zEEWME+@Z77G0lD(;m<(QMcd=iq!D{#lWus8&Q)_3gUMgyF#c@!wDtbzJ{gMq6tO{w zQ>s!<02-(K#LMuhvuj@l0fF*ms3^ZhEtG7lBd<@*EDtxI$c59`K zJ&amQ0BlB7p0}K0s9`LC71lfp9|S@7#P+Y@JAz*g9e~u-DC4*}ei)p3f)Wcu$9S}+ zXXP6{{^Y%hGMzHU>T~`7G%nWUUc|=Lw-&#Pf-biR`fwsig{mxIhuDiBFv=XFD$74Q zBL}`NY&CXhl94+@q@E|Aib_{$dYab5n(>o%YI&?-C9j?FapCq#`rYmhL_m$dw$Fvu zQRQ(LK1$l5)W48QK2XIOX&jN=HK+L4-0E@oG1pWAHignVwTq2rzgq%$kA)b9|F0~P zer783DOer!(s`~o%Wft6`}1K)g>Oco2t1&Xz}WVxG($Y6y$@zSOo=s6>HAj$N??vM zYQKu`n1Ds1A-9+6Wtgm>9aej?5_`$v1HZw=Zs$KJhPO0hS3*aDNWnOp1} zo=EW9(kj4(Rnnhdfj}VJyugtDmKP$XYZX!wpg9IV(3!%se?R~4iSmu5m=Ir$eYHaH`QFF!<9MXr(N%K}=bTn`Se ziHRxNAhXq*_)Hnt71HnU4Vi?ziuGjp=muab1X9xri4FgMTL~uuLW|lf*N^gcPRJ#K ztFrE0JTHWr^Gu*-D97Z&21pZ}_tRqVgm&WcJ{~UO4+M^ZBCExx;WY=be|Rx481EF# zQ8qT-W63ywv|K^ZM68rvHq>5bUI0a|_2GYOxT^2xWGnHl40*PrE(M_%qh^wS7(p=@s&8P6w53M5%u$6P7I^OUCaf}A z#8gl!acYz&EkS;SdlX8uU0~kwN)>qD!{vYy8YJxcK*z5(R$F{JNA8dYP{}}(!_qY4> zvjTDImj*$)tffb?d*zK-XoQJBHs4NQUC zq{HKuZnL9b)A(N!^hy8*n3eWU^adzwjd%kd`xx8L%~0M*QAyf~JfxfhlLRuHmzx|5 zV}JsMM(571TllLs^b)>C)Mgp~KMe9e-RWBOwKG@F_?pUvab}h1VraQ!T%f|}VOHE2 z81n=n_gc9MCO6LuGSm@n10A1Hz2(JH1&yY$z+CBPz_^g4<7Gs>PK}9TYQpo`n<)sQ!m+NJlF3Nn{dDI z4drD#mIICciU}Us`w*jKVrG2fhJeE`zg5Ay%!)XZt2=g06S{Sqd~ zigxj;de~~hEQOMbN@eafSP$3t%P3wRM^)2oWEOw!MMmxMKSfCQqsJ%JvECoPK%!mF zKhD#s7dZHeLmf0y9Qy}M!>JOZ;^*yn2|c!|I&IOZ47`t^tH~;aV=<-uRp9isD9UqV zBybK82g{|7JdYk}PVI9BeYq!ojn{Q!z;^G&FjSI^M@0%7?=}aa-_AvRO&U;hBcTQH z;Q0`uTnjDg_-?55CAy|R@HvHXBi$>a*#{qjO7y7aP<*>wkcOAitm_}Wtf@5>#RFqr z{tY~mD+yC8Lm7gtdvs^?P(;vw(vb0uH=EcK5Qsx89{#+y3B`Xe{7s50Q+8#!xQ`db zkkTD|yI)>={h9D1wZR}1r9XnUR~7yFdTa~x%t$ZahHH7ybn1_`Pw67LFoJCl$JuS- zjy~KjQPpTu6cPbZjRm`gr~J!k-`!TrOX!XA{Ifa%-gRH_{${$hk-%@h7rrx0k;bti z>5Z2qd~eTeD>ERSl+a%xVEs~qVs4UDf7Gy?8yJeRtb+v6%|&>AL+2uRiO1&fgpyhS zDSMv$aSCr;gXkxTclRn~s6hyL^5(8hIi8HBAmK^j(&08~1<`a#KMktFzj}NLNTAIe zm^Z?162zT7oEowXmKq9whw-g^;~nvPaPqWp4oI4<34_J}!H@21B%Vjpzf5WeCfZ_X zsj|+oE0L>?QIq zgSXP&YKdQ@-H{1c=105Cl{j=Beu0V5cIci1Vg_(=Ov1OYExbb}|Q z-J6?+D8nS5<6lOpgo<%^7LDI9=Vfvn2PvglA1Q?r_Z`nn6~D}uGQbuD9T2}AJR&<) z4G-zR45T>@S|f)NDadD8LwUwg7=j!-3O<(v7Wd-T9EQe7G9HYtW&UM%7x*|E)c0-M ze=goi+{T!FTQSz+OhctYB^bpBC(y=&Nxgx=6F&IGjM>=c|5)1C3v~a{mb)6uVpNy$ z5Xd+e7WA=`@u_hqZ@4V?FP&??vZyjfrbHq@`1m}P-6>NcA9tD0x)aEMRov4>ikJAYu7_$k*-P{9e9BrVm3(cXM{2G|I@+Pc z)HvEf^FSX#h--|oi7OL#7s+1A6`rs7@!zbgrz|to7mE<%7Ri4ha{(2oXUh|`CK*tL z;S@ZrJ!{~)Vj9KW{Z;SFXS-6vzg;XL(xe#9j$(TMZ!4&dtqBdqPyCv2mI=z-TQA@I z%3mx++eS4)E||zV?u|EK-kSn}Ryg z`=%w{U!2V*+ujFzV42rT*v71A2xZ(G`rXlClUUjo?JsVe$(=WcH+RGA$3~E|!P^I> zyl8qnH`x!;RU)#jGSf-SZLd?_Y!EnkXm|`S4c)pYcJ$02gc?p=k48{v?!`E&O6B~x zc;o&p4xD3z!hL+M;-@H+r_?vpxG;8QC-~cVtEpzXZum#qNo7BDtt-0ENXs1uIU1Pn{8|B0 zeZ$ZDhdV68imyK7+WP(Wpyp|lEOjl?8zKtUqD|)BeEr_#TUTsmEG#51W~*`Zb6VQF z9)CCC^_p-<-HRt?9TKvNcY?IY8OI#NGrU};bBZmp^G8>24c3xr!9EWQ%UeL^bX}G- zsAy=m1<>;*f)x5(ZWlv`mTgb{Q|p=_25f43)nNS4V<4)ZF03@j#W1m7p`*)a!%9~IAwlY?QQ~h9|S4+m4*TsCC*F}m)J(3eaOtJixXakfD3-|$K0=xZxT)kCL zTx+*B8WuqUfk1G&k>DPj#w9oecbDMq4hb6E-7UDg1ef4WS*|IGUKxA&=YL%~JY zq-wtXjxin^qyfiP(kt!@Qn?C_jmOfVfAuE(R6vi&pm1_#T*PSty!V{H?_G_jMjxN zQ~7M41*UPPWs>|dugc0YwipT5T{4XM)Xt-2m^Wf2x^+4h477%}VarMM5zSY@A^u?z zQ+kVTJ+YsQw=wK(|9J3=^XkBu87-`8)+$6XsUE=b3vbeztKR*s)A$w=9u3V+k~~B4xOo z_GDGJTi6s^l0*F-PRY9UX4u%_J(O_P#kuU`g*8Av)`X)%?!>^M4H~s7iGHwj*1hVC z`|eBy@8sG{;@XWfU9T;qUqogAy6bypzHb!zyMw(t2&%F`d=SuuF_1U&FT(CI?>Zn6YzzISPXjhSkL|a|HU(=If9&vrHl&k5Vg7D#-AwQ538b?2 zB!%4K8-Dt=*5T4Z_Q_QRvcU!U5Ujqyi_2D5EStRPzi>qVIE$9wyi8>xc3b10V#PXT zIu7Z-jX~AZOT4b$+n|*$TdV&2g5B@HjPaut`^tXB)MWTw$qXp4RA*gIRCT?u9UPq#p?`L9y=J_-HzT^n~1V&7OI^(90Xhg;QxEs6#zb}Vk zgPr=P0~Ty;&9jfl{XM6o{4&@5M40f?yebjPRFj&w`Wb$?8j9aH*F+{iR{3^i*c0xo z=>;zrUN7ELx139ILJr;nJWDW}GwIe^VO#K?NwQaJBK=bqYL6nzV2ga^?(&-5QJ}v6 zXA3j~F0?=m5glj5dT!{1K7fYrR}*t1n&03?Km6TICLAN0=fU91-l z{4E1De0~yXDD(}ynu%P;S3cA_EJeNu9k)40p*b;{*QNrJ4+2{seA8%E{lf0W1Jp56 zI^2X%>+8CXxn$8ZlB^T2dsi>T(mNQ|fhMv*a(mXv`p?n#&k4z}3#)oH+Xt|l$~9lt ze+?MJEUHr~kN!5Ab%`g5w^dk1zVG{1{GjXLNdmwOAw1wNLk_B)weLN4h&P<%D+~jj z*(f z+!ZNt6?emOXdmGMZ`uZCtm6+mi@F-YdGUjRCgLP?^FMcu&o&Nj=S07C)GL)rrP@ni zn~D?1XS!^=fig~rbKvImk@}2%4I*mNO!&d)!bV{?;LCw%Tw>k8=0f0b$wz;rLcI_U zOcG^VYvZgL%3;DuG)B7Ezh7RS;(!WNr1XY`2x+FxuWyI}T`vJEcr#y#jXOWhFV_`g z3Ep-nY8ZBMe3`|0CH$&>W(Q>+;>z) z813de745}u=^O`xdqG0HY(yher=l#=OD79PNA^d7a`?N;S=nzd>a{>8`-p}n6Ln^nQX@KAsvB${KM)dK%GJps~Y*{A68a8KfGktWlbr?|Zq@M~%R3LHDBVOvP}p zee2DY+09|PPlqK$xybx$*XU0gw3k3-Fgxu-cATf1#rCFaIN>1{xih#QhK?@g`j$57 z%MrYaA&0PG*!fT6k#YU7A(6_rq%_E6VaMshxiL3!9GC>&XrKA~Cu#VkeNpxI0|YCuDs6mv8R{$5mZ%i&?&w3i3ebr_+^ zi2sWPumWHD!fVZk5^kC@cwxcvKe@0`t(2nlD^9ADnVAYZ5)R%Wb7%SO@#doN&isf6 z<;Ijm<_t^c9fjNSV?`!4%|nfc zzxOwbj!&$MA245PaIxeA*u`+hI;%Oruw7c80r*7f+Z!+Nq@Xv-t;HN-*HB_*#&t{J zDfUF06yQZET6)Of+uH0PCJI{OpVAYRyAnhk8O(jC6y8L{4$r)z7aJD(-A?eq$Wd$Z ziI?TmK3$mx6PrWp{9v(8amwHp*=okFM^0SR+h00mf$*FhT_jsb!HjF)uL*v@GEbpT zhp7smSp0cT&vKWjae_~FaTtC!C20^@HRc-H)yIs1b$i)a2z6s;OZVCU?$x3Zx-la| zK*WdgE}LtBl-=rs^>vxG@W;%Wr=eDH1^Q|N9Vn0Ze~d~CqD|cvaaBwaUl>rylXJQe zrgFxx5Qst&xKZP{TZNqXxUi9|r5-Ly>BjZ-<+^qO%`?JzPWQfkj6GpkTV)B9fzmz( zd#TuWvKe>COl>mpe;W^n;I+b9?IAJTU0+>QoYVg29d{I*_z?VChV?s6=Px&<87R@u z>49nsGY!fd8Nk0Clc2I$$49oamUVXapvc@DOD-{)NiQ)3oEK+U8cwgb2zl}_E%Do9 zU6QD%>YVGEiIaiNB^30##;*h}+6LOg+pqDb_ZtswMMZ%qRZ;N#VEC;-(Ve`y`nYb}70infRz9_q$1`~(9CwBKqy@C9oYx#~6 zIeV+4-q^HXrS-|%`+A#h^e%2PYGgiPPR<>iQ8S`R>TN^A3-Khs#Pi$tJi#>Yn2`*0 zvzfNMbdcFSj9agj`3=)+1nocp8y}8bLMY}(p`m1Y68LH(Ep6v)YL}6|$#@)14 zpb+TZ4g~cHz^9%7d@7$$$B@X{^z6HBXtXV`#Ib+7nngWqSs+xz27%6iwQKHYjr{-s zWt#NeZY(e?gQy9F>=1LS@G_^^@El?)LKddmQIU`kSrgD3~*jIrFhM3?lS5TA;tThDBb*?eBK| z)~p+v+?{DezRpi4N+zl+dbN#Vs+|r|lk?N;8z($(nKHqa;LF{7ik|KPY zY|h-~Z)UdQVz3Cp(0>ji-|Fq~RD0vvQLrNxp@Sf6&ranj zGU8s8&`-)L`IFR+fJl{iN}eggFAY}9sc5=%1)&#kBY-y`zEu9TW9J?Tj@7Q$k(C*k zAP3txPwBTns-pblXA5U&sUkWT8B;{=jl6N@DhcGykuJ1&|DJ4y#0JNEqBDuzP+_=x z4rRqJhzVZ`R}QI{CQ!5TNx|;tM3&Q$9bRaXXcfp(Ep8M(%>Qepdl(EMl^<4X;>Pfu zj@DxSB9%=aO7DD9=*V4K`NRUEe>jz=e5EpF0*DXLT|{o*R(W!@c%SVpd10oW4_x12 z$a-CQ_zb}xdtInmR2`@LAXR+9#D`(^IxWB2Px z<^#rSXJnKx@=`?!w5ue}uP;(`9alEPtJ}d=z@@~fvLMRO5b5TPa!JRS?7ZEIgKbjN zaKfkdlRwGbkF3OVKlG8U)Y^y(bzPvpAquFd0y@vo=di_fKN_;VGgq>0^^NYYf^6Wi=_aTH|D64YQ`OKZcZ5k`Y$R8FqGjkfxOtlNps z030;j_%j{W8fy-moh6fFK2c(uZ`mF8JgmUJBd6*KCBslK80h++=o`#}_v~yd zm;kHYuLIpRpbbeu?=$3B!;Ml@qTs$y@|vB-h#vZC?vrB7;N|GG0@UCh2jwnHg_8pG zysWW_!5T+#9_!oN4OCjdWFd!du;4f1R|)rpT=C9on?2PPg6XM1+4V=2m+t-rUhyK@d{=2c)qt^^_nKf_i-w`_b(|S7jEYv>bKVfB9`?4 zLX+;dFDEbxeITTB&gGNCCe5);2sv$<&`3J4n&-6xH15l}(>_Wx+S4Zc){wUT&??YO z-&!Y#Qf|&DMg(aOcItz(NNnAwx77lh5WovG))o!W(dkDS$Vue7l7lWt0oi$Vg3rVl z$@$B`gnXHendvKETm?$-^Ak7VI7k7F%1(HK*}2NJY2-gKviQ%CeOi1}Sq;&QiTRlj zKw`XFSOt=#=8g3uXTE}RYb_vZ&VJo5h-EJq;k%o~pjle%U_EWo72l2LXWsL* zD^~IdC^>4P!lE>CL%e1+9jz?BGh!IZKnF^3WmYaXy@hE^6}%Ev&jt>>1b0@Ld|5tG z6TxJS@SCtn?Y;e^Rm?iN?cOq{G|03mI)t|kPi~#H+4mDx@~ehY`%FQH*`iDR%K_E& z!9ku-k{*7`C-+8H`70LThQ@CXTG%6g!9u7J)!5RCXIhS&5YvxvBL|O_U(FEXa>~ZWtIt$?^Om_mde`g)2h73! z_}YydY&r1z|!1iJOA#jIXRZ(WT?`$XPx-W9CJP);>4U~M~eFBQ4_a#ExC4$c_(cNHT z+nLMDg0A;V)9266Pv`xaU0!Vv(}UxrYcf>M$S?F@kHdTq;+hIHy2ZvF|6|h{T;7Yb zTvZ~EvJ)1yhMaxXKR2E>A~spuIZI+&3aexEr+q4~2lQ9Y49q#_|AZZO=0@_m3svwu zQ8;@T9%M3GoV+JMm#|W>D3RWJFcPa$3&F_+Dj;FF9AVKF^ox~2NBC@!EXU(p)2fD9 zA7t5%F01q;vCX+e{)<1rW8L1H#fce)_UsvPPB^>kyxHLFMJn@7W>&-x_`&0ENA{e% zt?qB|9IqZ9CQ@n$)#tgnQ=~k0y`Z;o;%+%3H55{jKr>eZA1Ne7Q=f@PMkmq_+RqKAar^y{?_U>=8X|`aIOB>bhOW z117o)93t<#=oXjLmm{E(t-hxETqAe`OBKpb@7stTHD6EHZFD_fEE=OiZ;w?MzGi}! zQp4YsH*JK-_kwQ_BwfB}TG=;@O@)v-Hjs}K*y;r8w4A5#4fzZQ59&(nWmWyegiX<$ zzCbqz?Rgj4Pz0`oFZG|*Axc%SJmw45eHK~#3hBkyBegeh&vUA+@W{n z0fb*VHSJ2cz)-qm*$#e7cH9wWJoSXcf}$bqAYRpx8%Icg_LU2`MgK-24z0^AFofX0 zSb#Zdga+jf!=q?suwSU`R$sWP1d~{IK}6!v`>N{32Wo+ffVlMoqwj6{<&$b}`L9gZ zmZPc!&aBtuxH4frPx;)i@FPTCCy{}EidT;&?rjp+)->j_%f_d$BRXIYX%0@*v6@id zAufd(&C#*U_f5*MD^Jt(f;e>j#%8<7CzK?;oDqEFHUb;y&xJt~$$c+(@;(w&m+q@S z&|c$Bt(~f$j11nsO9mweH*e3V>g-=z5pFLiX79MlY1DK`-wY73O=pH?-~3_5&agoD z0k>IgZTXUu5UEc_j~pYr2jAXQ;cTetw&<>e!$O}Q1z)=}pN6k@Glvd$I_m_Ug6qrE zFZ-ZpF%!5$Ek%g*?LnnwQ1|=ib{&L^`!`JGKFsnBtvQPcP!u2fzHG{p)9~%%QP16-x(c39gbgmw z<05ByJfYRo`qQfGitFDTUCt>}w~OPIMq5$e-DRI8^Xte=?pm(q0uvZk6d9<;z;6Pq z?q41r)v$8&>cwo$p!`yxi?TKop@v;!)N8tH$CC|6igp%-x>4|E(pK;cH*wp?@adm( zd{~nnz`PM#&)#SKeiK45VBAbwEGsXFxDs9u)fD5jYeYXAM_hNl|3Y|Io z#uVOJK8mN1<{s$RD=JCef2*Z|Q)a)>!to_p%n^2taQM_uMSnBlmO)0dKN-Ns@JDn} zcgG2@`|uIJ;xR#yv_c3=#8Y%o^Q7mECY@;45Bnfh>JLLA#5A+YlYmKqQQHa z`(>B^sUL8{y|i$?-GJZhBj7_z!Q`!qd5-Hp+;g1Lk@qT{eX zO-0KW+BvZh&d9AeMi*yKoM!n2AbZwIQkk>8=Nyo+Q(HCud>a|2tvSYtUWrO2Q1(u% zT+tP+HNJ{-Co?xhYhfB`Nz1}$;DiV{zMEGSk@kKFey%&C{5D&dtoX~eZ6J>?8gDt7 z8t_Ne3itHb9zCA?Xz_`|hHoK3sQ{9`8GPy!>&8z_4Q^08Lf#jBs9^gi8x54QJCG}#FPhCS(F_B(M%$V;7gK*KsXu?$P>2T3ii{_qHDwjS(Bt8#_ z*G-X}!LTceGd-$ch|h)kDIP zHB=^Tf4+7Q<^Up~;WHw;u13o;N@@%2;ZznAqJG!5dB8n|m=!P01Sh*r-{8uGRBqjF z|54HwhNRF~`?Gm{qAd`B?4+DB55VYydYlGI@r^Ru$!8QjKEU z{>dj_{^<_VLN2)$O`8qC@?^p!(8-<)WBJNQ0bNJuKc8m#d{XcEq9Z6;(;p-^lf%%E z&10dILnd{ID{<3&kBim89x}D=XLS7@hk#_+ByZ|M*N*UgZ{WpOXzJ=iIZj*ib@&de zwz*|aL5AC69Zp72+eQqWbuIku?b`s(^EJY)$DmvAcQ1>ES9P3_$T2RyL(dGO)F(xr zP(qIb(1{APV;u@@KV9^`X36Y3=UU@3{avIQI>gs<;%Kty6Pi1;Y7=R|0gmOKq>C-= zwfnO%Lt!iq+TqL5AEfMUuERSS@Uc?uk*lnNzoj77{JzYKjLc*d+yWwD~N z^$4KB&8?v5azOsrURS|SWwM$Sn<-*J#uA-_W!}==M~c>@v6y^mjhIkjxx@DIIYPc= z2Cs^6PHtDBd8@-I1u~imietZHGZSK0bU1sSCCxXon{>sMc!i zZ1k)$d(EA+u;(n(g+^pT_ybF^#acITqRX^xfF=j~QAR8N~zGv7y zz*K=6!*o0j>mCk$i1x|*lVPat!oH^TD5_C0wGK?c96mR?PYP5}Ef4`=!)PKx{D42L zRLaFjI!`If!)e|P!(KDa7-X@guezD>%?(%w?iKQoIxND?>ZiuS*0Nk^^A)-zz-y>6XW-A+Z&7wx5}IKRUmCb^knr-H!h34U zZGQgsQ)D4s=98{yq=gmMp9g_93?UmeJHik8ja!W9)MUf=w< zJ-DS?Ak#InqHO zN->-l!imKZpb~JU2>lg7Hgv(|vf@)liNQmNrWe*PU4=LYKw0Yu2=A*v4o^a85A@j? z`OLZA`9jEMKS~Zs(&@^To|h-2KKdX*>6;>*`>^fJHz2>5eYt+Ajdkj?;FrBroa?6S zZnrXMhtJww<>_j*_BD;uKgN71w7kb(J+H;Pt!-zKgnqk-WW>RD!oW^dbPSdmK$S;B zcJ)L*SvD#UI@V5M-=r{y4VtbT9S?uzB9{WfDw`+Dletp&0PDvmMJntROS`7NxKXxh z))kC>rO2$9vWobze8R!oQ}dtK1@5CNqq#SkhR;oD@Sc#H!?}v?M`iw2-ere^78jdz zS6U$E%c)@8kFo0ot5`AU4#jK2TM`9z!I57i)J4A2A-F!Nq(ES`b^ozp`31L{J5AkX z4)IZbK6@7K=jKNK>2pYX?vmmtoiJ}Z%dw(*MovqnfJBCcl7(Jbze{17N_hv($rJM^ zd`%Y8j&WU_)rX~@wJ)MKvJc?``o+hs+e0|nWV3CCH3#H7Lg~@C^5+)A)sz(T^NH?R zD#_D|##G1wa_0qE8_B+)5IuGIk-i#5OLQw(`$YkB(WRz(Zq&=lo`?8^RHU+k#n}`l zRlF~~jKegSceb=M& zgqycVXUo2)G&{auc)zqBzQGw5d7B&{#8@h9JAW_+H>M=Tqwz_T;3rELSz5e83U|2B z1)d2$^`UJ9AcS4TOR<}9D^T#yL*U%tx-Gfwr?AQaH)DRIULAd)i~W{6?O-?z13?g~ z;Jj%b#BFF}kN#%$<=!^5)Vtm!8Kv*RO7Gt8dNux3SC~?^m-d@CZ_@7q>@}?oi11j6 zY>y|#MgiliNH=D@^iS_{?Xm|>i=(D=Bf(}hv9H35qAFN0MyauW)OmartiQ^z4Q38l z@x@$_`aba-ilj1jwg@d!xiseU^zEGqVix48bupj*6p<3h{`PlRnc;-f6^hUOkdD56%N&fdLP>k*vm1ky zLnq?j6E}SQa#OL*%f9>ARMg(|O1CYNKZc|FYTmx{H$J)f_Bln^DeWQ$W+4!0tJ-ut zaYs`(ydYd4OV~!awnzD%i}<=eyTWh|_4htbF-5w1QGR}O1-#Sl!+4^He2WgY)BXR< zf~&K*mjfud#WJ@!AzSK|V6Xv<+H;kGA&ZAD zIM>?KIG?TlpN}Iy(5!x(9S8PkA>T>)Hf^^@7); zZdi8Ja!sbuc6bqpZ9hl2w!r#^>2JYbvX7Crr_oQ*T4=>EW z4C11zG@J6~$l0ZADvRdm$irLCtB@sqwTic8dTN5M3 zFp4;)u!>)$KHxZGg%YV7auB~5VXs<5Y!>QL$Pl)mR|)gWYmHvr3_O-M{iS>jN*MO1|Z^ZpdjDlE;uF@z%>nUCh{Bp zI!3az_@FM1M*PLPk{)2OWrEoy@C?PbRhi0Gyb`q)V@DO9iCJk4a(~VNyLfK5pPBxt{fTKL^3BZlXBXU`_ zy@*-}l`{kS&9VNFLUiMt?Ii`J?%TH0>Nq(_$She*3pyR zG^Mqgq0^F^lQj(!$Ago!t`mYs1pBQ&b(dY0`U{&SW8-V_saxqJ`keiFPzKV)R0r!z z6l;8Z&qUH7qNDjYH@GZyJt(LTWJTspb!BYSxAs5&iv{e_9y@hX$dhziYNdbsWwBc4 zUM-!IGi8|)T!U@9`ZnY(_Pk*_dflmVNlC3NVT&N59hmJ`WY!B`EjsuY;@d+PeG$~& zF;feK`33!GZJCVqeX)is4>lor;guZq3bBKgoOO8r$41Vb+HC8Lht z?b`2id~`#9!E(GCJvwRT@$5M-hJ#(^&oo2281VrG8@94Er`o|6hX-0t`T0(AR!n zMT0&}Lgh~q)K3zY>RYqLMZ2?>3^}$4(v2jf3mPO}d@DKXcu58#R)N%vQ^l+uHr9w- zK6dv08xGjhz#~6;e*Rq>G;`3#JvAwODja#aT?wA(fZ2UIluDDd#;tG}Ylfiyq}#ZA zgF9>f{F@y(B^dUkcW%abw?H}#F!%RcOYduI>FZi)o}G@S%hJkIcKkb)bDBPLDD0C^LS$R?Wrddb&1%2Rj~ ziCo;4PpR(>Yi zrjT*u7qMNXwm*Ugj8IA&kSEPZl6PqrIHqYL6JtOO z&*YNyHMP~-ASzwW_ZrW`DhdzG*UigLKTH3K4^YI+xf3QDp<8dsQL(vgPVY9@Gcdc?k`IbQ!Ym^fcsnR& zDI>=a`G4I$gaT$*nK%IBfbeo~jf9SZtr*fWsb-yOOWiN@zw#P>!?y^Ac^0bzsuj7a z)Ns!ypl_(#JXAz-j%sEDI8pYt!-W0lZ6kp`zdt$`R*xkV?o1XId9UXfpQHiIry<8h z!)$ZGzLm@}!lGuUX@6H~Xz^8(3Cp|+&V-IgeOB@7KNlGxBB)a|U-POy%4Jtvqm|6C z&hx$ZLXB8f{e+g;tHpy1wzo}6wFT~v;q|Z855hP3zs%6$OCo zHKYn;4*x4Dbn-XP29_#=1ZqSlLttEH9btCjlj~<32RwL%)Rtm5^gMr(|j8EXDH)l*OLwD${FWh2cre>aJ=T7)uNL$y8 z+b^h2h0!nB51+PTo;}U+isJj}TEs211pbgf2K$@XE&q9ni`px@fX|r;wtV#2X7f zGQ?>0DfOdM{3F;96i-ec$*yCEDC;C26t6&4U{xErsg?^!(hqg0KPFa+JNQD~Ja%6!0 zf9P`@HE&r5Tb?rdO-k*PHLoAD)N$W+IkyEiqzgS%k^TOH{6?GEumx5Jo>P`R!ezaR% z?UXldkM-V*<|bsTBo?>-lajsLPTHCE1RVcQzyfe)+)}Hq3Gj_To8rtx2RMe6ZZW6X ze*%s#a8Q_Phf#LG)|#m^1OBj%2H^r{^j-a&A#2D6u|k^Fhj{-%pV&q1AI;z1m%xe4 zY)F1|QdalCw zdW0xsWP__NoFzo&r*QRO7d&8U)AM9+t3>Bco1QvW=xbyhQD-DnX!0VC;$K^h=xZL?f$=%E zV!-6BdIOzI!3{>U6~+%>@ClTq+#PM1VWbhY#aQy=u)dCFx3;+YH9uL~hra2gf&o4X z*43c>w{xZ+r7sLvv=amEwpzuT(Hj0oW&_%Q%$gGQ3j!MsYAJO#&ma+d3~TjZ!)L=e zLk<-xjZ!{7Iqr(?4x*5j2)Neh4Xtw#ZBLq3q5WFSN8Ip{yN%B}PyL_x>2Tudk^1RF z=-&RyHfW;r^kDk0K94^LF#?+&@b_@Zi7Ad>FP?uVNwVe*Gz?xI=WxOWl24-v@=iDA zobv-M+_G6zfM#|fW#`XI!2Ie*1m23VNgiM!Sm&n()Ufw8Bs6RdT7TsXw^tH|0*xb` z+1!TVHQ%9TV;5d?-)aXstGET76Ln#!5rWcDrLMOk<^fbT(a*4d+*fM2sm*Pwf~RBu z3G=;!?H|s%{C##|z*Kf6J5-IOo~Kc{O2YZBDrvv!#<= z+wxE_o~ zVS0yM^&MZ_cCPQ2c%>Q@_ShH#BS2R4;S6e9Wf zhEzITM7p38O(Xkk;R&z!nyi?j6Vbn6Ka!P}+&U|^hJixXaQB$Nr#D#u z8wzM)>TL=n?5e+E_VaQygTdRsD4hK+SEg?`5LHmbG~@DLf}ffcw~EV3e?a@l&b8#a zY3$i6)xPFlDh|VbTp>fql&Ma{P4OcIaFx~){p!MS2}2IGR*)7w9^ke{$3DW=_QEmY zgh;kax-n7x$zf*}8EpeFHk$Y!LW7-u75^r&d$qT7C?Ref8#?n4>@kyQ2pmW1zDMOE-u^{?jrV|y37^Blezun9?0?>)CtuLw-&ms+xlw~en@0d0l$ zM+aLuAe7gsLPR!C+k4qcs@nlIg87#b)Y>K+8P!7(a3{jjBv1n3&p-hgJY?cRmUR7S zsoLY^?BN~4ilLv{Q_s)f^pQhF(ryvp<{uyt>h`v1X0-wHGkH}YHj-r$h}>#1bp~u* zD=36hA$-%c+GaW>s0uV`F?nhsuwRO?Ep20RVJemjHZ03DK#eFGXoKmQ3-|AJ$it4a z%pU-=AmX8zjI;?Jx^eVqSQv85URWoQ7jfboww%vL8o%RYGiVj%X>wpCHQ+p~khb*F z`?%fV$Syydtl&czn=5BsDAgEF8gzHV^GmRR0)vtsyNT083X9$Pjx2nDCiARl0X{?l88^_fxEE7Iwk zpR-GzFL!*e*7tXLH!u|>(pn8EbJ=;KQaOKa1@>G-+Xui3SK0!}pS}pOj zIOxtZl7gKIHRE^BYE--bJrFnSZmR<-RCh;3~@JA_T@zayhmf|j@q7lKOIyVmU z+{GGsg>sa!icV^VFLv=a-zN;;553E7m86F2ymkA!qA$nDEu9fr`+QK6nDy)7hl@Vv5O%rFv0hBw)rg}*Yb6P6ALN-#s-8(+%VxUQmNSeN_TjZ?MaZ^4{MGNrpHQ`)z1jz zm7a7JRHoO@yZFU|>`MASZjd^LUJ$ht@aL!DUYfQfAno8XfylBnZMs*wUJ!-EO3M6^ z4=_;v72rM7wgZ~24^MSjiPWZN*q1ar#)c>4C_7kT=;i0#xnMBa1o%bf!}=4ZZ~@ZH za=ls%;2KA=sc|~Z7?YjQ9+hdRIeziWXh>0~PXkPa9kbe_OCJ_X2DI(E0T`@jouO*%K4yMpK<4W%6GdS7WAR$G6v#c%4ZB@5~(pQ&!;%p!wz{_B9ea+$|8; zBxN=4&Ji-cCKd``~vY;{3K;blr$WrL2{_A#3I>V2`QEXt9)LgiJISSG_{uC9o z&tL_`vX>!3TRO-P`Yx@~!Cw6E$nOuXkaWNAg&ZCuvcK@j1H$v+DzPvzXG`yB%nqbsfkJ2XmwhnEEf=4SY!uOS>%dop~0!KQ+VrB|wt~(+`yK&e}o-*k}cxws`MjDwgydmoJ>U z{X>QhmS96v)Yl(p39$)?8pvish?)8y4`qWgizGS4Mlea%fU85rc-#W=wzM`ww@Sm{80D@EfD9aDAwFh(sV`!A_bG*V|E9X z<6Sf8@h+{l0|i<}IkrA%OF>v0o#6FUcr+Z1*+r= zdNT6&jQq)7>uFAMK&;z{cCQymt`DrZda*lT<+=Ei(DDSrkjzcaFxbR}*XfU5u(Q0z zQmnBo#%2q#JvVMei>?wiL#y}!PMqjB1&3gWHCE4 zfouwNT{1qvVg4Uf<2U~Tq6;QL-^PwF&JelgkBsCTPDo{vA1rY18C>Qr+yf_=4UqnK z2LaxeJz_U7L>=8Aac4KAa<4ot+e1u0yJj|JRM9w(>DO3i_9EFiUB?Qj#p;cu^JaPT z20_vxcP(0fXN*gCmHcq0AY_r6rcfsyh;;7#>(lINI3Txk;O@7+yQdB?`g#O^^%S=t z7QDH}I*Tc~q(S8Y-c_Uj6uw+oo1_6YA@#^+YGvKgfxSBZ41;XxxQjU+Cy~Uy~ zt?#H?wX8&XI2Jjfq8;RIeM4VXP*{@*fcX{Iz>&q*uMLrMZK02OL%e9-9NxQn%p(2>H+Nw1>lqjDsPRk1Qe|!ZsMpRShIrJkh0!rd?Q@K5t~4Pf<}`e|236r)ey*j#N#0!<*HZ#o(DUEP|wkr zNA~SCTP!)UdT%p>R(j8j;`)giCE|TaV9^HM7cnhv2t9Nopmg%116eN^tjO_eu%r^Z z$1W^JR(+z!&i^2Yra@5m9)c9GtruePqYVAiWM_Gp8|jLGS-@l?_>c*IFzE}>aOA!r z=nJ$z!=~vH-g?ACItcWg#EVEP#Qp<>KOp1*t*1N|JGOXzek5YA7Yh0NaF}e0(?EUZ$gs%$BW2-T!uy8V z2QLhWuvMk;D)D41s8mHO(*@SsSh8Xi9`NTo(4UF|XG6XibhMitv{3 zDccY&UHt1=p+J5!x`|2?x;0Lw@m|pj;IjPL2EDVA57~^`0@E1M>|!*HDYYR?%!Mbj zAs_^+qS`*go=0NNrw-vz;VZM6F(h$W?0ANROuzAAV2v=$D9OO#4=sZ`LGU-5=#V(Y z9r}ivi|1fF%)aScLlRLGsSOq@TZPYZbH6W}e4-b{guxRFwv+mMJ|5Pna`C1_mqg5o z-QM>%1}}FQzt6)B|B5SR?l+1NNzIMzFgi2%QH3{w5#F`Ru;h;T-!#_=W6L;>&A<)I z;a+1;CY*GbT_5mSmiuwuG<&Ra(Z^jjwuHrc^A9`!9b#Uqx7YUA?8P`up9n9}I56K$ zA@wo$=|x`veW)E6fVYW-ZS?@{J&nOY*qfTh$#w8Hf{@ggg-gZ3(Z&ru?y5x@rDJ_J z>tAklqlStci`ADa&%`@xhy@8i0G>wJkx`99TGt}QBO`!l;PH|<=ZaeWxu>So)*b9z zH^CF17R{+6Pw|3HmNHO@bw|l^>Wftj(e*Pw3Ira@gb?%yH@=X->1-%$aTI8>8m0IN zSO;SqHYRIUGQ@mjodiVUYp;YKlzmrZKKMwh3xad12a++`KA2?jQszfHWWRr<)ubF+ zw681qB8_0GG`dfiO>(jHv)%4PaBTdTZN?$=NQAO>+Q{;DlkqcJv4j%6b1IJd%z*S! zDhNMghwU9ob>gsQwDU8jo5W?xodH#8JZwCO7h%m|WLMAh-C9b`Q!aleK1=nDXcUKI zbpavQ*p@V#t}a*q=qiml>&1c6<8(Ubei-D?)Wy=PFXzRw=#0;>QF}TW}_q zE2jORD{90U-JGI81Y(o-1{j) zfNRoY5$%z1$Em#v>B801>1_?{k0U|Fr#>>_0<)>5^qTD9#t3l%YqviP_5$}rEna5I zgsT^0w5na+{#cNb=4TS5P-D4Bipip-!npsBHRyFH!7mp&L68sc(1idrEupEQFa&f8 zTSfScKzbGRrgmB1%ILu2$9veI0$|GIbS5>%9)EwYFy0ZZ4zo;<=Au-HsKqC3cUF$($&kaKRd> z5x4fZQb4~I(C*-Pg8K{DF>REhSJ6zvh=?#+40(C>QhoA{Uq8F%*^ge?s#nCPfm*%^ zHjpa^#)yV9S@f2AMhQHH_B#Mgr0sl%AOPDjFv4_D!d3*auF>+R15}`3_SE^UFMm%Bh3Z6sfX94?8 z9q6PlPFG4f^SrSX_TO;i`o2PsWe5Nyf?9JtemMyra(ms+YU6y>L+ij9GDQxEQAR$` z)5=5g9?8ps2QFY;ewupnm|Ns0LFe|^$meBC4gSNpP}kll?Z6*kITw4AUX~ia;F-hq z8KopYf+Azsqk_NremlmUOdMgHQ1V2G`x_@^!{vUE!S3nNy4rJIp zTA;qho;_w`KJEZPNPr1(KMnnH9n5_R0S zN%a^b%6Gk-R}%H3)E0F++s5lwim^c<3?yhH-|&x_@^9_fwz;a*X zzw{?TQ9Xql->?e{@#52QQVw4WVMD#u6M%# za5G*eZq*(ejhrWwYgYQdbpfusN`hB&q>nFt_hKEV+`bz@q#nDwDHVcmx>HvYBVXGo z8-x^35TMQM@%S|!0SyV7AEBBp10|csNRp%_q8NMZg=>76FVPJW?HA7ceZRYzKT3w& z(d~suRYI-I9Umh9aj3EphucJYYi1vO{O*;WcZ6TzPXs9<(S0vV%v>X* zYF!b2y3*Lf35~tPU={UnFm?QhLRm_I^G4u1X@Mv1x4`GSX@1URHv5?M(`MK6>f8E5 zw-&gs!781JlWR)N&Ud*UQ!cDWGm=+6pl;LdbgEqIJJzG)&Xd#~QJ{~<(%bK--T^aW zu#4iv7Q4Vv3~rZ$f9&hcTi&|s?xDsRfDJt93W|9bn6nOwW|?C#i#Cd0B9!J22;6Gn zUrGrQTmSMic}GmsE#-4SCt$6RY^)V3n~PJ9oeaHXz6?9y%9{i#S!3%AWpB)a&%laW z)jt*Zw90+H#06024CA&9Cb|N6cQ?$9xQCr0PFLEVfZ(;Fw_W}F+PBs9r{(p#3_n7E z92M+#pgq{NsW_161_F>BLoJ3=L@i7}U>FC2DC2k^gOZ)hLC!hYf)==)7$R?el`sVc z4!;sS_}L|nnHHw4+M~a&`zEMaIK}jxw-S;!eqTdw#FJ~4G{}uG0J{YN!Bute=~80b zoLG6{kHzkeo@&Is$@~m#a~lIBUVrT#=Y5~_pP1jK{jRwEuKzK?WJ?R9M%UW;+dLkO z!jhNgMNoQW9yd!~{Mg)JjErO)ljWw#Q3{~Xmu*tLF}hzt)d^IX#*6m~Ckkz(a}u*t zMLCCtH&#@!h7l)d16nclzEN7{25s`8k1OYbQQ3oP`3?ZSE*f~Y1T3^?r2;DLHff*P z!UtP8&9V+f~nfQpL6q<;+vHsPoDPeKheISJwsMBk~P73OoZ}`k2fjjaoI^+@%s!+5` zKTD2vO<8Rw>oq$c9B_A>(Ca^n?!z9Dqn_)nDDS-J231E-ZK6x8nrZP%-L2T5psf7} z>Y<4S?D{wGfV^OsbDCSF%M!s;Xg)4E+4FJ>B#*6AZXOBwsVRBLjl~YEKc|JSmd>6L z8_LW6fmzB`nP8wTKm*zE&jz!3tRVwvHNBrH6>aAw;MZOm3Og>+>iR+HLs zNT+0#)Ejs0XFkjVcPsTr^Vu)YX4K8s4Q{QVDnj-{r*)T*^A3UE1+RZkV^}$7Q>PKu za*NjzAI;%7^Gj(|WjO{7&)I$qEt6B%^TmE2POtJk$m4MMbglJbByEG1Mmb{GOI2|D zog`P2+APv5xheDQke8=;q)Wx&rl+}%x-wHXtFT$d@tdV&l39WC%LBysw8-yrr^xMe z#q(N0X$IFvV&aM0B)6;y=zWdm&AxZ|AO)hk?DrtbBH!CE5B{u~lBg&gD-b?c64f;qOL5%42?Vt7!$;LaV6fkFSgtaYusu;WVOO6tf^Pb zw+&g(ttX{%$ArG=NRFR`h^8ne5K*sI zo}teW$Np+8QKqnCSMhUw7J8IIl8KB-OC&TrFkYc(IV#!Z{3J|Pumq0mllvfz6GXR< zop3?7HCVmLVKV}{4i-Mj2_x~nc&uN4v3uz{nh^GTc|?p8c%)HpFdY4s`o#C`YZ8w) z!z0)6`LVu*hOZ<(-q>6_@=f;2ALk~@PjhnuCilIH4<3lSbD@O9@cEJGkd$xaz8q|& zi-yt~=xC@XlO{D4hz*H27BdWlOtTET8dP%X@lNgym{CzPC#{sV-m|$SZrWRymK~S-rs$HT)I{k~*al#(v`z`d2GlA<5N5^F!ZRz)J?70hM6 zGWLapDte&WlsRzU$wKVAzV!*}6#fw~*D^QaNFMGY{!T}#;_M!8RFbJ9kZ|fU{|m1x1lzY6Eg5#UUO(PYaOsS?=^R&v zdu8rKn6$i6smRK(KFhaQn8lp=Um@;CS6_Ko-*R{B0HR$19`>oW?G9#Rbot*C9u&f2~&i3`ek0vQ3)gj~Oz)0vS@de?1}Qzlp9;r?A#qH{ltHzQpNHV^@E*PVM$ZTB*P+i3H3Ja9 zOVL2eGfs{>B$9 zGN4fCa^osl&q*lYk)RLRJ}VTqu6P`@=1}l**qGvE!TiW7doGIq_n|RD?ritVl8&4CSN%r2)z_f6 zC_f0`hlDCHhlT4W)LF1D;2V*byT@S~OdS=k?Ioa>h972h{j)d3#lm8qsV|Ox^dY^i zlo4q-PCd+i3r~V!tFJ_^em(%E)~PcLovv&xTcxs0eUy(3xpt^ri4uYMmvq@1K>ZyB zU~|{NL|v5pWG`##N{tEyz`5^}X**2@L$>&Zt_9Ct3hf@`{7$82^wk7u3*R(ki|qBH z5ty9tzI;ctL=RCq7z1VZC-Pc)b#C8pu%c9ja7$x-o-+RX{8hH8f6F443`6%wrPAR$ z;tb(wjXFK(2|DD3UV6BF?@8L`JKmPbq2*0o>cy>FJETni(R)k4g%A@rjMKVQIbY`v zo6!D8XRR9goKrWhOSMvj;5|_ZWlJ+lsNQIOmWG^r7Rk)(>l)_8jSb~SBzle6@GheJ z@NVm7c8~*4=BfM*(FM9NjkX?E)?TAsG!ao9X<0!|>iR7JA-HOMT@t<_ebIm2c)Rqw znQQF00x%YKjj$`HBDxDUm7%s*Lj8D#zYX_Xr(_h)r4KCqhT9E+tUoN~m!}_jlqn+%JNq|5ZfNn9+B4M-#3>Ylf=U<$CnEB>? z><#mGH-35gM(%FV_#gofJ$D3u3)UZDIBuk9DtsoHhO5e?>F^LX=x=a5QJ-@qEy0-x zQjab4)`FP5^;HVIBsXS0@06Hj3&pop`W}pM*?7Znr9Xu(a(;Bc3z6&>zeSKZCrdvZ zUNGh85`eXVHwyCqediMEgjZjTsY@Us+*yGBKxRzwISCHslam4YnTx!s=#RystFoi| zy^Vci&K<2ift|6&fM!-=$i{|qvh0j7c|s`ABn}5Si8Mpc{Z3rzRn}&#V8L~X()UarC><$*$kssO6adVF2^Rz|`t&dFXYXJ9606wNYd_SxCCLg|jBa>BnlYQue^(R&&G zZT@ZG?Ktdh0qlFkzjou(apOjLGIe;>mTL1pL60q(Oz&Wa?ti<}xwd^HPy3Mj+Kl%5 zbe&BF^7|XEgTx5bn1Lw`4-o!Gyfu*h916sXZ>s-e&HLte!`=}Mzq|D-&E4bkdBGoB znDvKjyXS!Q8@m@Xzgs_uR}Es(Br?UBjp;8_v?4Y2?yqzl-UbzhO}gFzWOZM#%$0PCHg+p5{HAz=$y@WMqHp__}+Cz264IP_4>z7`yC&G^_TJ6r; z{Z`Z`Z`BVZDCZ`8USKT4;HnYadYLv`Z_j*o>F0q5Ti`HpzZL@D z^lf4N;T!mAw1dWFbUXc)j{Tu0n_gP()j};MTFdS4ulBaM9m&4f#1))zhrclu2P;C! z7_OvYIu5FF^5u_NA5f`7r#%!Bk}mUK`)G{GK}m_q810+U^L~-$B*N}yB- zo!uu~I?K&kc%Dx80}l?!c@zhFqjt!+={M5yk1{$=@;aWKNZ0RolP;@+)* zI@T6m(gDl4(?NAn`{wBhcWBTymR6ZKs_w_+GG2+KqquYq$so?CE(6@@g{!f>oW%M5 zwBp^2?o)vekq7n&dO;FL&DA=2+GmzO@6x2(5Je+4?bKcj{2)Nq>jLsfB~*D)7bX7Z z;fo?5!-{$$&~%_!FVtEHx76KLk?p^G0cre)*C4-}Z*S>$e+cxH36>xmc<%T(Qp%ds z!)zxi?14Zs)!|gOrCg^vFCCu%9w9*n5 zq9Td6>p*xY7;}qwMUYi#`9iA^#^6NNm>=KV8DL_|eA|2>9-N)dl>TDay}2|%*;eaQ z@YBRAF^=Lg=aw~-*@|jNloX~i)Q8C4ONkU+0yztdQCea-N^?5>CNK|2he&ElRH0)7 z(-TCB+H%X>cD&v+GaY^gdlRq}HUV+;X`lNIJeRzHUy}6s!p5U3ug>OxDrXrEG`dfL z3O~>7x9s+IIpJfyJ(g0TYXcakmd~CsIR72H1rQR^pExZd~=Ti#uTU;j?brs|SzZBKuwCij2U_cg ztC3$itsK3#EEzbZua<5JZer`R^PUFZGok&;UP{)#KS>>(3({MhB8C4{uqmFe(3Q-= zXn-&Kla)cyUo4kcI+auD59EeyMuYB-Nq}AWjPS#&Y=~!00&$9@DJ}$2d^{B1LA8eKlryD+6CBRKaeh5Gn zD)t32R$_!V*F#hHi8<`&3mV?Kl&U;p5WYVP9zT)}QnYWux;et06dJFJO>d759&B>@ zqWDn%8fuo7ZHOW|%*W4w>GTkkS+JG0!z)i2@A^>Yx7-aN6tD2Z>?#+W7Ijc!f3>Mh zCBl7|23iC48<-$ruYtv`=AD z{+;cu5TAT6y~q4!xM2D<`Nlq^SQ2$+or$il z!T(DF;QO+-p*=ZrV#;Ww*Ea@@!fe4(X%NlQ{|&F--zd7TzxFS}5$^kBUQ%Dt-cwfv zg?E2Yp^Z+0rUX}4umOD$tQR!`sZ0lbgKlcYrqvi{%ljX0J!_$>9fK|Ks!RamK!AN@Q9L zyE^~QfQT~A^x_`q?uUYcB`kMwu)hIl1w7Rmn!t!%B1OqE@i>^Og!bs(BVFj1ws?i^ zrDZ!#X+DE4MorJS^b!;KXbix~=(c)To7!8Ji-CA^k2R5K2iwcOYg2`Re)0V{Jt}2y zH9Uw+iM8b0V0~982$K8RgKuSiae9F(jc%*9Gf+|ad#^~({;}AjMb?2t!?zK-VvYl^ zREm9U${)@K?bfllIuIfFtaqzW1l;bO1-%L9+gz+c4fzYV%EHHg<|XXRdxj)5yn&dx z+ZQZx+aLk28ik~`z|VFS;`YBr%`b^2X8p7-<8FC*$Sd%TgC9%L*|H^tH@>8#qc+YI zdP{HAwq6H5guuc<+WovwkD9nyJOe zBhAS1ywo#8qO0*?4$3f5z7wT9HBTy7O?qsRNz7mfFp(PQ(LsWxh_@ROfC=y=Wqugw zACXX$=EaXoI$L1u>%b$%yqD|Lm$A55+IAB28~2-d8@G?tDamrVEtt{WcAR+3?~TE%znj5K3aF>E3LiFxkH4|Yq)P7za~4fd`ZAsoy*T7j|kC-Dv1!^2zg>Jlbp$uUP*>KTdofI zs#`s*{YVSCIB`%_v25g5IAk|qcbLZJKq~D}9YBmZhCOwN-o`r@7yru7j>?hL&ziIS z?m?{;d5igck(CfT4lg4`WXEILfI6W+5a5HA&TNVFb};-&_LB8Z>hb4{1yuRBSgdnu zNq&q{d0J|%dL`^kMmtJ&c*K$uy=5h&SweRG=(NpHD)JlMMle4lCnf1*Er=}tPRzoH zHsI_xe{wDYn<0_&(0JWx4&MPS%FV$5juHRDmOL4O-qsue=_d>lHJu)9x}w``f%Lj^ z5F(%@A_U_0!f}C+1Z+|&kua9)*YB-4nM!hD#{!_M@Imeb#U3oY=UH0KH_v=2&wO05 zqNj=@MX&NhTOHbos9Taq6p({cwX_3^L>PKjFF@w3UU=Z=bFzjuc>3OuZj}_c`&Cs~ zREoXQ&5z2*4cFPLAhGQyM`^Tcj-&?LVJq{Zx@-(xGW zuP9~*nW&!4FT^y}fjMJgtW^m486ZVGjO4%2iR3r;VJwvbZtlEZP1)`v=u!d)dLQyg zU0Fh|)F#1T=;{C~BKRYEWL4uesQ44pWl)ky) z-wz#m351F~ak5Pqe`^;SrTUcmZt#)C!hUmEQ3mI95#nL1s@k1C!%-|Xi{$i67Hdw? zd(s8jv8Fa+<;M!({N4?v`;9jwns8A3DQ2=(-EyRmXQVd)FL=ha<;d3JESm}tZ*CR%;=2b*d==YxPXn|`WCau-gEh)G-VVxlFXdGJ5*+1NHL zVxiQ)W|I!)qFR+x`}D6?yKS!)Zakf$@Z)j7~9a{t^l6T8`F}qqFG+%#TLaK zXP(~Z9#I^Jd_b3emeEZmusWnXS+C{MiRSh1>6o6kUQ&bR*5W=M$$94PvvgA}mF8Ey zv*~)G;X_(I&>YDD#2xD(vD^L3+h3Yc_*XOnDh@uC(jSPCTPt{(4{iB(H>wi70d3)N zZ`qvk(x>wCI|~Tj@xKY}RS`49j_JZE8#bvXd~ld@opoPc%} z2aW&pa4P^GCSmW7-&LHliGVL@`1A_s530m1f%GiJ^(W~WxY-Y}tGjjWl@)nJPWHhL zSZ6`~kSLpNBBo?9!-8`&0P|c7K`mI>N(SJ`n@~KW+ zP_hX19#fGO?@xUE9jEdrqM1N|*eqdDDfBmVDz!9~yc{w5Fo5!5yqb(#K3CL9;)fav zO0Zt--O~9fZLQE0jzGe!C|Pz5S_`_P{p5~nkt%^b5OhG^w$&$gzMk_aB}x<)YdTYn z5k=`(#*U)VJ;n_4p4f<) z03i_nQY*h}$@;Aw+-__LR5$hdz9fbjK|v;s#E$mw!HDoETAAdzBE%_!R>^l2fHZQ| z?&!5WX7z{L3;<_6Onu~`YZwe?Xf5^$ur~$Vdw{N`s*MpB3_IWF)$o`XAhGsf39CV9 zr)pKT;8m4CH3@VGRYlUH9GISo_EtYV&{$>raP>hAdT^^xvy8WhL{LY=X${3Mxc8!( zi}5li(&H?W%-EgaD^uM&m)6>eQ2%MiVAAkVmYsP{gcnwr{nDnDS-w&jk$F>fgpbev z$@(}@!@7KHv>+Q*D2rza1k7SA*n4?U9EH>;ppX7WFgA;9M+`GeexL|mK%O}`+(aX4 z1{Mu~LLFA)FpIgK0_2E9QakJnuja`X2cJc>q!4gj`%X6jnPOEORY3u2&=ev?G5hL( zN`4u!)K^5&_wbjcQ*n7?&<(7jgIz$FigOztWaE=G01anO|2Msu0*QVxY@28_bv(Mq z+if`3fp2sKFVv$6ROZgymj*ch&DptzGaSSmxb}?xSt;YuVTq`n709ap zy8iIDSfkyge*80Ci;~}2dhx=us$UDLW=pkK4_s~dr-m0Sz~VqOkpCJ*1*FLUArM4F zzeJ8hy?azWje#_Uw@D%*NkFn4e5Iy5p#-Ih659(QYC&(}5D*UO=jCZWCM4Qt@CC18 zI*IeW&ro9zw;^CIL~9|dfN}X$tQFWoMARjFAxjYhq+H&vacFo|0(p#0tk~ehcE&KF ztm6Z0rwq3sr$@|*7Q?~^0Dj*!`=#IbCuUVF7GJaa+U#E;MEV&cr4=(M=X5f~v%|kr zQ?ztz7Rr?5X%9tHXYXovzL}(@;}K$|Q#l1-*t`$c5n{gVYW=v+p^?RsT!fR1*c7q- z2}LeTI?G5NPJ6ixwk0WBl#05cQD)W2Xr|-Pq&l`O?*0 z{&z2+uj0x~=bykkAOy8$l0+bSO1oRTdudPbfEf6~|$w>LmGc9bEU>mwiuo@pR2Fy zAGEamS}uE0>f?({mM;%@Uq&sOw~NT=?${Fk(v~^L3;QNo(6DZer?ipk1~4Ox+y3FOvdYdQT=3ZK zKk1gwRV-ob!Tk=XNY(g+CGz`LSSepxZnqLYwboyJh+kO&prV5oU47_41kX% zgggAseGNHqZxzoR0pY1@2MX)!7MG;h?ts*!v2Tt*zuSzRO}?)mQz*|k8>xDl6dQf* zngQ6f*Dx<*CUnqn_M<$Aw1B^xFp7_6{`XIs6Byp-skY=cHws6Y>o0r$n&Nv_<{U}c ztVrf4DE!plfcP|dsoHP1>aq~57S^V>?t)mzrvRn|K!UqCuMMQaIV;AjriPRixV=Xn zGXh-Vm>EWa3gEs=@!&KPsj>bUSdsL~X>u6aypLveL*edUx_KObFx_C95JPA1%f}@4 zJ2$wpOQ6lunxq3}L18r}DqeiD;ooF~!j)ByQ0V^WWsZ9kA1kU2V@OxbvH=ctZ zFYZoe|2VQyhb6+)gc$$#NJ*j$_%n0u!;C^XE<1O|P=0Q}lztDD;lHbmOhpx5c+!DD z$-Ns#z5Za|rZw?u>4N0EV6a2ubAJ&r6#R0}y zxm_F#p(*4z6!>^fWV6MfJoTosncqT$C6T-QmLpvvYJ**59)iQmttBs1u!m5Kn>DB? z0J>q1Cu~swP!#SSYDLrTZ2SW9Q(6g;dWndVG#*6+XVN*(FrXY@)t?X+bvB-FWFL|s z8$VhJL){uNPJlbnse{Fo1(`qz5av_a@v>zxT_inrX_LsfGp#$J=?}=CoBD0*czI@A zZ-55<*Pg{@E(R6C3?RI3clG=L5yI6<-;J4Iso9Qf#PI6c){*F?-U^{!BIEMH*Q{xDrJud_w7MFe~)-i1^`yv#3xGekn36Jny zZ%|)3vPDJLbsR`rkSlgezj#=z)yu`;tL%)KjovC?KcN$tQ*zP@1LBvONh+)5t0Nny zSh!PIJiR|i#Fg|oYexSH(fNP*v(+}En#QwizR@t&@CqGP_0J!PU$0uA^pxh}H|aL& zc?#nUAN*GmpT5DvLsqV%Ca_*!3z8gX|I4Rs*GU+S-cMkv*o+Mcic%PvJ2#F$jMd+! zX#HqE3Y+pG_-E?%QX?>(p#NQ`s^IZ!l`uSf8~}Mo@QqW2gvER z;pJ$&V&PN{pEhO(QFx{o^0{(c0U;V!w(phH(B6#Le?2lB6D6ays8oOT)GQJ#*y=wF zdSH-G?uGvSb8&A2&4PjTncds@5VK6s^vV{92%h_Z0&0e=ei;NFl+QwCGrlg3W728w zz_YeXotx{c~hp)b=2bToI`}e|$Zo>ij!ADf`aWcezl9skth- zzGb)ttG`Ooh!x(KEx=MciAlku*Ty)qq!*oQU!)}Yh5(fY3LZqpIo{_kUqzyY%RF=H zv)TKE0@3H_S%AvPZgT3r`WSz zBFL+TrH<@#N1nYR?!zejyTOryJOE^hDu(fbj=Ok1pwf(2mQiDIV4?SDamQ==3^ z!V)K-8ZGU-wvYONYo34A_lp>18m*hMJ3znsuh>qBWZ{cFyC$zYoNlgbhWp@gGu3RO zIz(nGzXBrH<%XnoDJ;XkjV0A)g|o_YiK(+VS+fi8`}XQm;*ygXW|ZXeL|>H5*!iSE zM5C(YUM(j4&>NL30j#&K0BC z^W6#;YkfWltdK+rmeH)uA8R{K>sF0O*9vpGsZ^afj+b@1V~~4lt3L)89`gm}bLRIva8M)?>}iYI!dn#SF4_4xiZa@G#-kC#Z+ltbbwK zMW(y8<~VwG@L2y-;Fx#z(tihVg26&IjkpqKN&sCKF7iO6;Kq{$@2<1z7~v{HX&ToO+L|A!{tjec%1E`C?ffl&vQ;<>K~Ld zU!~a?I~V}4G6`SbuP!&bxARZ9eSPCcT;t590@!0Hm8#@gx%rP4^kYdE-C}=w%ygX< z8}Z_;ggj8w;MkVe#Q0a%9Zn)sVXk;)?bytH=Ix<=h8CObI}knED$H_Mv$t$<1&UqT z@>J-neM5=O8e#$*u?IAOYpM}x4-rUC?csbCeg5FY6+8wqdXDFbokqOMuYx>X1H6vN z$hnP?9Pb>p$DfKrF=FtT)8ieJb;=zrWG4~@Y?kk2G(~F)rOqS?M8fnYDta${$c@)o zl<;Bs72vfyzR6�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

ifHvFUwP_kG_5)k>< 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 None: + global _HELLGATE_RESULT, _HELLGATE_IDENTITIES + fields = result.get("fields") if isinstance(result, dict) else None + trial = fields.get("trial_diagnostics") if isinstance(fields, dict) else None + ground = fields.get("ground_state_transfer") if isinstance(fields, dict) else None + if ( + not isinstance(result, dict) + or result.get("status") != "bounded" + or result.get("checker_verdict") != "ACCEPT" + or result.get("formal") is not False + or not isinstance(trial, dict) + or trial.get("schema") != "jackal-hellgate-trial-diagnostics-v1" + or trial.get("subject") != "normalized-certificate-trial-phi" + or not isinstance(ground, dict) + or ground.get("schema") != "jackal-hellgate-ground-transfer-v1" + or ground.get("subject") != "positive-normalized-ground-state-u0" + or not all( + isinstance(value, str) and re.fullmatch(r"[0-9a-f]{64}", value) + for value in (advanced_sha256, checker_sha256, certificate_sha256) + ) + ): + raise RuntimeError("HELLGATE certificate did not pass the startup gate") + _HELLGATE_RESULT = copy.deepcopy(result) + _HELLGATE_IDENTITIES = { + "jackal_advanced_sha256": advanced_sha256, + "hellgate_checker_sha256": checker_sha256, + "hellgate_certificate_file_sha256": certificate_sha256, + } + + +def _identity() -> str: + if _IDENTITY is None: + raise RuntimeError("advanced identity is unavailable outside integrated dispatch") + return _IDENTITY + + +def _refusal(reason: str, detail: str) -> dict: + return { + "status": "refused", + "reason": reason, + "detail": detail, + "consequence_ceiling": CONSEQUENCE_CEILING, + "identities": {"jackal_advanced_sha256": _identity()}, + "non_claims": [ + "A refusal is an answer; no weaker lane was substituted", + "No visual or numerical result was established", + ], + } + + +def _kernel_call(tool: str, arguments: dict) -> dict: + if _KERNEL is None: + raise Refusal("kernel-unavailable", "advanced module is not attached to JACKAL") + result = _KERNEL.call(tool, arguments) + if not isinstance(result, dict): + raise Refusal("kernel-error", "JACKAL returned a non-object") + trace = { + "tool": tool, + "arguments": copy.deepcopy(arguments), + "status": result.get("status", "unknown"), + } + fields = result.get("fields") + if isinstance(fields, dict) and isinstance(fields.get("parsed"), str): + trace["parsed"] = fields["parsed"] + if isinstance(result.get("engine_output"), str): + trace["engine_output"] = result["engine_output"] + _TRACE.append(trace) + if result.get("status") == "refused": + raise Refusal( + f"kernel-refused:{result.get('reason', 'unknown')}", + str(result.get("detail", "the delegated JACKAL lane refused")), + ) + return result + + +def _fraction(text: object, subject: str) -> Fraction: + if not isinstance(text, str) or not text or len(text) > 256: + raise Refusal("args", f"{subject} must be a bounded rational string") + try: + value = Fraction(text) + except (ValueError, ZeroDivisionError) as error: + raise Refusal("args", f"{subject} is not an integer, decimal, or rational") from error + return value + + +def _cas(arguments: dict) -> dict: + operation = arguments.get("operation") + delegated_arguments = arguments.get("arguments") + if not isinstance(operation, str) or operation not in CAS_ROUTES: + raise Refusal("operation-unknown", "operation is not in the closed CAS route table") + if not isinstance(delegated_arguments, dict): + raise Refusal("args", "arguments must be an object for the selected JACKAL tool") + tool = CAS_ROUTES[operation] + result = _kernel_call(tool, delegated_arguments) + return { + "status": result.get("status", "indeterminate"), + "lane": "cas-route", + "formal": bool(result.get("formal", False)), + "parsed": {"operation": operation, "delegated_tool": tool}, + "result": result, + "delegated_to": list(_TRACE), + "identities": {"jackal_advanced_sha256": _identity()}, + "non_claims": [ + "The CAS router adds no assurance to the delegated JACKAL result", + "Preserve the delegated status, assumptions, identities, and non-claims unchanged", + ], + } + + +_FONT = { + " ": "00000/00000/00000/00000/00000/00000/00000", + "A": "01110/10001/10001/11111/10001/10001/10001", + "B": "11110/10001/10001/11110/10001/10001/11110", + "C": "01111/10000/10000/10000/10000/10000/01111", + "D": "11110/10001/10001/10001/10001/10001/11110", + "E": "11111/10000/10000/11110/10000/10000/11111", + "F": "11111/10000/10000/11110/10000/10000/10000", + "G": "01111/10000/10000/10111/10001/10001/01111", + "H": "10001/10001/10001/11111/10001/10001/10001", + "I": "11111/00100/00100/00100/00100/00100/11111", + "J": "00111/00010/00010/00010/10010/10010/01100", + "K": "10001/10010/10100/11000/10100/10010/10001", + "L": "10000/10000/10000/10000/10000/10000/11111", + "M": "10001/11011/10101/10101/10001/10001/10001", + "N": "10001/11001/10101/10011/10001/10001/10001", + "O": "01110/10001/10001/10001/10001/10001/01110", + "P": "11110/10001/10001/11110/10000/10000/10000", + "Q": "01110/10001/10001/10001/10101/10010/01101", + "R": "11110/10001/10001/11110/10100/10010/10001", + "S": "01111/10000/10000/01110/00001/00001/11110", + "T": "11111/00100/00100/00100/00100/00100/00100", + "U": "10001/10001/10001/10001/10001/10001/01110", + "V": "10001/10001/10001/10001/10001/01010/00100", + "W": "10001/10001/10001/10101/10101/10101/01010", + "X": "10001/10001/01010/00100/01010/10001/10001", + "Y": "10001/10001/01010/00100/00100/00100/00100", + "Z": "11111/00001/00010/00100/01000/10000/11111", + "0": "01110/10001/10011/10101/11001/10001/01110", + "1": "00100/01100/00100/00100/00100/00100/01110", + "2": "01110/10001/00001/00010/00100/01000/11111", + "3": "11110/00001/00001/01110/00001/00001/11110", + "4": "00010/00110/01010/10010/11111/00010/00010", + "5": "11111/10000/10000/11110/00001/00001/11110", + "6": "01110/10000/10000/11110/10001/10001/01110", + "7": "11111/00001/00010/00100/01000/01000/01000", + "8": "01110/10001/10001/01110/10001/10001/01110", + "9": "01110/10001/10001/01111/00001/00001/01110", + "+": "00000/00100/00100/11111/00100/00100/00000", + "-": "00000/00000/00000/11111/00000/00000/00000", + "*": "00000/10101/01110/11111/01110/10101/00000", + "/": "00001/00010/00010/00100/01000/01000/10000", + "^": "00100/01010/10001/00000/00000/00000/00000", + "(": "00010/00100/01000/01000/01000/00100/00010", + ")": "01000/00100/00010/00010/00010/00100/01000", + "[": "01110/01000/01000/01000/01000/01000/01110", + "]": "01110/00010/00010/00010/00010/00010/01110", + ".": "00000/00000/00000/00000/00000/00110/00110", + ",": "00000/00000/00000/00000/00110/00110/00100", + ":": "00000/00110/00110/00000/00110/00110/00000", + "=": "00000/00000/11111/00000/11111/00000/00000", + "|": "00100/00100/00100/00100/00100/00100/00100", + "_": "00000/00000/00000/00000/00000/00000/11111", + "?": "01110/10001/00001/00010/00100/00000/00100", +} + + +def _set_pixel(buffer: bytearray, x: int, y: int, color: tuple[int, int, int]) -> None: + if 0 <= x < RENDER_WIDTH and 0 <= y < RENDER_HEIGHT: + offset = (y * RENDER_WIDTH + x) * 3 + buffer[offset : offset + 3] = bytes(color) + + +def _fill_rect( + buffer: bytearray, + left: int, + top: int, + right: int, + bottom: int, + color: tuple[int, int, int], +) -> None: + clipped_left = max(0, left) + clipped_top = max(0, top) + clipped_right = min(RENDER_WIDTH, right) + clipped_bottom = min(RENDER_HEIGHT, bottom) + if clipped_left >= clipped_right or clipped_top >= clipped_bottom: + return + row = bytes(color) * (clipped_right - clipped_left) + for y in range(clipped_top, clipped_bottom): + start = (y * RENDER_WIDTH + clipped_left) * 3 + buffer[start : start + len(row)] = row + + +def _line( + buffer: bytearray, + x0: int, + y0: int, + x1: int, + y1: int, + color: tuple[int, int, int], + thickness: int = 1, +) -> None: + dx = abs(x1 - x0) + sx = 1 if x0 < x1 else -1 + dy = -abs(y1 - y0) + sy = 1 if y0 < y1 else -1 + error = dx + dy + while True: + for ox in range(-(thickness // 2), thickness // 2 + 1): + for oy in range(-(thickness // 2), thickness // 2 + 1): + _set_pixel(buffer, x0 + ox, y0 + oy, color) + if x0 == x1 and y0 == y1: + break + doubled = 2 * error + if doubled >= dy: + error += dy + x0 += sx + if doubled <= dx: + error += dx + y0 += sy + + +def _draw_text( + buffer: bytearray, + x: int, + y: int, + value: str, + color: tuple[int, int, int], + scale: int, + align: str = "left", +) -> None: + rendered = str(value).upper() + width = max(0, (len(rendered) * 6 - 1) * scale) + if align == "center": + x -= width // 2 + elif align == "right": + x -= width + for character in rendered: + rows = _FONT.get(character, _FONT["?"]).split("/") + for row_index, row in enumerate(rows): + for column_index, bit in enumerate(row): + if bit == "1": + _fill_rect( + buffer, + x + column_index * scale, + y + row_index * scale, + x + (column_index + 1) * scale, + y + (row_index + 1) * scale, + color, + ) + x += 6 * scale + + +def _fit_text(value: str, max_width: int, scale: int) -> str: + capacity = max(1, (max_width // scale + 1) // 6) + rendered = str(value).upper() + if len(rendered) <= capacity: + return rendered + if capacity <= 3: + return rendered[:capacity] + return rendered[: capacity - 3] + "..." + + +def _format_tick(value: float) -> str: + if abs(value) < 1e-12: + value = 0.0 + return f"{value:.5g}".upper() + + +def _downsample(rows: bytearray) -> bytearray: + output = bytearray(GRAPH_WIDTH * GRAPH_HEIGHT * 3) + area = GRAPH_SUPERSAMPLE * GRAPH_SUPERSAMPLE + for y in range(GRAPH_HEIGHT): + for x in range(GRAPH_WIDTH): + red = green = blue = 0 + for offset_y in range(GRAPH_SUPERSAMPLE): + source_y = y * GRAPH_SUPERSAMPLE + offset_y + for offset_x in range(GRAPH_SUPERSAMPLE): + source_x = x * GRAPH_SUPERSAMPLE + offset_x + source = (source_y * RENDER_WIDTH + source_x) * 3 + red += rows[source] + green += rows[source + 1] + blue += rows[source + 2] + target = (y * GRAPH_WIDTH + x) * 3 + output[target] = red // area + output[target + 1] = green // area + output[target + 2] = blue // area + return output + + +def _png(rows: bytearray) -> bytes: + scanlines = bytearray() + stride = GRAPH_WIDTH * 3 + for row in range(GRAPH_HEIGHT): + scanlines.append(0) + start = row * stride + scanlines.extend(rows[start : start + stride]) + + def chunk(kind: bytes, payload: bytes) -> bytes: + return ( + struct.pack(">I", len(payload)) + + kind + + payload + + struct.pack(">I", binascii.crc32(kind + payload) & 0xFFFFFFFF) + ) + + header = struct.pack(">IIBBBBB", GRAPH_WIDTH, GRAPH_HEIGHT, 8, 2, 0, 0, 0) + return b"\x89PNG\r\n\x1a\n" + chunk(b"IHDR", header) + chunk( + b"IDAT", zlib.compress(bytes(scanlines), 9) + ) + chunk(b"IEND", b"") + + +def _render_graph( + expression: str, + samples: int, + numeric: list[tuple[int, float, float]], + x_low: float, + x_high: float, + y_low: float, + y_high: float, +) -> bytes: + scale = GRAPH_SUPERSAMPLE + background_top = (7, 12, 19) + background_bottom = (11, 19, 29) + pixels = bytearray() + for y in range(RENDER_HEIGHT): + fraction = y / max(1, RENDER_HEIGHT - 1) + color = tuple( + round(background_top[channel] * (1 - fraction) + + background_bottom[channel] * fraction) + for channel in range(3) + ) + pixels.extend(bytes(color) * RENDER_WIDTH) + + foreground = (225, 236, 241) + secondary = (135, 158, 171) + muted = (92, 117, 132) + grid = (30, 48, 61) + border = (53, 75, 89) + plot_background = (10, 18, 27) + axis = (109, 139, 156) + teal = (0, 224, 184) + teal_highlight = (123, 255, 226) + teal_shadow = (0, 74, 72) + badge_background = (10, 51, 51) + + plot_left = 112 * scale + plot_right = 1144 * scale + plot_top = 150 * scale + plot_bottom = 592 * scale + _fill_rect(pixels, plot_left, plot_top, plot_right + 1, plot_bottom + 1, plot_background) + + title_scale = 6 + text_scale = 4 + small_scale = 3 + _draw_text(pixels, 64 * scale, 27 * scale, "JACKAL + THOTH", teal_highlight, title_scale) + _draw_text( + pixels, + 64 * scale, + 66 * scale, + "EVIDENCE-AWARE FUNCTION GRAPH", + secondary, + text_scale, + ) + badge_text = "ESTIMATED VISUALIZATION" + badge_left = 874 * scale + badge_top = 29 * scale + badge_right = 1144 * scale + badge_bottom = 64 * scale + _fill_rect( + pixels, + badge_left, + badge_top, + badge_right, + badge_bottom, + badge_background, + ) + _line(pixels, badge_left, badge_top, badge_right, badge_top, teal, 2) + _line(pixels, badge_left, badge_bottom, badge_right, badge_bottom, teal, 2) + _draw_text( + pixels, + (badge_left + badge_right) // 2, + 41 * scale, + badge_text, + teal_highlight, + small_scale, + "center", + ) + + expression_text = _fit_text( + "F(X) = " + expression, + plot_right - plot_left, + text_scale, + ) + _draw_text( + pixels, + plot_left, + 116 * scale, + expression_text, + foreground, + text_scale, + ) + _draw_text( + pixels, + plot_right, + 118 * scale, + f"{samples} DELEGATED SAMPLES", + muted, + small_scale, + "right", + ) + + x_divisions = 8 + y_divisions = 6 + for division in range(x_divisions + 1): + gx = plot_left + (plot_right - plot_left) * division // x_divisions + _line(pixels, gx, plot_top, gx, plot_bottom, grid, 2) + tick = x_low + (x_high - x_low) * division / x_divisions + _draw_text( + pixels, + gx, + 609 * scale, + _format_tick(tick), + secondary, + small_scale, + "center", + ) + for division in range(y_divisions + 1): + gy = plot_top + (plot_bottom - plot_top) * division // y_divisions + _line(pixels, plot_left, gy, plot_right, gy, grid, 2) + tick = y_high - (y_high - y_low) * division / y_divisions + _draw_text( + pixels, + 98 * scale, + gy - 3 * scale, + _format_tick(tick), + secondary, + small_scale, + "right", + ) + + _line(pixels, plot_left, plot_top, plot_right, plot_top, border, 2) + _line(pixels, plot_right, plot_top, plot_right, plot_bottom, border, 2) + _line(pixels, plot_right, plot_bottom, plot_left, plot_bottom, border, 2) + _line(pixels, plot_left, plot_bottom, plot_left, plot_top, border, 2) + + def map_x(value: float) -> int: + return round( + plot_left + + (value - x_low) * (plot_right - plot_left) / (x_high - x_low) + ) + + def map_y(value: float) -> int: + return round( + plot_bottom + - (value - y_low) * (plot_bottom - plot_top) / (y_high - y_low) + ) + + if x_low <= 0 <= x_high: + zero_x = map_x(0.0) + _line(pixels, zero_x, plot_top, zero_x, plot_bottom, axis, 4) + if y_low <= 0 <= y_high: + zero_y = map_y(0.0) + _line(pixels, plot_left, zero_y, plot_right, zero_y, axis, 4) + + previous: tuple[int, int, int] | None = None + segments: list[tuple[int, int, int, int]] = [] + for sample_index, x_value, y_value in numeric: + current = (map_x(x_value), map_y(y_value)) + if previous is not None and sample_index == previous[0] + 1: + segments.append((previous[1], previous[2], current[0], current[1])) + previous = (sample_index, current[0], current[1]) + for x0, y0, x1, y1 in segments: + _line(pixels, x0, y0, x1, y1, teal_shadow, 12) + for x0, y0, x1, y1 in segments: + _line(pixels, x0, y0, x1, y1, teal, 6) + for x0, y0, x1, y1 in segments: + _line(pixels, x0, y0, x1, y1, teal_highlight, 2) + + footer = "EXACT RATIONAL X COORDINATES | ESTIMATED F64 Y SAMPLES | PIXELS ARE NOT PROOF" + _draw_text( + pixels, + 64 * scale, + 680 * scale, + _fit_text(footer, 1080 * scale, small_scale), + muted, + small_scale, + ) + return _png(_downsample(pixels)) + + +def _graph(arguments: dict) -> dict: + expression = arguments.get("expression") + if ( + not isinstance(expression, str) + or not expression + or len(expression.encode("utf-8")) > MAX_EXPRESSION_BYTES + or any(ord(character) < 32 for character in expression) + ): + raise Refusal("args", "expression must be nonempty bounded printable text") + lower = _fraction(arguments.get("x_min"), "x_min") + upper = _fraction(arguments.get("x_max"), "x_max") + if lower >= upper: + raise Refusal("interval-order", "x_min must be strictly below x_max") + samples_text = arguments.get("samples") + if not isinstance(samples_text, str) or CANONICAL_INTEGER.fullmatch(samples_text) is None: + raise Refusal("args", "samples must be a canonical positive integer string") + samples = int(samples_text) + if not MIN_GRAPH_SAMPLES <= samples <= MAX_GRAPH_SAMPLES: + raise Refusal( + "sample-budget", + f"samples must be between {MIN_GRAPH_SAMPLES} and {MAX_GRAPH_SAMPLES}", + ) + + points: list[dict[str, str]] = [] + numeric: list[tuple[int, float, float]] = [] + for index in range(samples): + coordinate_result = _kernel_call( + "jackal_exact", + { + "expression": ( + f"({lower}) + ({index})*(({upper})-({lower}))/({samples - 1})" + ) + }, + ) + fields = coordinate_result.get("fields") + coordinate = fields.get("exact") if isinstance(fields, dict) else None + if not isinstance(coordinate, str): + raise Refusal("kernel-error", "jackal_exact returned no graph coordinate") + substituted = X_TOKEN.sub(f"({coordinate})", expression) + try: + evaluated = _kernel_call("jackal_evaluate", {"expression": substituted}) + except Refusal as error: + if error.reason.startswith("kernel-refused:"): + points.append( + {"x": coordinate, "status": "refused", "reason": error.reason} + ) + continue + raise + rendered = evaluated.get("engine_output") + if not isinstance(rendered, str): + points.append({"x": coordinate, "status": "indeterminate"}) + continue + try: + y_decimal = decimal.Decimal(rendered) + except decimal.InvalidOperation: + points.append({"x": coordinate, "status": "indeterminate"}) + continue + if not y_decimal.is_finite(): + points.append({"x": coordinate, "status": "indeterminate"}) + continue + try: + x_float = float(Fraction(coordinate)) + y_float = float(y_decimal) + except (OverflowError, ValueError): + points.append({"x": coordinate, "status": "indeterminate"}) + continue + if not math.isfinite(x_float) or not math.isfinite(y_float): + points.append({"x": coordinate, "status": "indeterminate"}) + continue + numeric.append((index, x_float, y_float)) + points.append({"x": coordinate, "y": rendered, "status": "estimated"}) + + if len(numeric) < 2: + raise Refusal("graph-empty", "fewer than two finite delegated samples were available") + y_values = [point[2] for point in numeric] + y_low = min(y_values) + y_high = max(y_values) + if y_low == y_high: + padding = max(1.0, abs(y_low) * 0.05) + else: + padding = (y_high - y_low) * 0.05 + y_low -= padding + y_high += padding + x_low = float(lower) + x_high = float(upper) + image = _render_graph( + expression, + samples, + numeric, + x_low, + x_high, + y_low, + y_high, + ) + summary = ( + f"JACKAL graph: {expression} on [{lower}, {upper}] using {samples} delegated " + "f64 samples. The curve is estimated visualization, not a bound or proof." + ) + return { + "status": "estimated", + "lane": "graph-delegated-f64-v1", + "formal": False, + "consequence_ceiling": CONSEQUENCE_CEILING, + "parsed": { + "expression": expression, + "x_interval": [str(lower), str(upper)], + "samples": str(samples), + }, + "fields": { + "points": points, + "finite_sample_count": len(numeric), + "observed_y_min": str(min(y_values)), + "observed_y_max": str(max(y_values)), + "image_mime_type": "image/png", + }, + "delegated_to": list(_TRACE), + "identities": {"jackal_advanced_sha256": _identity()}, + "non_claims": [ + "Graph pixels and connecting line segments are visualization only", + "Every plotted y value is status=estimated IEEE f64, not bounded or formal-bounded", + "Refused or indeterminate samples break the rendered curve instead of being bridged", + "Sampling cannot prove continuity, roots, extrema, absence of poles, or behavior between samples", + "Use JACKAL's exact or bounded lanes separately for claims inferred from the graph", + ], + "_mcp_content": [ + {"type": "text", "text": summary}, + { + "type": "image", + "data": base64.b64encode(image).decode("ascii"), + "mimeType": "image/png", + }, + ], + } + + +def _hellgate(arguments: dict) -> dict: + if arguments.get("problem_id") != "hellgate-v1": + raise Refusal( + "unsupported-problem", + "this certificate lane admits only problem_id='hellgate-v1'", + ) + if _HELLGATE_RESULT is None or _HELLGATE_IDENTITIES is None: + raise Refusal("certificate-unavailable", "HELLGATE startup verification is unavailable") + result = copy.deepcopy(_HELLGATE_RESULT) + identities = result.setdefault("identities", {}) + if not isinstance(identities, dict): + raise Refusal("certificate-error", "verified result identities are malformed") + identities.update(_HELLGATE_IDENTITIES) + result["consequence_ceiling"] = "advisory" + return result + + +def dispatch_integrated( + name: str, + arguments: dict, + kernel_call: Callable[[str, dict], dict], + identity: str, +) -> dict: + global _KERNEL, _IDENTITY, _TRACE + if name not in ADVANCED_TOOL_NAMES or not isinstance(arguments, dict): + return { + "status": "refused", + "reason": "tool-unknown", + "detail": "advanced tool name or arguments are invalid", + } + + class Kernel: + evaluator_sha256: str | None = None + + @staticmethod + def call(tool: str, delegated_arguments: dict) -> dict: + return kernel_call(tool, delegated_arguments) + + _KERNEL = Kernel() + _IDENTITY = identity + _TRACE = [] + try: + if name == "jackal_cas": + return _cas(arguments) + if name == "jackal_graph": + return _graph(arguments) + return _hellgate(arguments) + except Refusal as error: + return _refusal(error.reason, error.detail) + except Exception: + return _refusal("advanced-error", "advanced orchestration failed closed") + finally: + _KERNEL = None + _IDENTITY = None + _TRACE = [] + + +def _schema(properties: dict, required: list[str]) -> dict: + return { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": properties, + "required": required, + "additionalProperties": False, + } + + +def _definition(name: str, title: str, description: str, schema: dict) -> dict: + return { + "name": name, + "title": title, + "description": description, + "inputSchema": schema, + "annotations": { + "readOnlyHint": True, + "destructiveHint": False, + "idempotentHint": True, + "openWorldHint": False, + }, + } + + +def tool_definitions() -> list[dict]: + return [ + _definition( + "jackal_cas", + "JACKAL unified CAS", + "One evidence-preserving front door for exact, symbolic, numerical, bounded, and formal JACKAL lanes. The router adds no assurance and never silently downgrades.", + _schema( + { + "operation": { + "type": "string", + "enum": sorted(CAS_ROUTES), + "description": "Closed CAS operation identifier.", + }, + "arguments": { + "type": "object", + "description": "Arguments for the selected underlying JACKAL tool.", + }, + }, + ["operation", "arguments"], + ), + ), + _definition( + "jackal_graph", + "JACKAL graph", + "Render a PNG curve from exact rational x coordinates and delegated status=estimated JACKAL evaluations. Pixels are explicitly not proof; use a bound lane for graph-derived claims.", + _schema( + { + "expression": { + "type": "string", + "description": "JACKAL expression in the single plotting variable x.", + }, + "x_min": {"type": "string", "description": "Rational lower x bound."}, + "x_max": {"type": "string", "description": "Rational upper x bound."}, + "samples": { + "type": "string", + "description": "Canonical integer sample count, 17..257.", + }, + }, + ["expression", "x_min", "x_max", "samples"], + ), + ), + _definition( + "jackal_hellgate_ground_state", + "JACKAL HELLGATE ground-state certificate", + "Replay the identity-pinned exact-rational nonlinear Barta certificate for the fixed HELLGATE positive even normalized ground-state eigenvalue, scoped trial diagnostics, and a strong-convexity transfer for the ground-state quartic norm and energy functional. Returns status=bounded, never formal-bounded; trial moments are not ground-state moments.", + _schema( + { + "problem_id": { + "type": "string", + "enum": ["hellgate-v1"], + "description": "Exact fixed problem identifier.", + } + }, + ["problem_id"], + ), + ), + ] + + +if __name__ == "__main__": + raise SystemExit( + "advanced.py is an identity-pinned JACKAL module, not a standalone service" + ) diff --git a/plugins/jackel/mcp/certificates/README.md b/plugins/jackel/mcp/certificates/README.md new file mode 100644 index 0000000..f5b05ff --- /dev/null +++ b/plugins/jackel/mcp/certificates/README.md @@ -0,0 +1,15 @@ +# Identity-pinned certificates + +`hellgate_v1.json.zlib` is a deterministic compressed JSON certificate produced by +`tools/hellgate_generate.py`. The plugin never trusts the producer: startup loads the +compressed bytes through the plugin identity inventory, decompresses them under a hard +size bound, and passes the raw JSON to the independent exact-rational checker in +`mcp/hellgate_verify.py`. + +Acceptance is `status=bounded`, not `formal-bounded`. In addition to the Barta +eigenvalue enclosure, the checker returns exact-rational bounded diagnostics for +the normalized certificate trial `phi`. Those moments and residuals are not +ground-state quantities. A separately labelled lambda-strong-convexity transfer +encloses only the true ground-state quartic norm and energy functional. The +checker states the comparison and transfer assumptions plus their residual +non-claims in the returned result. diff --git a/plugins/jackel/mcp/certificates/hellgate_v1.json.zlib b/plugins/jackel/mcp/certificates/hellgate_v1.json.zlib new file mode 100644 index 0000000000000000000000000000000000000000..9c6071afe5379ce595278d0d517602d07710a8fd GIT binary patch literal 699181 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%0DT@d;K5}~2z2@H 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


iodoPEeE=2eOP|?@fI{8e?7Y$ZIkMg#%6a`! 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%0AZKS6sn>k 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 BW7Yrw literal 0 HcmV?d00001 diff --git a/plugins/jackel/mcp/hellgate_verify.py b/plugins/jackel/mcp/hellgate_verify.py new file mode 100644 index 0000000..498597c --- /dev/null +++ b/plugins/jackel/mcp/hellgate_verify.py @@ -0,0 +1,1145 @@ +#!/usr/bin/env python3 -B +"""Exact-rational checker for the fixed HELLGATE nonlinear Barta certificate. + +The producer is deliberately not imported. This verifier uses only Python's +integer and ``Fraction`` arithmetic. Transcendentals are enclosed by a second +implementation based on rational Taylor bounds. Acceptance means the encoded +positive normalized trial function has a globally bounded nonlinear Rayleigh +quotient; the nonlinear Barta comparison theorem then encloses the unique +positive normalized ground-state eigenvalue. + +The same replay additionally encloses diagnostics of the normalized trial and, +under a stated strong-convexity theorem, transfers only the quartic norm and +energy functional to the ground state. Subject fields and non-claims prevent +the trial moments from being presented as ground-state quantities. + +This checker is not a Lean theorem and never returns ``formal-bounded``. +""" + +from __future__ import annotations + +import hashlib +import hmac +import json +import re +import sys +from fractions import Fraction +from math import comb, factorial, isqrt, lcm +from pathlib import Path +from typing import Any + + +SCHEMA = "jackal-hellgate-barta-certificate-v1" +RESULT_SCHEMA = "jackal-hellgate-barta-verification-v1" +MAX_CERTIFICATE_BYTES = 4 * 1024 * 1024 +MAX_JSON_DEPTH = 16 +MAX_JSON_NODES = 40000 +MAX_INTEGER_DIGITS = 384 +MAX_PIECES = 512 +MAX_POLYNOMIAL_DEGREE = 64 +MAX_TAIL_TERMS = 128 +MAX_EIGENVALUE_WIDTH = Fraction(1, 500000000000) +EXP_TAYLOR_DEGREE = 60 +EXP_DYADIC_BITS = 256 +SQRT_DYADIC_BITS = 192 +MAX_TRIAL_VIRIAL_ABS = Fraction(1, 100000000000) +MAX_TRIAL_IDENTITY_ABS = Fraction(1, 1000000000000) +MAX_DENSITY_L2_DISTANCE = Fraction(1, 1000000) +RATIONAL = re.compile(r"-?(?:0|[1-9][0-9]*)(?:/[1-9][0-9]*)?\Z", re.ASCII) +SHA256 = re.compile(r"[0-9a-f]{64}\Z", re.ASCII) + + +class VerificationRefusal(RuntimeError): + def __init__(self, reason: str, detail: str): + super().__init__(detail) + self.reason = reason + self.detail = detail + + +def refuse(reason: str, detail: str) -> None: + raise VerificationRefusal(reason, detail) + + +def canonical_bytes(value: object) -> bytes: + return json.dumps( + value, sort_keys=True, separators=(",", ":"), ensure_ascii=False + ).encode("utf-8") + + +def strict_json(raw: bytes) -> object: + if not raw or len(raw) > MAX_CERTIFICATE_BYTES or not raw.endswith(b"\n"): + refuse("certificate-bytes", "certificate must be bounded and end in one LF") + try: + text = raw[:-1].decode("utf-8") + except UnicodeDecodeError as error: + refuse("certificate-encoding", "certificate is not UTF-8") + + def pairs(items: list[tuple[str, object]]) -> dict[str, object]: + result: dict[str, object] = {} + for key, value in items: + if key in result: + refuse("duplicate-json-key", f"duplicate JSON key {key!r}") + result[key] = value + return result + + def integer(token: str) -> int: + digits = token.lstrip("-") + if len(digits) > MAX_INTEGER_DIGITS: + refuse("integer-budget", "JSON integer exceeds the digit budget") + return int(token) + + try: + value = json.loads( + text, + object_pairs_hook=pairs, + parse_int=integer, + parse_float=lambda unused: refuse( + "json-number", "JSON floating-point literals are forbidden" + ), + parse_constant=lambda unused: refuse( + "json-number", "non-finite JSON literals are forbidden" + ), + ) + except VerificationRefusal: + raise + except (ValueError, RecursionError) as error: + refuse("certificate-json", f"certificate JSON refused: {error}") + + stack: list[tuple[object, int]] = [(value, 1)] + nodes = 0 + while stack: + item, depth = stack.pop() + nodes += 1 + if nodes > MAX_JSON_NODES or depth > MAX_JSON_DEPTH: + refuse("certificate-structure", "certificate structure budget exceeded") + if isinstance(item, dict): + stack.extend((child, depth + 1) for child in item.values()) + elif isinstance(item, list): + stack.extend((child, depth + 1) for child in item) + return value + + +def rational(value: object, context: str) -> Fraction: + if not isinstance(value, str) or len(value) > 2 * MAX_INTEGER_DIGITS + 2: + refuse("rational-token", f"{context} is not a bounded rational token") + if RATIONAL.fullmatch(value) is None: + refuse("rational-token", f"{context} is not canonical rational syntax") + numerator, separator, denominator = value.partition("/") + if len(numerator.lstrip("-")) > MAX_INTEGER_DIGITS or ( + separator and len(denominator) > MAX_INTEGER_DIGITS + ): + refuse("integer-budget", f"{context} exceeds the integer digit budget") + try: + result = Fraction(value) + except (ValueError, ZeroDivisionError) as error: + refuse("rational-token", f"{context} is not a rational: {error}") + if str(result) != value: + refuse("rational-canonical", f"{context} is not reduced canonical form") + return result + + +def exact_keys(value: object, expected: set[str], context: str) -> dict[str, object]: + if not isinstance(value, dict) or set(value) != expected: + refuse("certificate-shape", f"{context} keys do not match the closed schema") + return value + + +def poly_trim(value: list[Fraction]) -> list[Fraction]: + result = list(value) + while len(result) > 1 and result[-1] == 0: + result.pop() + return result + + +def poly_add(left: list[Fraction], right: list[Fraction]) -> list[Fraction]: + size = max(len(left), len(right)) + result = [Fraction(0)] * size + for index in range(size): + if index < len(left): + result[index] += left[index] + if index < len(right): + result[index] += right[index] + return poly_trim(result) + + +def poly_scale(value: list[Fraction], factor: Fraction) -> list[Fraction]: + return poly_trim([factor * coefficient for coefficient in value]) + + +def poly_mul(left: list[Fraction], right: list[Fraction]) -> list[Fraction]: + left_denominator = lcm(*(coefficient.denominator for coefficient in left)) + right_denominator = lcm(*(coefficient.denominator for coefficient in right)) + left_integers = [ + coefficient.numerator * (left_denominator // coefficient.denominator) + for coefficient in left + ] + right_integers = [ + coefficient.numerator * (right_denominator // coefficient.denominator) + for coefficient in right + ] + integer_result = [0] * (len(left) + len(right) - 1) + for left_index, left_value in enumerate(left_integers): + for right_index, right_value in enumerate(right_integers): + integer_result[left_index + right_index] += left_value * right_value + denominator = left_denominator * right_denominator + return poly_trim([Fraction(value, denominator) for value in integer_result]) + + +def poly_pow(value: list[Fraction], exponent: int) -> list[Fraction]: + result = [Fraction(1)] + base = list(value) + power = exponent + while power: + if power & 1: + result = poly_mul(result, base) + power //= 2 + if power: + base = poly_mul(base, base) + return result + + +def poly_derivative(value: list[Fraction]) -> list[Fraction]: + if len(value) <= 1: + return [Fraction(0)] + return [Fraction(index) * value[index] for index in range(1, len(value))] + + +def poly_at_one(value: list[Fraction]) -> Fraction: + return sum(value, Fraction(0)) + + +def poly_abs_sum(value: list[Fraction]) -> Fraction: + return sum((abs(coefficient) for coefficient in value), Fraction(0)) + + +def poly_integral_unit(value: list[Fraction]) -> Fraction: + """Integrate a power-basis polynomial exactly over ``0 <= s <= 1``.""" + coefficient_denominator = lcm( + *(coefficient.denominator for coefficient in value) + ) + integral_denominator = lcm(*range(1, len(value) + 1)) + numerator = sum( + coefficient.numerator + * (coefficient_denominator // coefficient.denominator) + * (integral_denominator // (index + 1)) + for index, coefficient in enumerate(value) + ) + return Fraction(numerator, coefficient_denominator * integral_denominator) + + +def poly_product_integral_unit( + left: list[Fraction], right: list[Fraction] +) -> Fraction: + """Integrate a polynomial product with one final rational reduction. + + Accumulating every product through ``Fraction`` repeatedly computes very + large gcds. Common coefficient and monomial-integral denominators make the + same exact sum an integer accumulation followed by one reduction. + """ + left_denominator = lcm(*(coefficient.denominator for coefficient in left)) + right_denominator = lcm(*(coefficient.denominator for coefficient in right)) + integral_denominator = lcm(*range(1, len(left) + len(right))) + left_integers = [ + coefficient.numerator * (left_denominator // coefficient.denominator) + for coefficient in left + ] + right_integers = [ + coefficient.numerator * (right_denominator // coefficient.denominator) + for coefficient in right + ] + numerator = sum( + left_value + * right_value + * (integral_denominator // (left_index + right_index + 1)) + for left_index, left_value in enumerate(left_integers) + for right_index, right_value in enumerate(right_integers) + ) + return Fraction( + numerator, + left_denominator * right_denominator * integral_denominator, + ) + + +def power_to_bernstein(value: list[Fraction]) -> list[Fraction]: + """Return exact same-degree Bernstein coefficients on the unit interval.""" + degree = len(value) - 1 + return [ + sum( + ( + value[power] * Fraction(comb(index, power), comb(degree, power)) + for power in range(index + 1) + ), + Fraction(0), + ) + for index in range(degree + 1) + ] + + +Interval = tuple[Fraction, Fraction] + + +def interval_add(left: Interval, right: Interval) -> Interval: + return left[0] + right[0], left[1] + right[1] + + +def interval_sub(left: Interval, right: Interval) -> Interval: + return left[0] - right[1], left[1] - right[0] + + +def interval_scale(value: Interval, factor: Fraction) -> Interval: + if factor >= 0: + return value[0] * factor, value[1] * factor + return value[1] * factor, value[0] * factor + + +def interval_divide_positive(numerator: Interval, denominator: Interval) -> Interval: + if numerator[0] < 0 or denominator[0] <= 0: + refuse("checker-internal", "positive interval division received an invalid input") + return numerator[0] / denominator[1], numerator[1] / denominator[0] + + +def interval_square_positive(value: Interval) -> Interval: + if value[0] < 0: + refuse("checker-internal", "positive interval square received a negative input") + return value[0] * value[0], value[1] * value[1] + + +def sqrt_fraction_bound(value: Fraction) -> Interval: + """Enclose a nonnegative rational square root on an exact dyadic grid.""" + if value < 0: + refuse("checker-internal", "rational square root received a negative input") + scale = 1 << SQRT_DYADIC_BITS + scaled_numerator = value.numerator * scale * scale + quotient = scaled_numerator // value.denominator + lower_integer = isqrt(quotient) + lower = Fraction(lower_integer, scale) + if lower * lower == value: + return lower, lower + return lower, Fraction(lower_integer + 1, scale) + + +def interval_text(value: Interval) -> list[str]: + if value[0] > value[1]: + refuse("checker-internal", "attempted to render a reversed interval") + return [str(value[0]), str(value[1])] + + +def outward_decimal_interval( + lower: Fraction, upper: Fraction, places: int +) -> list[str]: + scale = 10**places + scaled_lower = lower * scale + scaled_upper = upper * scale + lower_integer = scaled_lower.numerator // scaled_lower.denominator + upper_integer = -((-scaled_upper.numerator) // scaled_upper.denominator) + + def render(value: int) -> str: + sign = "-" if value < 0 else "" + digits = str(abs(value)).rjust(places + 1, "0") + return f"{sign}{digits[:-places]}.{digits[-places:]}" + + return [render(lower_integer), render(upper_integer)] + + +def exp_positive_bound(value: Fraction) -> tuple[Fraction, Fraction]: + if value < 0: + refuse("checker-internal", "positive exponential helper received a negative input") + halvings = 0 + reduced = value + while reduced > Fraction(1, 2): + reduced /= 2 + halvings += 1 + if halvings > 32: + refuse("exp-budget", "exponential range reduction budget exceeded") + term = Fraction(1) + partial = Fraction(1) + for index in range(1, EXP_TAYLOR_DEGREE + 1): + term *= reduced / index + partial += term + next_term = term * reduced / (EXP_TAYLOR_DEGREE + 1) + ratio = reduced / (EXP_TAYLOR_DEGREE + 2) + upper = partial + next_term / (1 - ratio) + lower = partial + lower, upper = outward_dyadic(lower, upper) + for _ in range(halvings): + lower, upper = outward_dyadic(lower * lower, upper * upper) + return lower, upper + + +def exp_bound(value: Fraction) -> tuple[Fraction, Fraction]: + if value >= 0: + return exp_positive_bound(value) + lower, upper = exp_positive_bound(-value) + return outward_dyadic(1 / upper, 1 / lower) + + +def outward_dyadic(lower: Fraction, upper: Fraction) -> tuple[Fraction, Fraction]: + """Round an established enclosure outward to a fixed exact dyadic grid.""" + if lower > upper: + refuse("checker-internal", "attempted to round a reversed enclosure") + scale = 1 << EXP_DYADIC_BITS + lower_scaled = lower * scale + upper_scaled = upper * scale + lower_integer = lower_scaled.numerator // lower_scaled.denominator + upper_integer = -((-upper_scaled.numerator) // upper_scaled.denominator) + return Fraction(lower_integer, scale), Fraction(upper_integer, scale) + + +def validate_density_polynomial( + q: list[Fraction], density: list[Fraction] +) -> Fraction: + """Bound |exp(q(s))-density(s)| by an exact Gronwall calculation.""" + initial_lower, initial_upper = exp_bound(q[0]) + initial_error = max( + abs(density[0] - initial_lower), abs(density[0] - initial_upper) + ) + q_derivative = poly_derivative(q) + defect = poly_add( + poly_derivative(density), + poly_scale(poly_mul(q_derivative, density), Fraction(-1)), + ) + integrated_defect_bound = poly_abs_sum(defect) + logarithmic_variation = poly_abs_sum(q_derivative) + growth = exp_bound(logarithmic_variation)[1] + return (initial_error + integrated_defect_bound) * growth + + +def parse_piece(value: object, context: str) -> dict[str, object]: + piece = exact_keys( + value, + {"origin", "step", "coefficients", "density_coefficients"}, + context, + ) + origin = rational(piece["origin"], f"{context}.origin") + step = rational(piece["step"], f"{context}.step") + raw_coefficients = piece["coefficients"] + if ( + not isinstance(raw_coefficients, list) + or not 3 <= len(raw_coefficients) <= MAX_POLYNOMIAL_DEGREE + 1 + ): + refuse("polynomial-budget", f"{context} polynomial degree is outside the budget") + coefficients = [ + rational(item, f"{context}.coefficients[{index}]") + for index, item in enumerate(raw_coefficients) + ] + raw_density = piece["density_coefficients"] + if ( + not isinstance(raw_density, list) + or not 2 <= len(raw_density) <= MAX_POLYNOMIAL_DEGREE + 1 + ): + refuse("polynomial-budget", f"{context} density polynomial is outside the budget") + density = [ + rational(item, f"{context}.density_coefficients[{index}]") + for index, item in enumerate(raw_density) + ] + return { + "origin": origin, + "step": step, + "coefficients": coefficients, + "density_coefficients": density, + } + + +def parse_chain(value: object, name: str) -> list[dict[str, object]]: + if not isinstance(value, list) or not value or len(value) > MAX_PIECES: + refuse("piece-budget", f"{name} is not a nonempty bounded piece list") + return [parse_piece(piece, f"{name}[{index}]") for index, piece in enumerate(value)] + + +def endpoint(piece: dict[str, object]) -> tuple[Fraction, Fraction, Fraction]: + origin = piece["origin"] + step = piece["step"] + coefficients = piece["coefficients"] + assert isinstance(origin, Fraction) and isinstance(step, Fraction) + assert isinstance(coefficients, list) + value = poly_at_one(coefficients) + derivative = poly_at_one(poly_derivative(coefficients)) / step + return origin + step, value, derivative + + +def validate_chain( + chain: list[dict[str, object]], start: Fraction, stop: Fraction, direction: int, name: str +) -> None: + expected_origin = start + prior_value: Fraction | None = None + prior_derivative: Fraction | None = None + for index, piece in enumerate(chain): + origin = piece["origin"] + step = piece["step"] + coefficients = piece["coefficients"] + assert isinstance(origin, Fraction) and isinstance(step, Fraction) + assert isinstance(coefficients, list) + if origin != expected_origin or step * direction <= 0: + refuse("piece-coverage", f"{name}[{index}] does not continue the chain") + if prior_value is not None and ( + coefficients[0] != prior_value + or coefficients[1] / step != prior_derivative + ): + refuse("piece-continuity", f"{name}[{index}] is not C1-continuous") + expected_origin, prior_value, prior_derivative = endpoint(piece) + if expected_origin != stop: + refuse("piece-coverage", f"{name} does not end at its declared boundary") + + +def laurent_add(target: dict[int, Fraction], exponent: int, value: Fraction) -> None: + target[exponent] = target.get(exponent, Fraction(0)) + value + if target[exponent] == 0: + del target[exponent] + + +def tail_residual_bound( + coefficients: list[Fraction], eigenvalue: Fraction, right: Fraction +) -> tuple[Fraction, Fraction, Fraction]: + epsilon = Fraction(1, 20) + w = {2 * index - 3: value for index, value in enumerate(coefficients)} + derivative: dict[int, Fraction] = {} + for exponent, value in w.items(): + laurent_add(derivative, exponent + 1, -exponent * value) + square: dict[int, Fraction] = {} + for left_power, left_value in w.items(): + for right_power, right_value in w.items(): + laurent_add(square, left_power + right_power, left_value * right_value) + residual: dict[int, Fraction] = {} + for exponent, value in derivative.items(): + laurent_add(residual, exponent, -epsilon * epsilon * value) + for exponent, value in square.items(): + laurent_add(residual, exponent, -epsilon * epsilon * value) + laurent_add(residual, -6, Fraction(1)) + laurent_add(residual, -4, Fraction(-5)) + laurent_add(residual, -2, Fraction(4)) + laurent_add(residual, 0, -eigenvalue) + if residual and min(residual) < 0: + refuse("tail-recurrence", "tail recurrence leaves an uncancelled growing term") + y_max = 1 / right + absolute_residual = sum( + (abs(value) * y_max**exponent for exponent, value in residual.items()), + Fraction(0), + ) + + # w'(x) = sum -p*a_p*y^(p+1). The leading term is -60/y^2. + derivative_upper = Fraction(-60) / (y_max * y_max) + for exponent, value in derivative.items(): + if exponent == -2: + continue + contribution = value * y_max**exponent + if contribution > 0: + derivative_upper += contribution + if derivative_upper >= 0: + refuse("tail-monotonicity", "tail logarithmic derivative is not proved decreasing") + w_at_right = sum( + (value * y_max**exponent for exponent, value in w.items()), Fraction(0) + ) + if w_at_right >= 0: + refuse("tail-sign", "tail logarithmic derivative is not negative") + return absolute_residual, derivative_upper, w_at_right + + +def potential_polynomial(origin: Fraction, step: Fraction) -> list[Fraction]: + x = [origin, step] + return poly_add( + poly_add(poly_pow(x, 6), poly_scale(poly_pow(x, 4), Fraction(-5))), + poly_scale(poly_pow(x, 2), Fraction(4)), + ) + + +def exponential_moment_tail_upper( + power: int, + right: Fraction, + decay_rate: Fraction, + amplitude_upper: Fraction, +) -> Fraction: + """Bound ``integral_right^infinity x^power amplitude*exp(-rate*t)``.""" + if power < 0 or decay_rate <= 0 or amplitude_upper <= 0: + refuse("checker-internal", "exponential tail moment inputs are invalid") + moment = sum( + ( + Fraction(comb(power, index) * factorial(index)) + * right ** (power - index) + / decay_rate ** (index + 1) + for index in range(power + 1) + ), + Fraction(0), + ) + return amplitude_upper * moment + + +def raw_density_moment_interval( + pieces: list[dict[str, object]], + exponentials: list[tuple[list[Fraction], Fraction]], + power: int, + right: Fraction, + tail_decay_rate: Fraction, + tail_amplitude_upper: Fraction, +) -> Interval: + half_interval: Interval = (Fraction(0), Fraction(0)) + for piece, (density, density_error) in zip(pieces, exponentials, strict=True): + origin = piece["origin"] + step = piece["step"] + assert isinstance(origin, Fraction) and isinstance(step, Fraction) + weight = poly_pow([origin, step], power) + weight_integral = poly_integral_unit(weight) + if weight_integral < 0: + refuse("checker-internal", "nonnegative moment weight integrated negative") + nominal = abs(step) * poly_product_integral_unit(weight, density) + allowance = abs(step) * density_error * weight_integral + lower = max(Fraction(0), nominal - allowance) + upper = nominal + allowance + if upper < lower: + refuse("diagnostic-moment", "piece moment enclosure is reversed") + half_interval = interval_add(half_interval, (lower, upper)) + tail_upper = exponential_moment_tail_upper( + power, right, tail_decay_rate, tail_amplitude_upper + ) + return 2 * half_interval[0], 2 * (half_interval[1] + tail_upper) + + +def raw_quartic_interval( + pieces: list[dict[str, object]], + exponentials: list[tuple[list[Fraction], Fraction]], + tail_q: Fraction, + tail_w: Fraction, +) -> Interval: + half_interval: Interval = (Fraction(0), Fraction(0)) + for index, (piece, (density, density_error)) in enumerate( + zip(pieces, exponentials, strict=True) + ): + step = piece["step"] + assert isinstance(step, Fraction) + lower_density = list(density) + upper_density = list(density) + lower_density[0] -= density_error + upper_density[0] += density_error + if min(power_to_bernstein(lower_density)) <= 0: + refuse( + "diagnostic-density-positivity", + f"piece {index} does not prove a positive density lower bound", + ) + lower = abs(step) * poly_product_integral_unit( + lower_density, lower_density + ) + upper = abs(step) * poly_product_integral_unit( + upper_density, upper_density + ) + if lower < 0 or upper < lower: + refuse("diagnostic-quartic", "piece quartic enclosure is invalid") + half_interval = interval_add(half_interval, (lower, upper)) + tail_upper = exp_bound(2 * tail_q)[1] / (-4 * tail_w) + return 2 * half_interval[0], 2 * (half_interval[1] + tail_upper) + + +def raw_kinetic_integral_interval( + pieces: list[dict[str, object]], + exponentials: list[tuple[list[Fraction], Fraction]], + tail: list[Fraction], + right: Fraction, + tail_q: Fraction, + tail_w: Fraction, +) -> Interval: + half_interval: Interval = (Fraction(0), Fraction(0)) + for piece, (density, density_error) in zip(pieces, exponentials, strict=True): + step = piece["step"] + q = piece["coefficients"] + assert isinstance(step, Fraction) and isinstance(q, list) + q_x = poly_scale(poly_derivative(q), 1 / step) + weight = poly_mul(q_x, q_x) + weight_integral = poly_integral_unit(weight) + nominal = abs(step) * poly_product_integral_unit(weight, density) + allowance = abs(step) * density_error * weight_integral + lower = max(Fraction(0), nominal - allowance) + upper = nominal + allowance + if weight_integral < 0 or upper < lower: + refuse("diagnostic-kinetic", "piece kinetic enclosure is invalid") + half_interval = interval_add(half_interval, (lower, upper)) + + w = {2 * index - 3: value for index, value in enumerate(tail)} + w_square: dict[int, Fraction] = {} + for left_power, left_value in w.items(): + for right_power, right_value in w.items(): + laurent_add( + w_square, left_power + right_power, left_value * right_value + ) + tail_amplitude_upper = exp_bound(tail_q)[1] + decay_rate = -2 * tail_w + tail_mass_upper = tail_amplitude_upper / decay_rate + tail_w_square_upper = Fraction(0) + for y_power, coefficient in w_square.items(): + x_power = -y_power + if x_power >= 0: + weighted_tail = exponential_moment_tail_upper( + x_power, right, decay_rate, tail_amplitude_upper + ) + else: + weighted_tail = right**x_power * tail_mass_upper + tail_w_square_upper += abs(coefficient) * weighted_tail + + # q' = 2*w, so q'^2 = 4*w^2. + return 2 * half_interval[0], 2 * ( + half_interval[1] + 4 * tail_w_square_upper + ) + + +def compute_trial_and_ground_diagnostics( + *, + pieces: list[dict[str, object]], + exponentials: list[tuple[list[Fraction], Fraction]], + normalization: Interval, + tail: list[Fraction], + right: Fraction, + tail_q: Fraction, + tail_w: Fraction, + eigenvalue_interval: Interval, + quotient_residual_radius: Fraction, +) -> tuple[dict[str, object], dict[str, object]]: + epsilon = Fraction(1, 20) + coupling = Fraction(7, 10) + tail_amplitude_upper = exp_bound(tail_q)[1] + tail_decay_rate = -2 * tail_w + + raw_moments = { + power: raw_density_moment_interval( + pieces, + exponentials, + power, + right, + tail_decay_rate, + tail_amplitude_upper, + ) + for power in (2, 4, 6) + } + moments = { + power: interval_divide_positive(raw, normalization) + for power, raw in raw_moments.items() + } + raw_quartic = raw_quartic_interval( + pieces, exponentials, tail_q, tail_w + ) + normalization_squared = interval_square_positive(normalization) + quartic = interval_divide_positive(raw_quartic, normalization_squared) + raw_q_derivative_squared = raw_kinetic_integral_interval( + pieces, exponentials, tail, right, tail_q, tail_w + ) + kinetic = interval_scale( + interval_divide_positive(raw_q_derivative_squared, normalization), + epsilon * epsilon / 4, + ) + potential = interval_add( + interval_add(moments[6], interval_scale(moments[4], Fraction(-5))), + interval_scale(moments[2], Fraction(4)), + ) + energy = interval_add( + interval_add(kinetic, potential), + interval_scale(quartic, coupling / 2), + ) + eigenvalue_from_energy = interval_add( + energy, interval_scale(quartic, coupling / 2) + ) + energy_identity_residual = interval_sub( + eigenvalue_interval, eigenvalue_from_energy + ) + virial_residual = interval_add( + interval_add( + interval_add( + interval_scale(kinetic, Fraction(2)), + interval_scale(moments[6], Fraction(-6)), + ), + interval_scale(moments[4], Fraction(20)), + ), + interval_add( + interval_scale(moments[2], Fraction(-8)), + interval_scale(quartic, coupling / 2), + ), + ) + if not ( + energy_identity_residual[0] <= 0 <= energy_identity_residual[1] + and max(map(abs, energy_identity_residual)) < MAX_TRIAL_IDENTITY_ABS + ): + refuse( + "diagnostic-energy-identity", + "trial energy/eigenvalue identity residual misses its exact-rational gate", + ) + if not ( + virial_residual[0] <= 0 <= virial_residual[1] + and max(map(abs, virial_residual)) < MAX_TRIAL_VIRIAL_ABS + ): + refuse( + "diagnostic-virial", + "trial virial residual misses its exact-rational gate", + ) + + density_distance_squared_upper = ( + 4 * quotient_residual_radius / coupling + ) + density_distance_upper = sqrt_fraction_bound( + density_distance_squared_upper + )[1] + if density_distance_upper >= MAX_DENSITY_L2_DISTANCE: + refuse( + "ground-transfer-distance", + "strong-convexity density transfer is too wide to admit", + ) + trial_density_norm = sqrt_fraction_bound(quartic[0])[0], sqrt_fraction_bound( + quartic[1] + )[1] + ground_density_norm_lower = max( + Fraction(0), trial_density_norm[0] - density_distance_upper + ) + ground_density_norm_upper = trial_density_norm[1] + density_distance_upper + ground_quartic = ( + ground_density_norm_lower * ground_density_norm_lower, + ground_density_norm_upper * ground_density_norm_upper, + ) + ground_energy = interval_sub( + eigenvalue_interval, interval_scale(ground_quartic, coupling / 2) + ) + + trial = { + "schema": "jackal-hellgate-trial-diagnostics-v1", + "status": "bounded", + "subject": "normalized-certificate-trial-phi", + "quartic_norm_interval": interval_text(quartic), + "quartic_norm_decimal_interval": outward_decimal_interval( + quartic[0], quartic[1], 18 + ), + "moment_intervals": { + "x2": interval_text(moments[2]), + "x4": interval_text(moments[4]), + "x6": interval_text(moments[6]), + }, + "moment_decimal_intervals": { + "x2": outward_decimal_interval(moments[2][0], moments[2][1], 18), + "x4": outward_decimal_interval(moments[4][0], moments[4][1], 18), + "x6": outward_decimal_interval(moments[6][0], moments[6][1], 18), + }, + "kinetic_energy_interval": interval_text(kinetic), + "kinetic_energy_decimal_interval": outward_decimal_interval( + kinetic[0], kinetic[1], 18 + ), + "energy_functional_interval": interval_text(energy), + "energy_functional_decimal_interval": outward_decimal_interval( + energy[0], energy[1], 18 + ), + "energy_eigenvalue_identity_residual_interval": interval_text( + energy_identity_residual + ), + "energy_eigenvalue_identity_residual_decimal_interval": ( + outward_decimal_interval( + energy_identity_residual[0], + energy_identity_residual[1], + 21, + ) + ), + "virial_residual_interval": interval_text(virial_residual), + "virial_residual_decimal_interval": outward_decimal_interval( + virial_residual[0], virial_residual[1], 21 + ), + "assumptions": [ + "the Bernstein convex-hull property bounds each power-basis density polynomial on the unit interval", + "the proved decreasing negative tail logarithmic derivative gives the declared exponential-moment tail majorants", + ], + "non_claims": [ + "these diagnostics enclose the normalized certificate trial phi, not the exact ground state u0", + "a narrow trial virial or energy-identity residual does not by itself transfer trial moments to u0", + "bounded is not formal-bounded; the diagnostic integration is exact-rational Python outside the Lean and SPARK certificate chains", + ], + } + ground = { + "schema": "jackal-hellgate-ground-transfer-v1", + "status": "bounded", + "subject": "positive-normalized-ground-state-u0", + "method": "lambda-strong-convexity-density-transfer-v1", + "derivation": [ + "strong convexity gives (lambda/2)*norm(rho_phi-rho_0,L2)^2 <= -integral((R_phi-c)*(rho_0-rho_phi))", + "the mass constraint cancels c and nonnegative mass-one densities give norm(rho_phi-rho_0,L1) <= 2", + "the global quotient residual therefore gives norm(rho_phi-rho_0,L2)^2 <= 4*delta/lambda", + "the reverse triangle inequality transfers the density L2 norm, whose square is integral(u^4)", + ], + "density_l2_distance_squared_upper": str( + density_distance_squared_upper + ), + "density_l2_distance_upper": str(density_distance_upper), + "density_l2_distance_decimal_upper": outward_decimal_interval( + density_distance_upper, density_distance_upper, 18 + )[1], + "quartic_norm_interval": interval_text(ground_quartic), + "quartic_norm_decimal_interval": outward_decimal_interval( + ground_quartic[0], ground_quartic[1], 18 + ), + "energy_functional_interval": interval_text(ground_energy), + "energy_functional_decimal_interval": outward_decimal_interval( + ground_energy[0], ground_energy[1], 18 + ), + "assumptions": [ + "the mass-one density energy is lambda-strongly convex in L2 because Fisher information is convex and lambda/2 times integral rho^2 supplies the modulus", + "the nonlinear quotient is the density energy first variation and its global residual radius is valid", + "both rho_phi and rho_0 are nonnegative mass-one finite-energy densities", + ], + "non_claims": [ + "the transfer encloses the ground-state quartic norm and energy functional only", + "the transfer does not enclose polynomial moments, lambda sensitivity, tunneling, or Bogoliubov frequencies", + "the strong-convexity theorem is stated and applied by the checker but is not Lean- or SPARK-proved here", + ], + } + return trial, ground + + +def verify_document(document: object) -> dict[str, object]: + root = exact_keys( + document, + { + "schema", + "problem", + "representation", + "center_eigenvalue", + "right_endpoint", + "match_point", + "tail_terms", + "tail_coefficients", + "forward_pieces", + "backward_pieces", + "nonclaims", + "certificate_sha256", + }, + "certificate", + ) + if root["schema"] != SCHEMA or root["representation"] != "piecewise-log-density-power-v1": + refuse("certificate-schema", "certificate schema or representation is unsupported") + problem = exact_keys( + root["problem"], + {"epsilon", "lambda", "potential", "mass", "parity", "positivity"}, + "problem", + ) + expected_problem = { + "epsilon": "1/20", + "lambda": "7/10", + "potential": "x^6-5*x^4+4*x^2", + "mass": "1", + "parity": "even", + "positivity": "strict", + } + if problem != expected_problem: + refuse("unsupported-problem", "certificate is not for the fixed HELLGATE problem") + supplied_digest = root["certificate_sha256"] + if not isinstance(supplied_digest, str) or SHA256.fullmatch(supplied_digest) is None: + refuse("certificate-digest", "certificate digest is malformed") + digest_document = {key: value for key, value in root.items() if key != "certificate_sha256"} + actual_digest = hashlib.sha256(canonical_bytes(digest_document)).hexdigest() + if not hmac.compare_digest(actual_digest, supplied_digest): + refuse("certificate-digest", "certificate self-digest mismatch") + + eigenvalue = rational(root["center_eigenvalue"], "center_eigenvalue") + right = rational(root["right_endpoint"], "right_endpoint") + match = rational(root["match_point"], "match_point") + if not Fraction(0) < match < right: + refuse("certificate-domain", "match and right endpoints are not ordered") + tail_terms = root["tail_terms"] + if ( + isinstance(tail_terms, bool) + or not isinstance(tail_terms, int) + or not 8 <= tail_terms <= MAX_TAIL_TERMS + ): + refuse("tail-budget", "tail term count is outside the closed budget") + raw_tail = root["tail_coefficients"] + if not isinstance(raw_tail, list) or len(raw_tail) != tail_terms: + refuse("tail-shape", "tail coefficient list does not match tail_terms") + tail = [ + rational(value, f"tail_coefficients[{index}]") + for index, value in enumerate(raw_tail) + ] + nonclaims = root["nonclaims"] + expected_nonclaims = [ + "producer arithmetic is untrusted until independent exact-rational replay accepts", + "certificate is specific to the declared HELLGATE parameters", + "bounded is not formal-bounded; no Lean theorem checks this certificate", + ] + if nonclaims != expected_nonclaims: + refuse("certificate-nonclaims", "certificate nonclaims were weakened or changed") + + forward = parse_chain(root["forward_pieces"], "forward_pieces") + backward = parse_chain(root["backward_pieces"], "backward_pieces") + validate_chain(forward, Fraction(0), match, 1, "forward_pieces") + validate_chain(backward, right, match, -1, "backward_pieces") + first_coefficients = forward[0]["coefficients"] + assert isinstance(first_coefficients, list) + if first_coefficients[1] != 0: + refuse("even-boundary", "trial log-density derivative is not zero at the origin") + _, forward_value, forward_derivative = endpoint(forward[-1]) + _, backward_value, backward_derivative = endpoint(backward[-1]) + if forward_value != backward_value or forward_derivative != backward_derivative: + refuse("match-continuity", "forward and backward trial chains do not meet C1") + + tail_linear_error, _, tail_w = tail_residual_bound(tail, eigenvalue, right) + backward_origin = backward[0] + backward_coefficients = backward_origin["coefficients"] + backward_step = backward_origin["step"] + assert isinstance(backward_coefficients, list) and isinstance(backward_step, Fraction) + if backward_coefficients[1] / backward_step != 2 * tail_w: + refuse("tail-continuity", "interior trial derivative does not match the tail") + tail_q = backward_coefficients[0] + + pieces = forward + backward + exponentials: list[tuple[list[Fraction], Fraction]] = [] + half_mass_lower = Fraction(0) + half_mass_upper = Fraction(0) + for index, piece in enumerate(pieces): + coefficients = piece["coefficients"] + density_polynomial = piece["density_coefficients"] + step = piece["step"] + assert ( + isinstance(coefficients, list) + and isinstance(density_polynomial, list) + and isinstance(step, Fraction) + ) + polynomial = density_polynomial + error = validate_density_polynomial(coefficients, polynomial) + integral = abs(step) * sum( + (value / (power + 1) for power, value in enumerate(polynomial)), + Fraction(0), + ) + allowance = abs(step) * error + lower = integral - allowance + if lower <= 0: + refuse("normalization-lower", f"piece {index} has no positive mass lower bound") + half_mass_lower += lower + half_mass_upper += integral + allowance + exponentials.append((polynomial, error)) + + tail_exp_upper = exp_bound(tail_q)[1] + tail_mass_upper = tail_exp_upper / (-2 * tail_w) + normalization_lower = 2 * half_mass_lower + normalization_upper = 2 * (half_mass_upper + tail_mass_upper) + if not normalization_lower > 0 or normalization_lower > normalization_upper: + refuse("normalization", "normalization enclosure is invalid") + inverse_lower = 1 / normalization_upper + inverse_upper = 1 / normalization_lower + inverse_center = (inverse_lower + inverse_upper) / 2 + inverse_error = max(inverse_center - inverse_lower, inverse_upper - inverse_center) + + epsilon = Fraction(1, 20) + coupling = Fraction(7, 10) + residual_radius = Fraction(0) + for piece, (density_poly, density_error) in zip(pieces, exponentials, strict=True): + origin = piece["origin"] + step = piece["step"] + q = piece["coefficients"] + assert isinstance(origin, Fraction) and isinstance(step, Fraction) + assert isinstance(q, list) + q_x = poly_scale(poly_derivative(q), 1 / step) + q_xx = poly_scale(poly_derivative(q_x), 1 / step) + residual = poly_scale(q_xx, -epsilon * epsilon / 2) + residual = poly_add( + residual, poly_scale(poly_mul(q_x, q_x), -epsilon * epsilon / 4) + ) + residual = poly_add(residual, potential_polynomial(origin, step)) + residual[0] -= eigenvalue + residual = poly_add( + residual, poly_scale(density_poly, coupling * inverse_center) + ) + normalization_error = coupling * ( + density_error * inverse_upper + + poly_abs_sum(density_poly) * inverse_error + ) + piece_radius = poly_abs_sum(residual) + normalization_error + residual_radius = max(residual_radius, piece_radius) + + tail_nonlinear = coupling * tail_exp_upper * inverse_upper + residual_radius = max(residual_radius, tail_linear_error + tail_nonlinear) + eigen_lower = eigenvalue - residual_radius + eigen_upper = eigenvalue + residual_radius + width = 2 * residual_radius + if width >= MAX_EIGENVALUE_WIDTH: + refuse( + "target-width", + "exact-rational quotient enclosure does not meet the HELLGATE width requirement", + ) + trial_diagnostics, ground_transfer = compute_trial_and_ground_diagnostics( + pieces=pieces, + exponentials=exponentials, + normalization=(normalization_lower, normalization_upper), + tail=tail, + right=right, + tail_q=tail_q, + tail_w=tail_w, + eigenvalue_interval=(eigen_lower, eigen_upper), + quotient_residual_radius=residual_radius, + ) + return { + "schema": RESULT_SCHEMA, + "status": "bounded", + "lane": "nonlinear-barta-exact-rational-v1", + "formal": False, + "checker_verdict": "ACCEPT", + "parsed": "epsilon=1/20; lambda=7/10; V=x^6-5*x^4+4*x^2; mass=1; positive-even-ground-state", + "fields": { + "eigenvalue_interval": [str(eigen_lower), str(eigen_upper)], + "eigenvalue_decimal_interval": outward_decimal_interval( + eigen_lower, eigen_upper, 18 + ), + "interval_width": str(width), + "center_eigenvalue": str(eigenvalue), + "quotient_residual_radius": str(residual_radius), + "normalization_interval": [ + str(normalization_lower), + str(normalization_upper), + ], + "certificate_sha256": supplied_digest, + "piece_count": len(pieces), + "tail_terms": tail_terms, + "trial_diagnostics": trial_diagnostics, + "ground_state_transfer": ground_transfer, + }, + "theorem": { + "name": "normalized defocusing nonlinear Barta comparison", + "statement": "For lambda>=0, a positive normalized trial phi with quotient R=(-epsilon^2 phi''+V phi+lambda phi^3)/phi in [a,b] encloses the positive normalized ground-state eigenvalue E in [a,b].", + "application": "phi=exp(q/2)/sqrt(integral exp(q)); exact-rational piece and tail bounds enclose R globally.", + }, + "assumptions": [ + "the normalized defocusing nonlinear Barta comparison theorem is valid for positive C1 piecewise-C2 trials with the stated confining potential", + "the stated lambda-strong-convexity density-transfer argument is valid for the admitted finite-energy densities", + "Python arbitrary-precision integer, Fraction, and integer-square-root operations implement their documented exact arithmetic", + ], + "non_claims": expected_nonclaims + + [ + "checker acceptance does not establish implementation correctness of the Python interpreter", + "checker acceptance encloses E0 plus the explicitly scoped ground-state quartic norm and energy-functional transfer only", + "reported polynomial moments and consistency residuals belong to the certificate trial phi, not the exact ground state u0", + "ground-state polynomial moments, lambda sensitivity, tunneling, and Bogoliubov frequencies require separate certificates", + ], + } + + +def verify_bytes(raw: bytes) -> dict[str, object]: + return verify_document(strict_json(raw)) + + +def refusal_body(error: VerificationRefusal) -> dict[str, object]: + return { + "schema": RESULT_SCHEMA, + "status": "refused", + "reason": error.reason, + "detail": error.detail, + "formal": False, + "non_claims": [ + "a refusal is an answer and no weaker numerical lane was substituted", + "no eigenvalue enclosure was established", + ], + } + + +def main() -> int: + if len(sys.argv) != 2: + print("usage: hellgate_verify.py CERTIFICATE.json", file=sys.stderr) + return 2 + path = Path(sys.argv[1]) + try: + raw = path.read_bytes() + result = verify_bytes(raw) + except VerificationRefusal as error: + result = refusal_body(error) + except OSError as error: + result = refusal_body(VerificationRefusal("certificate-io", str(error))) + print(json.dumps(result, sort_keys=True, separators=(",", ":"))) + return 0 if result["status"] == "bounded" else 1 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/plugins/jackel/mcp/measurement.py b/plugins/jackel/mcp/measurement.py new file mode 100644 index 0000000..49eecda --- /dev/null +++ b/plugins/jackel/mcp/measurement.py @@ -0,0 +1,1341 @@ +#!/usr/bin/python3 -B +"""Identity-pinned measurement and provenance tools for the JACKAL MCP server. + +This module is not a standalone service. The identity-pinned JACKAL wrapper +loads it in-process and supplies a callback into the same serialized runtime +backend used by every other JACKAL tool. Each arithmetic result is echoed in +``delegated_to``. If the runtime is unavailable or refuses, this layer refuses; +it never substitutes Python floating-point arithmetic. + +WHAT THIS SUBSYSTEM ADDS — the gap it closes: + +JACKAL is airtight on numerals that ANNOUNCE THEMSELVES as arithmetic. The +leak is the numerals that do not: unit conversions, percentages, date deltas, +currency comparisons. Each of those is an exact computation resting on a datum +that is NOT mathematics — a conversion factor, a tz rule, an exchange rate. +The arithmetic deserves `exact`; the datum deserves scrutiny. Collapsing the +two in either direction is a lie: + + - calling a currency conversion `exact` launders the rate into mathematics + - calling it `estimated` slanders arithmetic that is, in fact, exact + +The subsystem introduces one status class, and only one: + + exact-given — exact rational arithmetic, CONDITIONAL on a declared datum + that is carried in the result and is NOT verified by JACKAL. + +`given` is a required, structured field on every such result. A datum with no +source and no as-of date is refused at the door. That is the whole point: the +tool makes declaring provenance the only way to get an answer at all. + +`exact-given` is NOT a rung below `exact`, in the same way that `exact` and +`formal-bounded` are not rungs. It names a different shape of claim. +""" + +import datetime +import decimal +import json +import re +import sys +from fractions import Fraction +from typing import Callable + +# Everything this subsystem says about the world is informational. Even a formal-bounded +# enclosure of a standard deviation says nothing about whether the sample was +# collected correctly, and no conversion says anything about whether the +# quantity was measured correctly. The ceiling never rises above this. +CONSEQUENCE_CEILING = "informational" + +UNIVERSAL_NON_CLAIMS = [ + "The JACKAL measurement orchestrator is identity-pinned but remains outside the Lean certificate chain", + "The measurement orchestrator performs no arithmetic of its own: every arithmetic result here was produced by a delegated JACKAL runtime call recorded in `delegated_to`; library metadata such as calendar ordinals, collection counts, and lexical offsets is not an arithmetic claim", + "The epistemic class above is the STRONGEST claim this result supports", +] + + +class Refusal(Exception): + """A named refusal. Carried to the client as a result, never as an error. + + A refusal is an answer. Raising it through the JSON-RPC error channel would + invite the client to treat it as a transport failure and retry, and retrying + a refusal on a weaker lane until something answers is precisely the move the + kernel's discipline forbids. + """ + + def __init__(self, reason: str, detail: str, non_claims: list[str] | None = None): + super().__init__(detail) + self.reason = reason + self.detail = detail + self.non_claims = non_claims or [] + + +# Set only for the duration of one serialized call by ``dispatch_integrated``. +# There is intentionally no child-process fallback in this module. +JACKAL: object | None = None +_ACTIVE_IDENTITY: str | None = None + + +def _active_identity() -> str: + if _ACTIVE_IDENTITY is None: + raise RuntimeError("measurement identity is unavailable outside integrated dispatch") + return _ACTIVE_IDENTITY + +# Every delegated call made while serving one request, echoed into the result so +# a reader can confirm the measurement orchestrator computed nothing. Request handling is serialized +# by the single-threaded stdio loop, so a module-level list is safe here. +_TRACE: list[dict] = [] + + +def exact(expression: str) -> Fraction: + """Delegate one exact-rational computation and record the call.""" + if JACKAL is None: + raise Refusal( + "kernel-unavailable", + "the measurement module is not attached to the JACKAL runtime", + ) + out = JACKAL.call("jackal_exact", {"expression": expression}) + fields = out.get("fields", {}) + value = fields.get("exact") + if not isinstance(value, str): + raise Refusal("kernel-error", "jackal_exact returned no exact field") + _TRACE.append({ + "tool": "jackal_exact", + "parsed": fields.get("parsed", expression), + "exact": value, + "approx": fields.get("approx"), + "status": out.get("status", "unknown"), + }) + try: + return Fraction(value) + except (ValueError, ZeroDivisionError) as exc: + raise Refusal("kernel-error", f"unparseable exact value {value!r}") from exc + + +def sqrt_bound(value: Fraction) -> tuple[Fraction, Fraction]: + """Delegate a formal-bounded sqrt enclosure at a point. + + A point interval (lo == hi) is the degenerate case the certified range + checker already handles, so a scalar square root gets the SAME Lean-checked + treatment as an interval one. Nothing here approximates. + """ + if value < 0: + raise Refusal("domain", f"sqrt of a negative rational {value} is not real") + if JACKAL is None: + raise Refusal( + "kernel-unavailable", + "the measurement module is not attached to the JACKAL runtime", + ) + arg = frac_str(value) + out = JACKAL.call("jackal_sqrt_rat_bound", { + "expression": "sqrt(x)", "input_lo": arg, "input_hi": arg, + }) + text = out.get("checker_output", "") + match = re.search(r"output\s+(\S+)\s+(\S+)\s*$", text.strip()) + if not match: + raise Refusal("kernel-error", "could not read the enclosure from the checker output") + lo, hi = Fraction(match.group(1)), Fraction(match.group(2)) + _TRACE.append({ + "tool": "jackal_sqrt_rat_bound", + "parsed": f"sqrt(x) on [{arg},{arg}]", + "enclosure": [str(lo), str(hi)], + "status": out.get("status", "unknown"), + "checker_rerun": out.get("checker_rerun"), + }) + return lo, hi + + +# --------------------------------------------------------------------------- +# Envelope +# --------------------------------------------------------------------------- + +def envelope( + *, + status: str, + lane: str, + assurance: str, + parsed: str, + fields: dict, + non_claims: list[str], + given: dict | None = None, + formal: bool = False, +) -> dict: + """Build one JACKAL measurement result in the kernel's idiom. + + `parsed` is mandatory and never omitted, including for trivial input. The + dominant failure at the model/tool boundary is transcription, not + computation, so the echo is worth more than it costs on every single call. + """ + body = { + "status": status, + "lane": lane, + "assurance": assurance, + "formal": formal, + "consequence_ceiling": CONSEQUENCE_CEILING, + "parsed": parsed, + "fields": fields, + "delegated_to": list(_TRACE), + "non_claims": non_claims + UNIVERSAL_NON_CLAIMS, + "identities": {"jackal_measurement_sha256": _active_identity()}, + } + if JACKAL is not None and JACKAL.evaluator_sha256: + body["identities"]["jackal_evaluator_sha256"] = JACKAL.evaluator_sha256 + if given is not None: + body["given"] = given + return body + + +def refusal_body(reason: str, detail: str, non_claims: list[str] | None = None) -> dict: + return { + "status": "refused", + "reason": reason, + "detail": detail, + "consequence_ceiling": CONSEQUENCE_CEILING, + "non_claims": (non_claims or []) + [ + "A refusal is an answer: report it as one", + "Do NOT substitute unverified arithmetic for a refused result", + "Do NOT retry this question on a weaker lane to obtain some number", + ], + "identities": {"jackal_measurement_sha256": _active_identity()}, + } + + +def as_fraction(text: str, subject: str) -> Fraction: + """Parse a user-supplied number WITHOUT arithmetic. + + Literal parsing is transcription, not computation, so it happens here. The + moment two of these meet an operator, the expression goes to the kernel. + """ + if not isinstance(text, str) or not text.strip(): + raise Refusal("args", f"{subject} must be a non-empty string") + raw = text.strip().replace("_", "") + # Thousands separators are a transcription hazard, not a notation the measurement subsystem + # guesses at: 1,234 is one number in one locale and two in another. + if "," in raw: + raise Refusal( + "ambiguous-literal", + f"{subject} contains a comma ({text!r}); comma grouping and comma decimals are " + "indistinguishable here. Supply an unambiguous literal such as '1234' or '1234.5'.", + ) + try: + if "/" in raw: + return Fraction(raw) + return Fraction(decimal.Decimal(raw)) + except (ValueError, ArithmeticError, decimal.InvalidOperation) as exc: + raise Refusal("args", f"{subject} is not an integer, decimal, or rational: {text!r}") from exc + + +def frac_str(value: Fraction) -> str: + return str(value.numerator) if value.denominator == 1 else f"{value.numerator}/{value.denominator}" + + +def approx(value: Fraction, places: int = 12) -> str: + """Return JACKAL's decimal rendering for reading only. + + The ``places`` parameter remains for source compatibility but does not ask + Python to round or divide. JACKAL owns the rendering as well as the exact + rational. Reuse a matching delegated result when one exists; otherwise + delegate an identity expression and record it in the trace. + """ + del places + wanted = frac_str(value) + for item in reversed(_TRACE): + if item.get("tool") == "jackal_exact" and item.get("exact") == wanted: + rendered = item.get("approx") + if isinstance(rendered, str) and rendered: + return rendered + exact(wanted) + rendered = _TRACE[-1].get("approx") if _TRACE else None + if not isinstance(rendered, str) or not rendered: + raise Refusal("kernel-error", "jackal_exact returned no decimal rendering") + return rendered + + +# --------------------------------------------------------------------------- +# Definitional unit table +# +# ONLY exact-by-definition conversions appear here. Each factor is a rational +# converting the unit to its dimension's base, alongside the instrument that +# makes it exact. A unit whose factor is empirical, drifting, or transcendental +# is absent ON PURPOSE, and absence produces a refusal rather than a guess. +# +# The notable absences, each a real laundering site: +# - `year` / `month` : no exact second count. `julian_year` is exact and named. +# - `degree`/`radian` : the factor is pi/180, outside the exact-rational fragment. +# - `tonne-of-TNT`, `calorie (nutritional)` : convention-dependent. +# --------------------------------------------------------------------------- + +SI = "SI base/derived definition (BIPM SI Brochure, 9th ed.)" +YARD_POUND = "International yard and pound agreement (1959), exact by definition" +IEC = "IEC 80000-13 binary prefixes, exact by definition" + +UNITS: dict[str, dict[str, tuple[str, str]]] = { + "length": { # base: metre + "m": ("1", SI), "metre": ("1", SI), "meter": ("1", SI), + "km": ("1000", SI), "cm": ("1/100", SI), "mm": ("1/1000", SI), + "um": ("1/1000000", SI), "nm": ("1/1000000000", SI), + "in": ("0.0254", YARD_POUND), "inch": ("0.0254", YARD_POUND), + "ft": ("0.3048", YARD_POUND), "foot": ("0.3048", YARD_POUND), + "yd": ("0.9144", YARD_POUND), "yard": ("0.9144", YARD_POUND), + "mi": ("1609.344", YARD_POUND), "mile": ("1609.344", YARD_POUND), + "nmi": ("1852", "Exact by definition (BIPM/IHO international nautical mile)"), + }, + "mass": { # base: kilogram + "kg": ("1", SI), "g": ("1/1000", SI), "mg": ("1/1000000", SI), + "t": ("1000", SI), "tonne": ("1000", SI), + "lb": ("0.45359237", YARD_POUND), "pound": ("0.45359237", YARD_POUND), + "oz": ("0.45359237/16", YARD_POUND), + "st": ("0.45359237*14", YARD_POUND), "stone": ("0.45359237*14", YARD_POUND), + "short_ton": ("0.45359237*2000", YARD_POUND), + "long_ton": ("0.45359237*2240", YARD_POUND), + }, + "time": { # base: second + "s": ("1", SI), "sec": ("1", SI), "second": ("1", SI), + "ms": ("1/1000", SI), "us": ("1/1000000", SI), "ns": ("1/1000000000", SI), + "min": ("60", SI), "minute": ("60", SI), + "h": ("3600", SI), "hr": ("3600", SI), "hour": ("3600", SI), + "day": ("86400", "Exact by definition (86400 SI seconds; NOT a solar day)"), + "week": ("604800", "Exact by definition (7 x 86400 s)"), + "julian_year": ("31557600", "IAU Julian year, exact by definition (365.25 x 86400 s)"), + }, + "volume": { # base: litre + "l": ("1", SI), "litre": ("1", SI), "liter": ("1", SI), + "ml": ("1/1000", SI), "m3": ("1000", SI), + "us_gal": ("3.785411784", "US gallon = 231 cubic inches exactly (yard-and-pound)"), + "us_qt": ("3.785411784/4", "US quart = 1/4 US gallon exactly"), + "us_pt": ("3.785411784/8", "US pint = 1/8 US gallon exactly"), + "us_floz": ("3.785411784/128", "US fluid ounce = 1/128 US gallon exactly"), + "imp_gal": ("4.54609", "Imperial gallon, exact by definition (UK Weights and Measures Act 1985)"), + "imp_pt": ("4.54609/8", "Imperial pint = 1/8 imperial gallon exactly"), + "imp_floz": ("4.54609/160", "Imperial fluid ounce = 1/160 imperial gallon exactly"), + }, + "speed": { # base: metre per second + "m/s": ("1", SI), + "km/h": ("1000/3600", SI), + "mph": ("1609.344/3600", YARD_POUND), + "kn": ("1852/3600", "Knot = one nautical mile per hour, exact by definition"), + "knot": ("1852/3600", "Knot = one nautical mile per hour, exact by definition"), + }, + "energy": { # base: joule + "j": ("1", SI), "joule": ("1", SI), "kj": ("1000", SI), "mj": ("1000000", SI), + "wh": ("3600", SI), "kwh": ("3600000", SI), "mwh": ("3600000000", SI), + "cal": ("4.184", "Thermochemical calorie, exact by definition"), + "kcal": ("4184", "Thermochemical kilocalorie, exact by definition"), + "btu": ("1055.05585262", "BTU (International Table), exact by definition"), + "ev": ("1.602176634*10^-19", "SI 2019 redefinition: elementary charge is exact"), + }, + "power": { # base: watt + "w": ("1", SI), "watt": ("1", SI), "kw": ("1000", SI), "mw": ("1000000", SI), + "hp": ("550*0.3048*0.45359237*9.80665", + "Mechanical horsepower = 550 ft.lbf/s, exact via the defined standard gravity 9.80665 m/s^2"), + }, + "data": { # base: byte -- the single most productive laundering site in computing + "b": ("1", IEC), "byte": ("1", IEC), "bit": ("1/8", IEC), + "kb": ("1000", "SI decimal prefix: kB = 10^3 bytes"), + "mb": ("1000000", "SI decimal prefix: MB = 10^6 bytes"), + "gb": ("1000000000", "SI decimal prefix: GB = 10^9 bytes"), + "tb": ("1000000000000", "SI decimal prefix: TB = 10^12 bytes"), + "kib": ("1024", IEC), "mib": ("1048576", IEC), + "gib": ("1073741824", IEC), "tib": ("1099511627776", IEC), + }, +} + +# Units whose absence is deliberate, with the reason stated at the point of +# refusal. Guessing here would be the exact failure this subsystem exists to prevent. +REFUSED_UNITS = { + "year": "a calendar year has no exact second count (365 or 366 days); use `julian_year` for the exact IAU definition, or jackal_date_delta for civil dates", + "yr": "a calendar year has no exact second count; use `julian_year` or jackal_date_delta", + "month": "a calendar month has no fixed length (28-31 days); use jackal_date_delta on real dates", + "deg": "degree-to-radian requires pi, which is outside the exact-rational fragment", + "degree": "degree-to-radian requires pi, which is outside the exact-rational fragment", + "rad": "radian-to-degree requires pi, which is outside the exact-rational fragment", + "radian": "radian-to-degree requires pi, which is outside the exact-rational fragment", +} + +TEMPERATURE = {"c", "celsius", "f", "fahrenheit", "k", "kelvin", "r", "rankine"} + + +def find_unit(name: str) -> tuple[str, str, str]: + """Resolve a unit to (dimension, factor-expression, authority) or refuse.""" + key = name.strip().lower().replace("^", "").replace(" ", "") + if key in REFUSED_UNITS: + raise Refusal("undefined-unit", f"unit {name!r} is deliberately absent: {REFUSED_UNITS[key]}") + for dimension, table in UNITS.items(): + if key in table: + factor, authority = table[key] + return dimension, factor, authority + if key in TEMPERATURE: + return "temperature", "", "affine scale; handled separately" + known = sorted({u for table in UNITS.values() for u in table} | TEMPERATURE) + raise Refusal( + "undefined-unit", + f"unit {name!r} is not in the definitional table, and JACKAL does not guess conversion " + f"factors. Known units: {', '.join(known)}", + ) + + +# --------------------------------------------------------------------------- +# jackal_convert -- definitional unit conversion +# --------------------------------------------------------------------------- + +_TEMP_TO_K = { + "c": "({v}) + 273.15", "celsius": "({v}) + 273.15", + "f": "(({v}) - 32) * 5/9 + 273.15", "fahrenheit": "(({v}) - 32) * 5/9 + 273.15", + "k": "({v})", "kelvin": "({v})", + "r": "({v}) * 5/9", "rankine": "({v}) * 5/9", +} +_K_TO_TEMP = { + "c": "({v}) - 273.15", "celsius": "({v}) - 273.15", + "f": "(({v}) - 273.15) * 9/5 + 32", "fahrenheit": "(({v}) - 273.15) * 9/5 + 32", + "k": "({v})", "kelvin": "({v})", + "r": "({v}) * 9/5", "rankine": "({v}) * 9/5", +} + + +def tool_convert(args: dict) -> dict: + value_text = args.get("value") + frm = args.get("from_unit") + to = args.get("to_unit") + for name, val in (("value", value_text), ("from_unit", frm), ("to_unit", to)): + if not isinstance(val, str) or not val.strip(): + raise Refusal("args", f"{name} is required and must be a non-empty string") + value = as_fraction(value_text, "value") + from_dim, from_factor, from_auth = find_unit(frm) + to_dim, to_factor, to_auth = find_unit(to) + if from_dim != to_dim: + raise Refusal( + "dimension-mismatch", + f"cannot convert {frm!r} ({from_dim}) to {to!r} ({to_dim}); these are different " + "physical dimensions and no conversion between them exists without a declared " + "physical relation the JACKAL measurement subsystem was not given", + ) + + if from_dim == "temperature": + # Affine scales: a temperature is a point, not a magnitude, so the + # zero offsets do not cancel and a plain ratio would be wrong. + kelvin = exact(_TEMP_TO_K[frm.strip().lower()].format(v=frac_str(value))) + result = exact(_K_TO_TEMP[to.strip().lower()].format(v=frac_str(kelvin))) + auth = "Exact by definition (ITS-90 fixed offsets 273.15 and 459.67; scale factors 9/5)" + note = ("temperature is an AFFINE scale: this converts a POINT on the scale. " + "A temperature DIFFERENCE converts differently (offsets cancel).") + else: + result = exact(f"({frac_str(value)}) * ({from_factor}) / ({to_factor})") + auth = f"from: {from_auth} | to: {to_auth}" + note = None + + fields = { + "exact": frac_str(result), + "approx": approx(result), + "from": frm, "to": to, "dimension": from_dim, + "definition_authority": auth, + } + if note: + fields["scale_note"] = note + non_claims = [ + "This converts a NUMBER between units defined to be exactly related; it does not verify that the input quantity was measured correctly", + "Only definitional (exact-by-definition) conversions are in the table; empirical or convention-dependent factors are absent and refuse", + ] + if note: + non_claims.insert(0, "This is a SCALE POINT conversion, NOT a temperature difference") + return envelope( + status="exact", lane="jackal-measure-convert", + assurance="exact rational conversion between definitionally-related units (not checker-covered)", + parsed=f"{frac_str(value)} {frm} -> {to}", + fields=fields, non_claims=non_claims, + ) + + +# --------------------------------------------------------------------------- +# jackal_rate_apply -- the exact-given lane +# --------------------------------------------------------------------------- + +def tool_rate_apply(args: dict) -> dict: + """Apply a declared rate. The arithmetic is exact; the RATE is not mathematics. + + Every argument below is required, and that is the entire design. A rate with + no source and no as-of date is a number of unknown origin, and multiplying + by it silently promotes that unknown origin to the authority of the result. + Refusing at the door is what makes the provenance impossible to skip. + """ + value_text = args.get("value") + rate_text = args.get("rate") + source = args.get("rate_source") + asof = args.get("rate_asof") + frm = args.get("from_label") or "from" + to = args.get("to_label") or "to" + + missing = [n for n, v in (("value", value_text), ("rate", rate_text), + ("rate_source", source), ("rate_asof", asof)) + if not isinstance(v, str) or not v.strip()] + if missing: + raise Refusal( + "undeclared-datum", + f"missing required declaration(s): {', '.join(missing)}. A rate is a DATUM, not " + "mathematics: JACKAL will not apply one that does not carry its source and as-of " + "date, because the result would inherit an authority the rate never had.", + ) + value = as_fraction(value_text, "value") + rate = as_fraction(rate_text, "rate") + if rate <= 0: + raise Refusal("args", f"rate must be positive; got {rate_text!r}") + result = exact(f"({frac_str(value)}) * ({frac_str(rate)})") + return envelope( + status="exact-given", lane="jackal-measure-rate", + assurance="exact rational arithmetic CONDITIONAL on the declared rate below; the rate itself is unverified", + parsed=f"{frac_str(value)} {frm} x {frac_str(rate)} -> {to}", + given={ + "datum": "conversion rate", + "rate": frac_str(rate), + "rate_approx": approx(rate), + "direction": f"1 {frm} = {frac_str(rate)} {to}", + "source": source.strip(), + "as_of": asof.strip(), + }, + fields={"exact": frac_str(result), "approx": approx(result), + "from_label": frm, "to_label": to}, + non_claims=[ + "JACKAL did NOT verify the rate, its source, or its as-of date; all three are reported as supplied", + "This result is exact ONLY under the declared rate; a different rate yields a different exact result", + "`exact-given` is NOT a weaker `exact`: the arithmetic is exact and the datum is unverified. Do not report it as `exact`, and do not soften it to `estimated`", + "Rates change: an as-of date in the past does not describe the present", + ], + ) + + +# --------------------------------------------------------------------------- +# jackal_percent +# --------------------------------------------------------------------------- + +def tool_percent(args: dict) -> dict: + op = (args.get("op") or "").strip().lower() + a_text, b_text = args.get("a"), args.get("b") + if not isinstance(a_text, str) or not isinstance(b_text, str): + raise Refusal("args", "both `a` and `b` are required strings") + a, b = as_fraction(a_text, "a"), as_fraction(b_text, "b") + + ops = { + "of": ("({a}) * ({b}) / 100", "a% of b", "value"), + "change": ("(({b}) - ({a})) * 100 / ({a})", "percent change from a to b", "percent"), + "ratio": ("({a}) * 100 / ({b})", "a as a percentage of b", "percent"), + "points": ("({b}) - ({a})", "difference in PERCENTAGE POINTS between a% and b%", "percentage_points"), + "increase": ("({a}) * (1 + ({b})/100)", "a increased by b%", "value"), + "decrease": ("({a}) * (1 - ({b})/100)", "a decreased by b%", "value"), + } + if op not in ops: + raise Refusal("args", f"op must be one of {', '.join(sorted(ops))}; got {op!r}") + if op in ("change", "ratio") and (a if op == "change" else b) == 0: + raise Refusal("domain", f"op {op!r} divides by zero for the given inputs") + + template, meaning, unit = ops[op] + result = exact(template.format(a=frac_str(a), b=frac_str(b))) + non_claims = [ + "A percentage is meaningless without its base; the base used here is exactly as supplied", + ] + if op in ("change", "ratio", "points"): + non_claims.insert(0, + "PERCENT vs PERCENTAGE POINTS are different quantities and are routinely conflated: " + "`change`/`ratio` return PERCENT (relative), `points` returns PERCENTAGE POINTS (absolute). " + f"This result is in {unit.upper()}.") + if op == "change": + non_claims.append( + "Percent change is asymmetric: a rise of x% followed by a fall of x% does not return to the start") + return envelope( + status="exact", lane="jackal-measure-percent", + assurance="exact rational arithmetic (not checker-covered)", + parsed=f"{op}(a={frac_str(a)}, b={frac_str(b)}) = {meaning}", + fields={"exact": frac_str(result), "approx": approx(result), + "result_unit": unit, "meaning": meaning}, + non_claims=non_claims, + ) + + +# --------------------------------------------------------------------------- +# jackal_date_delta -- civil-date arithmetic +# --------------------------------------------------------------------------- + +CALENDAR = "proleptic Gregorian" + + +def _civil_date(text: str, subject: str) -> datetime.date: + if not isinstance(text, str) or not re.fullmatch(r"\d{4}-\d{2}-\d{2}", text.strip()): + raise Refusal( + "args", + f"{subject} must be an ISO civil date YYYY-MM-DD; got {text!r}. This JACKAL lane takes civil " + "dates only: a wall-clock time carries a timezone, and a timezone is a datum " + "(tzdata rules, DST transitions) that this lane does not accept.", + ) + try: + return datetime.date.fromisoformat(text.strip()) + except ValueError as exc: + raise Refusal("args", f"{subject} is not a real calendar date: {text!r} ({exc})") from exc + + +def tool_date_delta(args: dict) -> dict: + op = (args.get("op") or "").strip().lower() + given = { + "datum": "calendar convention", + "calendar": CALENDAR, + "day_length": "one civil day, NOT 86400 SI seconds", + "excludes": "timezones, DST transitions, leap seconds", + "source": "Python datetime.date proleptic-Gregorian calendar semantics", + "as_of": "JACKAL measurement definition 1.1.0 (this convention is not time-varying)", + } + non_claims = [ + "Civil-date arithmetic ONLY: no timezone, no DST, no leap seconds, no wall-clock times", + "A civil day is not a fixed number of seconds; do not convert this result to seconds by multiplying by 86400 unless that assumption is stated", + f"Dates before the 1582 Gregorian adoption are interpreted {CALENDAR}ly and will NOT match historical Julian records", + "`exact-given` is NOT a weaker `exact`: the day count is exact under the declared calendar convention", + ] + + if op == "diff": + start = _civil_date(args.get("start"), "start") + end = _civil_date(args.get("end"), "end") + # The calendar->ordinal mapping is library calendar logic, not arithmetic; + # the SUBTRACTION is what goes to the kernel. + days = exact(f"{end.toordinal()} - {start.toordinal()}") + fields = { + "exact_days": frac_str(days), + "start": start.isoformat(), "end": end.isoformat(), + "start_ordinal": str(start.toordinal()), "end_ordinal": str(end.toordinal()), + "direction": "end - start (negative means end precedes start)", + } + parsed = f"diff({start.isoformat()} -> {end.isoformat()})" + elif op == "add": + start = _civil_date(args.get("start"), "start") + days_text = args.get("days") + offset = as_fraction(days_text, "days") + if offset.denominator != 1: + raise Refusal("args", f"days must be a whole number of civil days; got {days_text!r}") + target_ordinal = exact(f"{start.toordinal()} + ({frac_str(offset)})") + n = int(target_ordinal) + if not 1 <= n <= datetime.date.max.toordinal(): + raise Refusal("domain", f"resulting date falls outside the representable calendar range (ordinal {n})") + result = datetime.date.fromordinal(n) + fields = { + "result": result.isoformat(), "start": start.isoformat(), + "days_added": frac_str(offset), "result_ordinal": str(n), + } + parsed = f"add({start.isoformat()} + {frac_str(offset)} days)" + else: + raise Refusal("args", f"op must be 'diff' or 'add'; got {op!r}") + + return envelope( + status="exact-given", lane="jackal-measure-date", + assurance="exact day arithmetic CONDITIONAL on the declared calendar convention below", + parsed=parsed, given=given, fields=fields, non_claims=non_claims, + ) + + +# --------------------------------------------------------------------------- +# jackal_stat -- descriptive statistics, honestly classed +# --------------------------------------------------------------------------- + +def tool_stat(args: dict) -> dict: + sample = args.get("sample") + if isinstance(sample, str): + parts = [p for p in re.split(r"[\s;]+", sample.strip()) if p] + elif isinstance(sample, list): + parts = [str(p) for p in sample] + else: + raise Refusal("args", "sample must be a whitespace-separated string or a list of numbers") + if not parts: + raise Refusal("args", "sample is empty") + values = [as_fraction(p, f"sample[{i}]") for i, p in enumerate(parts)] + n = len(values) + + total = exact(" + ".join(f"({frac_str(v)})" for v in values)) + mean = exact(f"({frac_str(total)}) / {n}") + ordered = sorted(values) + if n % 2 == 1: + median = ordered[n // 2] + median_note = "middle order statistic" + else: + median = exact(f"(({frac_str(ordered[n//2 - 1])}) + ({frac_str(ordered[n//2])})) / 2") + median_note = "mean of the two central order statistics" + + ss = exact(" + ".join(f"(({frac_str(v)}) - ({frac_str(mean)}))^2" for v in values)) + pop_var = exact(f"({frac_str(ss)}) / {n}") + field_status = {k: "exact" for k in + ("n", "sum", "mean", "median", "min", "max", "range", "population_variance")} + fields = { + "n": str(n), + "sum": frac_str(total), "mean": frac_str(mean), "mean_approx": approx(mean), + "median": frac_str(median), "median_note": median_note, + "min": frac_str(ordered[0]), "max": frac_str(ordered[-1]), + "range": frac_str(exact(f"({frac_str(ordered[-1])}) - ({frac_str(ordered[0])})")), + "population_variance": frac_str(pop_var), + } + if n > 1: + sample_var = exact(f"({frac_str(ss)}) / {n - 1}") + fields["sample_variance"] = frac_str(sample_var) + field_status["sample_variance"] = "exact" + else: + fields["sample_variance"] = "undefined (n=1: division by n-1 = 0)" + field_status["sample_variance"] = "undefined" + + non_claims = [ + "DESCRIPTIVE ONLY. These summarize the supplied numbers and nothing else", + "NOT inferential: no population parameter, confidence interval, significance, or distributional assumption is claimed or implied", + "The mean is not robust to outliers; the median is reported alongside it for that reason", + "n is the count of numbers SUPPLIED, which is not evidence that the sample was drawn correctly or is representative of anything", + ] + + if args.get("include_stddev"): + lo, hi = sqrt_bound(pop_var) + fields["population_stddev_enclosure"] = [frac_str(lo), frac_str(hi)] + fields["population_stddev_approx"] = f"[{approx(lo)}, {approx(hi)}]" + field_status["population_stddev_enclosure"] = "formal-bounded" + non_claims.insert(0, + "The field `population_stddev_enclosure` is FORMAL-BOUNDED (a Lean-checked ENCLOSURE), " + "NOT exact, and NOT a single number. The top-level `exact` describes the other fields. " + "Report it as an interval, never as a point value.") + + return envelope( + status="exact", lane="jackal-measure-stat", + assurance="exact rational descriptive statistics; see `field_status` for any field carrying a different class", + parsed=f"n={n} sample=[{', '.join(frac_str(v) for v in values)}]", + fields={**fields, "field_status": field_status}, + non_claims=non_claims, + ) + + +# --------------------------------------------------------------------------- +# jackal_compare -- dimension-aware comparison +# --------------------------------------------------------------------------- + +BASE_UNITS = { + "dimensionless": "one", + "length": "m", + "mass": "kg", + "time": "s", + "volume": "l", + "speed": "m/s", + "energy": "j", + "power": "w", + "data": "b", + "temperature": "k", +} +COMPARISON_LABELS = {"usd", "eur", "gbp", "jpy"} + + +def _unit_key(name: str) -> str: + return name.strip().lower().replace("^", "").replace(" ", "") + + +def _quantity_in_base(value_text: object, unit_text: object, subject: str) -> dict: + """Normalize one quantity through JACKAL, returning base-unit metadata.""" + value = as_fraction(value_text, f"{subject}_value") + if unit_text is None: + normalized = exact(frac_str(value)) + return { + "dimension": "dimensionless", + "base_unit": BASE_UNITS["dimensionless"], + "value": normalized, + "authority": "dimensionless identity", + "input_unit": None, + } + if not isinstance(unit_text, str) or not unit_text.strip(): + raise Refusal("args", f"{subject}_unit must be a non-empty string when supplied") + label_key = _unit_key(unit_text) + if label_key in COMPARISON_LABELS: + normalized = exact(frac_str(value)) + label = label_key.upper() + return { + "dimension": f"currency:{label}", + "base_unit": label, + "value": normalized, + "authority": "nominal currency-label identity; no exchange-rate relation is implied", + "input_unit": unit_text.strip(), + } + dimension, factor, authority = find_unit(unit_text) + if dimension == "temperature": + key = _unit_key(unit_text) + normalized = exact(_TEMP_TO_K[key].format(v=frac_str(value))) + authority = "Exact affine scale definition; normalized to kelvin scale points" + else: + normalized = exact(f"({frac_str(value)}) * ({factor})") + return { + "dimension": dimension, + "base_unit": BASE_UNITS[dimension], + "value": normalized, + "authority": authority, + "input_unit": unit_text.strip(), + } + + +def tool_compare(args: dict) -> dict: + """Compare dimensioned magnitudes, requiring provenance across dimensions.""" + a = _quantity_in_base(args.get("a_value"), args.get("a_unit"), "a") + b = _quantity_in_base(args.get("b_value"), args.get("b_unit"), "b") + same_dimension = a["dimension"] == b["dimension"] + supplied_rate = args.get("rate") + given = None + + if same_dimension: + if any(args.get(key) not in (None, "") for key in ("rate", "rate_source", "rate_asof")): + raise Refusal( + "args", + "a declared rate is only accepted when the dimensions differ; same-dimension " + "quantities are compared through their exact definitional base-unit conversions", + ) + a_comparable = a["value"] + b_comparable = b["value"] + base_unit = a["base_unit"] + status = "exact" + assurance = "exact rational comparison after definitional base-unit normalization (not checker-covered)" + else: + if supplied_rate is None: + raise Refusal( + "dimension-mismatch-no-rate", + f"cannot compare {a['dimension']} with {b['dimension']} without a declared rate. " + f"Supply `rate`, `rate_source`, and `rate_asof`, where 1 {a['base_unit']} " + f"of a is declared equal to `rate` {b['base_unit']} of b.", + ) + if not isinstance(supplied_rate, str) or not supplied_rate.strip(): + raise Refusal("args", "rate must be a non-empty numeric string when dimensions differ") + source = args.get("rate_source") + asof = args.get("rate_asof") + missing = [ + name for name, value in (("rate_source", source), ("rate_asof", asof)) + if not isinstance(value, str) or not value.strip() + ] + if missing: + raise Refusal( + "undeclared-datum", + f"missing required declaration(s): {', '.join(missing)}. A cross-dimension " + "comparison rate is a DATUM, not mathematics, and must carry source and as-of.", + ) + rate = as_fraction(supplied_rate, "rate") + if rate <= 0: + raise Refusal("args", f"rate must be positive; got {supplied_rate!r}") + a_comparable = exact(f"({frac_str(a['value'])}) * ({frac_str(rate)})") + b_comparable = b["value"] + base_unit = b["base_unit"] + status = "exact-given" + assurance = ( + "exact rational comparison CONDITIONAL on the declared cross-dimension rate; " + "the rate itself is unverified" + ) + given = { + "datum": "cross-dimension comparison rate", + "rate": frac_str(rate), + "rate_approx": approx(rate), + "direction": f"1 {a['base_unit']} ({a['dimension']}) = {frac_str(rate)} " + f"{b['base_unit']} ({b['dimension']})", + "source": source.strip(), + "as_of": asof.strip(), + } + + difference = exact(f"({frac_str(a_comparable)}) - ({frac_str(b_comparable)})") + if a_comparable > b_comparable: + verdict = "a_greater" + elif b_comparable > a_comparable: + verdict = "b_greater" + else: + verdict = "equal" + + fields = { + "verdict": verdict, + "difference": frac_str(difference), + "base_unit": base_unit, + "a_in_base": frac_str(a_comparable), + "b_in_base": frac_str(b_comparable), + "a_dimension": a["dimension"], + "b_dimension": b["dimension"], + "definition_authority": {"a": a["authority"], "b": b["authority"]}, + } + if not same_dimension: + fields["a_before_declared_rate"] = frac_str(a["value"]) + fields["a_original_base_unit"] = a["base_unit"] + if b_comparable != 0: + fields["ratio"] = frac_str( + exact(f"({frac_str(a_comparable)}) / ({frac_str(b_comparable)})") + ) + + parsed = ( + f"compare(a={frac_str(a['value'])} {a['base_unit']}[{a['dimension']}], " + f"b={frac_str(b['value'])} {b['base_unit']}[{b['dimension']}])" + ) + if given is not None: + parsed += f" under ({given['direction']})" + non_claims = [ + "A comparison of magnitudes is not a comparison of value, quality, or suitability", + "Equal magnitudes in different units are not the same quantity", + ] + if given is not None: + non_claims.extend([ + "The verdict may reverse under a different declared rate; state the rate whenever reporting the verdict", + "JACKAL did NOT verify the rate, its source, or its as-of date; all are reported as supplied", + "`exact-given` is NOT a weaker `exact`: the arithmetic is exact and the datum is unverified. Do not report it as `exact`, and do not soften it to `estimated`", + ]) + if a["dimension"] == "temperature" or b["dimension"] == "temperature": + non_claims.insert(0, "Temperature inputs are SCALE POINTS normalized to kelvin, NOT temperature differences") + return envelope( + status=status, + lane="jackal-measure-compare", + assurance=assurance, + parsed=parsed, + fields=fields, + given=given, + non_claims=non_claims, + ) + + +# --------------------------------------------------------------------------- +# jackal_scan -- lexical noticing prosthetic +# --------------------------------------------------------------------------- + +DERIVATION_CUES = ( + "total", "sum", "combined", "difference", "average", "mean", "median", + "per", "each", "times", "twice", "half", "double", "increase", "decrease", + "up from", "down from", "faster", "slower", "cheaper", "more than", "less than", + "about", "roughly", "approximately", "estimated", +) +OBSERVATION_CUES = ( + "listed", "reported", "read", "says", "shows", "according to", "output", + "returned", "printed", "per the", +) + + +def _number_pattern() -> str: + # Keep scientific notation as one lexical token. The ordering is + # intentional: coefficient-times-ten, e notation, and powers of ten must + # win before the final plain-decimal alternative can consume a prefix. + decimal_number = r"\d[\d,]*(?:\.\d+)?" + signed_exponent = r"[+-]?\d+" + braced_exponent = rf"\{{{signed_exponent}\}}" + superscript_exponent = r"[⁺⁻]?[⁰¹²³⁴⁵⁶⁷⁸⁹]+" + power = rf"(?:\^\s*(?:{braced_exponent}|{signed_exponent})|\*\*\s*(?:{braced_exponent}|{signed_exponent})|{superscript_exponent})" + ten_power = rf"10\s*{power}" + return rf"(?:{decimal_number}\s*[×·*]\s*{ten_power}|{decimal_number}[eE]{signed_exponent}|{ten_power}|{decimal_number})" + + +def _scan_patterns() -> list[tuple[str, re.Pattern]]: + known_units = {unit for table in UNITS.values() for unit in table} + known_units.update(TEMPERATURE) + known_units.update(REFUSED_UNITS) + unit_alt = "|".join(re.escape(unit) for unit in sorted(known_units, key=len, reverse=True)) + number = _number_pattern() + return [ + ("version", re.compile(r"(?\d+\.\d+(?:\.\d+)+)(?![\w.])")), + ("date_iso", re.compile(r"(?\d{4}-\d{2}-\d{2})(?!\d)")), + ("currency", re.compile(rf"[$£€¥]\s?(?P{number})")), + ("currency", re.compile(rf"(?{number})\s?(?:USD|EUR|GBP|JPY)\b", re.IGNORECASE)), + ("percentage", re.compile(rf"(?{number})\s?%")), + ("dimensioned", re.compile(rf"(?{number})\s*(?P{unit_alt})(?![\w/])", re.IGNORECASE)), + # Sentence punctuation after a numeral is permitted; a dot/comma only + # blocks the match when it begins another numeric component. + ("plain", re.compile(rf"(?{number})(?!\w|[.,]\d)")), + ] + + +SCAN_PATTERNS = _scan_patterns() +CURRENCY_MARKERS = re.compile(r"[$£€¥]|\b(?:USD|EUR|GBP|JPY)\b", re.IGNORECASE) + + +def _cue_hits(context: str) -> list[str]: + lower = context.lower() + hits = [cue for cue in DERIVATION_CUES if cue in lower] + symbol_tests = ( + ("+", "+" in context), + ("-", bool(re.search(r"(?:\d|\s)-\s*(?:\d|[$£€¥])", context))), + ("×", "×" in context), + ("x", bool(re.search(r"(? list[str]: + lower = context.lower() + hits = [cue for cue in OBSERVATION_CUES if cue in lower] + before = text[:full_start].rstrip() + after = text[full_end:].lstrip() + if before and after and (before[-1], after[0]) in { + ('"', '"'), ("'", "'"), ("“", "”"), ("‘", "’"), + }: + hits.append("quoted") + return list(dict.fromkeys(hits)) + + +def _currency_marker_set(text: str) -> set[str]: + aliases = {"$": "USD", "£": "GBP", "€": "EUR", "¥": "YEN"} + markers = set() + for match in CURRENCY_MARKERS.finditer(text): + token = match.group(0) + markers.add(aliases.get(token, token.upper())) + return markers + + +def tool_scan(args: dict) -> dict: + text = args.get("text") + if not isinstance(text, str) or not text: + raise Refusal("args", "text is required and must be a non-empty string") + window = args.get("context_window", 60) + if isinstance(window, bool) or not isinstance(window, int) or window < 0: + raise Refusal("args", "context_window must be a non-negative integer") + + candidates = [] + for priority, (kind, pattern) in enumerate(SCAN_PATTERNS): + for match in pattern.finditer(text): + candidates.append({ + "priority": priority, + "kind": kind, + "full_start": match.start(), + "full_end": match.end(), + "offset": match.start("num"), + "text": match.group("num"), + "unit": match.groupdict().get("unit"), + }) + candidates.sort(key=lambda item: ( + item["full_start"], item["priority"], -(item["full_end"] - item["full_start"]) + )) + + selected = [] + occupied_until = -1 + for candidate in candidates: + if candidate["full_start"] < occupied_until: + continue + selected.append(candidate) + occupied_until = candidate["full_end"] + + cross_currency = len(_currency_marker_set(text)) > 1 + findings = [] + by_kind: dict[str, int] = {} + unrouted = [] + for candidate in selected: + context_start = max(0, candidate["full_start"] - window) + context_end = min(len(text), candidate["full_end"] + window) + context = text[context_start:context_end] + cue_context = ( + text[context_start:candidate["full_start"]] + + " " * (candidate["full_end"] - candidate["full_start"]) + + text[candidate["full_end"]:context_end] + ) + derived = _cue_hits(cue_context) + observed = _observation_hits( + text, candidate["full_start"], candidate["full_end"], cue_context + ) + kind = candidate["kind"] + if kind == "version": + route = None + must_declare = False + elif kind == "currency" and cross_currency: + route = "jackal_rate_apply / jackal_compare" + must_declare = True + elif kind == "currency": + route = "jackal_exact" if derived else None + must_declare = bool(derived) + elif kind == "percentage": + route = "jackal_percent" + must_declare = bool(derived) + elif kind == "dimensioned": + route = "jackal_convert" + must_declare = bool(derived) + elif kind == "date_iso": + route = "jackal_date_delta" if derived else None + must_declare = bool(derived) + else: + route = "jackal_exact" if derived else None + must_declare = bool(derived) + + finding = { + "text": candidate["text"], + "offset": candidate["offset"], + "kind": kind, + "context": context, + "cues_derived": derived, + "cues_observed": observed, + "route": route, + "must_declare": must_declare, + } + if candidate["unit"]: + finding["unit"] = candidate["unit"] + findings.append(finding) + by_kind[kind] = by_kind.get(kind, 0) + 1 + if must_declare: + unrouted.append({ + "text": candidate["text"], + "offset": candidate["offset"], + "kind": kind, + "route": route, + }) + + summary = { + "total_numerals": len(findings), + "by_kind": by_kind, + "flagged": len(unrouted), + "unrouted_derived": unrouted, + } + return envelope( + status="checked", + lane="jackal-measure-scan", + assurance="checked lexical classification only; no numeral was mathematically verified", + parsed=f"text={json.dumps(text, ensure_ascii=False)} context_window={window}", + fields={"numerals": findings, "summary": summary}, + non_claims=[ + "This is a LEXICAL scan. It reads characters, not provenance", + "The ABSENCE of a flag is NOT evidence that a numeral was observed rather than derived. A clean scan means nothing was detected, not that nothing is wrong", + "Cue matching is heuristic and both over- and under-fires. Version strings, ordinals, identifiers, and quoted figures are frequently misclassified", + "This tool cannot verify any numeral. It only suggests where one should be sent", + "Offsets and counts are lexical metadata returned by Python string/regex operations, not JACKAL arithmetic results", + ], + ) + + +# --------------------------------------------------------------------------- +# Tool registry and stdio MCP server +# --------------------------------------------------------------------------- + +DRAFT7 = "http://json-schema.org/draft-07/schema#" +NUMBER_STRING = { + "type": "string", + "minLength": 1, + "description": "Unambiguous integer, decimal, or rational string; commas refuse", +} +NONEMPTY_STRING = {"type": "string", "minLength": 1} + + +def _schema(properties: dict, required: list[str]) -> dict: + return { + "$schema": DRAFT7, + "type": "object", + "properties": properties, + "required": required, + "additionalProperties": False, + } + + +TOOL_REGISTRY = { + "jackal_convert": ( + tool_convert, + "Convert definitionally related units through JACKAL. Returns status=exact. Refuses ambiguous literals, undefined units, deliberately excluded units, dimension mismatches, kernel loss, and kernel refusal.", + _schema({ + "value": NUMBER_STRING, + "from_unit": {**NONEMPTY_STRING, "description": "Source unit token from the JACKAL measurement subsystem's exact-by-definition table"}, + "to_unit": {**NONEMPTY_STRING, "description": "Target unit token in the same physical dimension"}, + }, ["value", "from_unit", "to_unit"]), + ), + "jackal_rate_apply": ( + tool_rate_apply, + "Apply a caller-declared rate through JACKAL. Returns status=exact-given, never exact. Refuses unless value, positive rate, rate_source, and rate_asof are all declared; also refuses kernel loss or kernel refusal.", + _schema({ + "value": NUMBER_STRING, + "rate": NUMBER_STRING, + "rate_source": {**NONEMPTY_STRING, "description": "Caller-declared provenance for the rate; the JACKAL measurement subsystem does not verify it"}, + "rate_asof": {**NONEMPTY_STRING, "description": "Caller-declared date/time or period when the rate applied"}, + "from_label": {**NONEMPTY_STRING, "description": "Optional source quantity label"}, + "to_label": {**NONEMPTY_STRING, "description": "Optional target quantity label"}, + }, ["value", "rate", "rate_source", "rate_asof"]), + ), + "jackal_percent": ( + tool_percent, + "Perform percentage operations through JACKAL. Returns status=exact and distinguishes percent from percentage points. Refuses unknown operations, ambiguous literals, division by zero, kernel loss, and kernel refusal.", + _schema({ + "op": {"type": "string", "enum": ["of", "change", "ratio", "points", "increase", "decrease"]}, + "a": NUMBER_STRING, + "b": NUMBER_STRING, + }, ["op", "a", "b"]), + ), + "jackal_date_delta": ( + tool_date_delta, + "Compute proleptic-Gregorian civil-date differences or additions through JACKAL. Returns status=exact-given. Refuses wall-clock timestamps, invalid dates, fractional day offsets, range overflow, kernel loss, and kernel refusal.", + _schema({ + "op": {"type": "string", "enum": ["diff", "add"]}, + "start": {**NONEMPTY_STRING, "description": "ISO civil date YYYY-MM-DD"}, + "end": {**NONEMPTY_STRING, "description": "ISO civil date YYYY-MM-DD; required for diff"}, + "days": {**NUMBER_STRING, "description": "Whole civil-day offset; required for add"}, + }, ["op", "start"]), + ), + "jackal_stat": ( + tool_stat, + "Compute descriptive statistics through JACKAL. Top-level status=exact; requested population_stddev_enclosure is separately status=formal-bounded. Refuses empty/malformed samples, ambiguous literals, kernel loss, and kernel refusal.", + _schema({ + "sample": { + "description": "Whitespace/semicolon-separated numeric string or an array of numeric strings/integers; JSON floats refuse to avoid binary-float transcription", + "anyOf": [ + {"type": "string"}, + {"type": "array", "items": {"type": ["string", "integer"]}}, + ], + }, + "include_stddev": {"type": "boolean", "default": False}, + }, ["sample"]), + ), + "jackal_compare": ( + tool_compare, + "Compare dimensioned magnitudes through JACKAL. Returns status=exact for dimensionless or same-dimension comparisons and status=exact-given across dimensions. Refuses cross-dimension comparison without a positive rate plus source and as-of, undefined units, kernel loss, and kernel refusal.", + _schema({ + "a_value": NUMBER_STRING, + "a_unit": {**NONEMPTY_STRING, "description": "Optional unit; omit for dimensionless a"}, + "b_value": NUMBER_STRING, + "b_unit": {**NONEMPTY_STRING, "description": "Optional unit; omit for dimensionless b"}, + "rate": {**NUMBER_STRING, "description": "Required only across dimensions: 1 a-base-unit equals rate b-base-units"}, + "rate_source": {**NONEMPTY_STRING, "description": "Required provenance whenever rate is supplied"}, + "rate_asof": {**NONEMPTY_STRING, "description": "Required as-of declaration whenever rate is supplied"}, + }, ["a_value", "b_value"]), + ), + "jackal_scan": ( + tool_scan, + "Lexically audit draft prose for numerals and suggest routing lanes. Returns status=checked and computes/verifies no mathematical result. Refuses missing text or an invalid context window; a clean scan is never evidence of sound provenance.", + _schema({ + "text": {"type": "string", "minLength": 1, "description": "Draft prose to audit before sending"}, + "context_window": {"type": "integer", "minimum": 0, "maximum": 10000, "default": 60}, + }, ["text"]), + ), +} + +TOOL_TITLES = { + "jackal_convert": "Convert Definitional Units", + "jackal_rate_apply": "Apply a Declared Rate", + "jackal_percent": "Compute Percentage Operations", + "jackal_date_delta": "Compute Civil-Date Delta", + "jackal_stat": "Compute Descriptive Statistics", + "jackal_compare": "Compare Dimensioned Quantities", + "jackal_scan": "Scan Draft Numerals", +} +TOOL_ANNOTATIONS = { + "readOnlyHint": True, + "destructiveHint": False, + "idempotentHint": True, + "openWorldHint": False, +} + + +def _tool_definitions() -> list[dict]: + return [ + { + "name": name, + "title": TOOL_TITLES[name], + "description": description, + "inputSchema": schema, + "annotations": dict(TOOL_ANNOTATIONS), + } + for name, (_handler, description, schema) in TOOL_REGISTRY.items() + ] + + +def _matches_schema(value: object, schema: dict) -> bool: + if "anyOf" in schema: + return any(_matches_schema(value, branch) for branch in schema["anyOf"]) + expected = schema.get("type") + if isinstance(expected, list): + return any(_matches_schema(value, {**schema, "type": item}) for item in expected) + if expected == "string": + return isinstance(value, str) + if expected == "boolean": + return isinstance(value, bool) + if expected == "integer": + return isinstance(value, int) and not isinstance(value, bool) + if expected == "number": + return isinstance(value, (int, float)) and not isinstance(value, bool) + if expected == "array": + if not isinstance(value, list): + return False + item_schema = schema.get("items") + return item_schema is None or all(_matches_schema(item, item_schema) for item in value) + if expected == "object": + return isinstance(value, dict) + return True + + +def _validate_arguments(tool_name: str, arguments: object) -> dict: + if not isinstance(arguments, dict): + raise Refusal("args", "tool arguments must be a JSON object") + schema = TOOL_REGISTRY[tool_name][2] + properties = schema["properties"] + extras = sorted(set(arguments) - set(properties)) + if extras: + raise Refusal("args", f"unexpected argument(s): {', '.join(extras)}") + for name, value in arguments.items(): + property_schema = properties[name] + if not _matches_schema(value, property_schema): + raise Refusal("args", f"argument {name!r} does not match its declared JSON type") + enum = property_schema.get("enum") + if enum is not None and value not in enum: + raise Refusal("args", f"argument {name!r} must be one of {', '.join(enum)}") + if isinstance(value, str) and property_schema.get("minLength", 0) > 0 and not value: + raise Refusal("args", f"argument {name!r} must not be empty") + if isinstance(value, int) and not isinstance(value, bool): + if "minimum" in property_schema and value < property_schema["minimum"]: + raise Refusal("args", f"argument {name!r} is below its minimum") + if "maximum" in property_schema and value > property_schema["maximum"]: + raise Refusal("args", f"argument {name!r} exceeds its maximum") + return arguments + + +MEASUREMENT_TOOL_NAMES = frozenset(TOOL_REGISTRY) + + +def tool_definitions() -> list[dict]: + """Return fresh MCP definitions for the identity-pinned wrapper to merge.""" + return _tool_definitions() + + +class _IntegratedKernelBridge: + """Synchronous facade over the wrapper's serialized runtime callback.""" + + def __init__(self, callback: Callable[[str, dict], dict]) -> None: + self._callback = callback + self._evaluator_sha: str | None = None + + def call(self, tool: str, arguments: dict) -> dict: + out = self._callback(tool, arguments) + if not isinstance(out, dict): + raise Refusal("kernel-error", f"{tool} returned no structured content") + if out.get("status") == "refused": + raise Refusal( + f"kernel-refused:{out.get('reason', 'unnamed')}", + f"JACKAL {tool} refused: {out.get('detail', '(no detail)')}", + ["The underlying kernel refused; no measurement-side arithmetic was substituted"], + ) + ident = out.get("identities") + if isinstance(ident, dict) and isinstance(ident.get("evaluator_sha256"), str): + self._evaluator_sha = ident["evaluator_sha256"] + return out + + @property + def evaluator_sha256(self) -> str | None: + return self._evaluator_sha + + +def dispatch_integrated( + tool_name: str, + arguments: object, + kernel_call: Callable[[str, dict], dict], + identity_sha256: str, +) -> dict: + """Run one measurement tool through the caller-supplied JACKAL backend. + + Runtime transport and cancellation exceptions intentionally propagate to + the wrapper, which already maps them to MCP errors and reaps the process + group. Only epistemic/argument refusals become ordinary JACKAL refusal + payloads here. + """ + if re.fullmatch(r"[0-9a-f]{64}", identity_sha256) is None: + raise RuntimeError("measurement module identity is invalid") + if tool_name not in TOOL_REGISTRY: + raise RuntimeError("unknown integrated measurement tool") + + global JACKAL, _ACTIVE_IDENTITY + previous = JACKAL + previous_identity = _ACTIVE_IDENTITY + JACKAL = _IntegratedKernelBridge(kernel_call) + _ACTIVE_IDENTITY = identity_sha256 + _TRACE.clear() + try: + validated = _validate_arguments(tool_name, arguments) + return TOOL_REGISTRY[tool_name][0](validated) + except Refusal as refusal: + return refusal_body(refusal.reason, refusal.detail, refusal.non_claims) + finally: + JACKAL = previous + _ACTIVE_IDENTITY = previous_identity + + +if __name__ == "__main__": + raise SystemExit( + "This identity-pinned module is not a standalone server; launch JACKAL instead." + ) diff --git a/plugins/jackel/mcp/server.py b/plugins/jackel/mcp/server.py index c53484c..d112b41 100644 --- a/plugins/jackel/mcp/server.py +++ b/plugins/jackel/mcp/server.py @@ -1,9 +1,11 @@ #!/usr/bin/env python3 -"""Fail-closed MCP bridge for the sealed JACKAL macOS runtime.""" +"""Fail-closed MCP bridge for the host-pinned sealed JACKAL runtime.""" from __future__ import annotations import asyncio +import base64 +import binascii from collections import deque import contextlib import copy @@ -16,12 +18,12 @@ import re import selectors import signal -import socket import stat import subprocess import sys import threading import time +import zlib from dataclasses import dataclass, field from pathlib import Path from types import ModuleType @@ -38,12 +40,88 @@ ) SUPPORTED_ARGUMENT_TYPES = frozenset({"string", "object"}) EXPECTED_TOOL_COUNT = 41 +EXPECTED_MEASUREMENT_TOOL_COUNT = 7 +EXPECTED_ADVANCED_TOOL_COUNT = 3 +EXPECTED_STEM_TOOL_COUNT = 7 +EXPECTED_UNIFIED_TOOL_COUNT = 58 +MEASUREMENT_TOOL_NAMES = frozenset( + { + "jackal_compare", + "jackal_convert", + "jackal_date_delta", + "jackal_percent", + "jackal_rate_apply", + "jackal_scan", + "jackal_stat", + } +) +MEASUREMENT_KERNEL_TOOLS = frozenset({"jackal_exact", "jackal_sqrt_rat_bound"}) +ADVANCED_TOOL_NAMES = frozenset( + {"jackal_cas", "jackal_graph", "jackal_hellgate_ground_state"} +) +ADVANCED_KERNEL_TOOLS = frozenset( + { + "jackal_alg_cmp", + "jackal_alg_sign", + "jackal_atan_rat_bound", + "jackal_canon", + "jackal_cos_rat_bound", + "jackal_diff", + "jackal_evaluate", + "jackal_exact", + "jackal_exp_rat_bound", + "jackal_gaussian_integral", + "jackal_integrate", + "jackal_integrate_adaptive", + "jackal_integrate_bound", + "jackal_integrate_bound_cert", + "jackal_ln_rat_bound", + "jackal_poly_canon", + "jackal_poly_eq", + "jackal_poly_gcd", + "jackal_range_bound", + "jackal_ratfunc_canon", + "jackal_roots_isolate", + "jackal_sin_rat_bound", + "jackal_solve", + "jackal_sqrt_rat_bound", + "jackal_tanh_rat_bound", + } +) +STEM_TOOL_NAMES = frozenset( + { + "jackal_aerospace", + "jackal_hypothesis", + "jackal_linked_workspace", + "jackal_matrix", + "jackal_probability", + "jackal_regression", + "jackal_sensor", + } +) +STEM_KERNEL_TOOLS = frozenset( + { + "jackal_canon", + "jackal_diff", + "jackal_evaluate", + "jackal_exact", + "jackal_integrate_adaptive", + "jackal_ln_rat_bound", + "jackal_sqrt_rat_bound", + } +) TOOL_TIMEOUT_SECONDS = 3600.0 TERMINATE_GRACE_SECONDS = 0.5 LEADER_POLL_SECONDS = 0.01 -MAX_REQUEST_LINE_BYTES = 1024 * 1024 +THREAD_WORKER_POLL_SECONDS = 0.01 MAX_CATALOG_BYTES = 2 * 1024 * 1024 MAX_WRAPPER_MODULE_BYTES = 2 * 1024 * 1024 +MAX_CERTIFICATE_COMPRESSED_BYTES = 2 * 1024 * 1024 +MAX_CERTIFICATE_BYTES = 4 * 1024 * 1024 +MAX_MCP_CONTENT_BLOCKS = 4 +MAX_MCP_CONTENT_TEXT_BYTES = 1024 * 1024 +MAX_MCP_IMAGE_BYTES = 4 * 1024 * 1024 +MAX_MCP_RESOURCE_TEXT_BYTES = 2 * 1024 * 1024 MAX_STDOUT_BYTES = 16 * 1024 * 1024 MAX_STDERR_BYTES = 1024 * 1024 MAX_ERROR_RESPONSE_BYTES = 1024 @@ -51,11 +129,24 @@ MAX_TRANSPORT_TASKS = 16 MAX_JSON_DEPTH = 64 MAX_MCP_RESPONSE_BYTES = (2 * MAX_STDOUT_BYTES) + (2 * 1024 * 1024) +# A full runtime payload at the stdout ceiling must fit back through the +# request side for independent receipt replay, including its JSON-RPC envelope. +MAX_REQUEST_LINE_BYTES = MAX_STDOUT_BYTES + MAX_CATALOG_BYTES MAX_RESPONSE_QUEUE_BYTES = 2 * MAX_MCP_RESPONSE_BYTES +BACKEND_RPC_REQUEST_ID = "jackal-adapter-backend" STDIO_DRAIN_TIMEOUT = 0.5 PROCESS_GROUP_OBSERVATION_BYTES = 64 * 1024 PROCESS_GROUP_OBSERVATION_TIMEOUT = 0.5 +NAMESPACE_SETUP_TIMEOUT = 5.0 +PRIVATE_NAMESPACE_FLAG = "--jackal-private-runtime-namespace" +PROCESS_GUARDIAN_FLAG = "--jackal-process-guardian" +PRIVATE_SNAPSHOT_PARENT_PREFIX = ".jackal-codex-runtime-private-" _IDENTITY_LINE = re.compile(r"([0-9a-f]{64}) ([^\n]+)", re.ASCII) +_MOUNT_NAMESPACE_IDENTITY = re.compile(r"mnt:\[[0-9]+\]", re.ASCII) +_LINKED_WORKSPACE_RESOURCE = re.compile( + r"ui://jackal/linked-workspace/([0-9a-f]{64})\Z", re.ASCII +) +LINKED_WORKSPACE_SHELL_URI = "ui://jackal/linked-workspace" PARSE_ERROR = -32700 INVALID_REQUEST = -32600 @@ -119,6 +210,8 @@ def default_locator_path(self) -> Path: ... def validate_runtime(self, runtime: Path, **kwargs: Any) -> object: ... + def reap_orphaned_runtime_snapshots(self, temporary_parent: Path | str | None = None) -> object: ... + def create_runtime_snapshot(self, runtime: Path, **kwargs: Any) -> object: ... def runtime_subprocess_environment( @@ -222,13 +315,215 @@ def build_tool_definitions( return definitions +def _build_integrated_tool_definitions( + module: ModuleType, + *, + exported_name: str, + expected_names: frozenset[str], + expected_count: int, + label: str, +) -> tuple[dict[str, Any], ...]: + """Validate one identity-pinned in-process surface before merging it.""" + exported_names = getattr(module, exported_name, None) + exporter = getattr(module, "tool_definitions", None) + dispatcher = getattr(module, "dispatch_integrated", None) + refusal_type = getattr(module, "Refusal", None) + if ( + exported_names != expected_names + or not callable(exporter) + or not callable(dispatcher) + or not isinstance(refusal_type, type) + or not issubclass(refusal_type, Exception) + ): + raise CatalogError(f"{label} module API is invalid") + try: + records = exporter() + except Exception as error: + raise CatalogError(f"{label} tool export failed") from error + if not isinstance(records, list) or len(records) != expected_count: + raise CatalogError(f"{label} tool count does not match the wrapper expectation") + + definitions: list[dict[str, Any]] = [] + for record in records: + if not isinstance(record, dict) or set(record) != { + "name", "title", "description", "inputSchema", "annotations" + }: + raise CatalogError(f"{label} tool record has an unsupported shape") + name = record["name"] + title = record["title"] + description = record["description"] + schema = record["inputSchema"] + annotations = record["annotations"] + if ( + not isinstance(name, str) + or name not in expected_names + or not isinstance(title, str) + or not title + or not isinstance(description, str) + or not description + or not isinstance(schema, dict) + or set(schema) != { + "$schema", "type", "properties", "required", "additionalProperties" + } + or schema.get("$schema") != DRAFT_07 + or schema.get("type") != "object" + or not isinstance(schema.get("properties"), dict) + or not isinstance(schema.get("required"), list) + or schema.get("additionalProperties") is not False + or not isinstance(annotations, dict) + or set(annotations) != { + "readOnlyHint", "destructiveHint", "idempotentHint", "openWorldHint" + } + or annotations != { + "readOnlyHint": True, + "destructiveHint": False, + "idempotentHint": True, + "openWorldHint": False, + } + ): + raise CatalogError(f"{label} tool definition is invalid: {name!r}") + properties = schema["properties"] + required = schema["required"] + if ( + any(not isinstance(key, str) or not isinstance(value, dict) + for key, value in properties.items()) + or any(not isinstance(key, str) or key not in properties for key in required) + or len(set(required)) != len(required) + ): + raise CatalogError(f"{label} schema is invalid: {name!r}") + try: + encoded = json.dumps( + record, + ensure_ascii=False, + allow_nan=False, + sort_keys=True, + separators=(",", ":"), + ).encode("utf-8") + except (TypeError, ValueError, RecursionError) as error: + raise CatalogError(f"{label} definition is not strict JSON: {name!r}") from error + if len(encoded) > MAX_CATALOG_BYTES: + raise CatalogError(f"{label} definition exceeds byte limit: {name!r}") + definitions.append(copy.deepcopy(record)) + + names = [definition["name"] for definition in definitions] + if set(names) != expected_names or len(set(names)) != len(names): + raise CatalogError(f"{label} tool names are incomplete or duplicated") + return tuple(definitions) + + +def build_measurement_tool_definitions(module: ModuleType) -> tuple[dict[str, Any], ...]: + """Validate THOTH's pinned in-process measurement surface.""" + return _build_integrated_tool_definitions( + module, + exported_name="MEASUREMENT_TOOL_NAMES", + expected_names=MEASUREMENT_TOOL_NAMES, + expected_count=EXPECTED_MEASUREMENT_TOOL_COUNT, + label="measurement", + ) + + +def build_advanced_tool_definitions(module: ModuleType) -> tuple[dict[str, Any], ...]: + """Validate the pinned CAS, graph, and certificate surface.""" + return _build_integrated_tool_definitions( + module, + exported_name="ADVANCED_TOOL_NAMES", + expected_names=ADVANCED_TOOL_NAMES, + expected_count=EXPECTED_ADVANCED_TOOL_COUNT, + label="advanced", + ) + + +def build_stem_tool_definitions(module: ModuleType) -> tuple[dict[str, Any], ...]: + """Validate the pinned additive STEM workflow and linked-view surface.""" + return _build_integrated_tool_definitions( + module, + exported_name="STEM_TOOL_NAMES", + expected_names=STEM_TOOL_NAMES, + expected_count=EXPECTED_STEM_TOOL_COUNT, + label="stem", + ) + + +def _validated_mcp_content(value: object) -> list[dict[str, Any]]: + if ( + not isinstance(value, list) + or not value + or len(value) > MAX_MCP_CONTENT_BLOCKS + ): + raise BackendFailure("backend MCP content block count is invalid") + result: list[dict[str, Any]] = [] + text_bytes = 0 + for block in value: + if not isinstance(block, dict) or not isinstance(block.get("type"), str): + raise BackendFailure("backend MCP content block is invalid") + if block["type"] == "text": + if set(block) != {"type", "text"} or not isinstance(block.get("text"), str): + raise BackendFailure("backend MCP text block is invalid") + text_bytes += len(block["text"].encode("utf-8")) + if text_bytes > MAX_MCP_CONTENT_TEXT_BYTES: + raise BackendFailure("backend MCP text content exceeds byte limit") + result.append({"type": "text", "text": block["text"]}) + continue + if block["type"] == "image": + if ( + set(block) != {"type", "data", "mimeType"} + or block.get("mimeType") != "image/png" + or not isinstance(block.get("data"), str) + ): + raise BackendFailure("backend MCP image block is invalid") + try: + decoded = base64.b64decode(block["data"], validate=True) + except (ValueError, binascii.Error) as error: + raise BackendFailure("backend MCP image is not canonical base64") from error + if ( + not decoded + or len(decoded) > MAX_MCP_IMAGE_BYTES + or not decoded.startswith(b"\x89PNG\r\n\x1a\n") + or base64.b64encode(decoded).decode("ascii") != block["data"] + ): + raise BackendFailure("backend MCP image is not a bounded canonical PNG") + result.append( + {"type": "image", "data": block["data"], "mimeType": "image/png"} + ) + continue + if block["type"] == "resource": + if set(block) != {"type", "resource"} or not isinstance( + block.get("resource"), dict + ): + raise BackendFailure("backend MCP resource block is invalid") + resource = block["resource"] + if ( + set(resource) != {"uri", "mimeType", "text"} + or not isinstance(resource.get("uri"), str) + or resource.get("mimeType") != "text/html" + or not isinstance(resource.get("text"), str) + ): + raise BackendFailure("backend MCP resource contents are invalid") + matched = _LINKED_WORKSPACE_RESOURCE.fullmatch(resource["uri"]) + encoded = resource["text"].encode("utf-8") + if ( + matched is None + or not encoded + or len(encoded) > MAX_MCP_RESOURCE_TEXT_BYTES + or not resource["text"].startswith("") + or not hmac.compare_digest(hashlib.sha256(encoded).hexdigest(), matched.group(1)) + ): + raise BackendFailure("backend MCP resource identity is invalid") + result.append(copy.deepcopy(block)) + continue + raise BackendFailure("backend MCP content type is unsupported") + return result + + def backend_result(value: object) -> dict[str, Any]: """Wrap one backend JSON object without changing its assurance semantics.""" if not isinstance(value, dict): raise BackendFailure("backend result is not a JSON object") + structured = copy.deepcopy(value) + raw_content = structured.pop("_mcp_content", None) try: text = json.dumps( - value, + structured, ensure_ascii=False, allow_nan=False, sort_keys=True, @@ -236,10 +531,12 @@ def backend_result(value: object) -> dict[str, Any]: ) except (TypeError, ValueError) as error: raise BackendFailure("backend result is not strict JSON") from error - return { - "content": [{"type": "text", "text": text}], - "structuredContent": copy.deepcopy(value), - } + content = ( + [{"type": "text", "text": text}] + if raw_content is None + else _validated_mcp_content(raw_content) + ) + return {"content": content, "structuredContent": structured} def _object_pairs(pairs: Sequence[tuple[str, Any]]) -> dict[str, Any]: @@ -380,6 +677,9 @@ def __init__( stderr_limit: int, terminate_grace: float, leader_poll_interval: float, + process_guardian: Sequence[str] | None = None, + stdin_bytes: bytes | None = None, + stdio_request_id: str | None = None, ) -> None: if ( not command @@ -390,8 +690,27 @@ def __init__( or stderr_limit < 1 or terminate_grace <= 0 or leader_poll_interval <= 0 + or (stdin_bytes is None) != (stdio_request_id is None) + or (stdio_request_id is not None and ( + not isinstance(stdio_request_id, str) or not stdio_request_id + )) + or (stdin_bytes is not None and ( + not isinstance(stdin_bytes, bytes) + or not stdin_bytes + or len(stdin_bytes) > MAX_REQUEST_LINE_BYTES + or not stdin_bytes.endswith(b"\n") + or stdin_bytes.count(b"\n") != 1 + )) ): raise ValueError("invalid anchored backend bounds") + if process_guardian is not None and ( + not process_guardian + or any( + not isinstance(argument, str) or not argument or "\x00" in argument + for argument in process_guardian + ) + ): + raise ValueError("invalid backend process guardian") self.state = state self.command = tuple(command) self.cwd = Path(cwd) @@ -409,9 +728,14 @@ def __init__( self.stderr_limit = int(stderr_limit) self.terminate_grace = float(terminate_grace) self.leader_poll_interval = float(leader_poll_interval) + self.process_guardian = ( + None if process_guardian is None else tuple(process_guardian) + ) + self.stdin_bytes = stdin_bytes + self.stdio_request_id = stdio_request_id self._cancelled = threading.Event() self._wake_lock = threading.Lock() - self._wake_writer: socket.socket | None = None + self._wake_writer: int | None = None def cancel(self) -> None: """Wake the runner and request cleanup; the caller never signals.""" @@ -420,7 +744,7 @@ def cancel(self) -> None: writer = self._wake_writer if writer is not None: with contextlib.suppress(OSError): - writer.send(b"\0") + os.write(writer, b"\0") def _peek_leader_anchor(self, process: subprocess.Popen[bytes]) -> int | None: state = self.state @@ -536,17 +860,19 @@ def _terminate_and_reap(self, process: subprocess.Popen[bytes]) -> int: leader_deadline = time.monotonic() + max(1.0, self.terminate_grace * 4) status = self._peek_leader_anchor(process) while status is None: - if time.monotonic() >= leader_deadline: + remaining = leader_deadline - time.monotonic() + if remaining <= 0: raise BackendFailure("backend leader did not exit within cleanup bounds") - time.sleep(self.leader_poll_interval) + time.sleep(min(self.leader_poll_interval, remaining)) status = self._peek_leader_anchor(process) if state.kill_sent: group_deadline = time.monotonic() + max(1.0, self.terminate_grace * 4) while self._group_exists(process): - if time.monotonic() >= group_deadline: + remaining = group_deadline - time.monotonic() + if remaining <= 0: raise BackendFailure("backend process group survived SIGKILL") - time.sleep(self.leader_poll_interval) + time.sleep(min(self.leader_poll_interval, remaining)) try: reaped_status = process.wait() @@ -560,10 +886,10 @@ def _terminate_and_reap(self, process: subprocess.Popen[bytes]) -> int: return status @staticmethod - def _drain_wakeup(reader: socket.socket) -> None: + def _drain_wakeup(reader: int) -> None: while True: try: - if not reader.recv(4096): + if not os.read(reader, 4096): return except BlockingIOError: return @@ -578,8 +904,9 @@ def _read_ready( selector: selectors.BaseSelector, buffers: dict[str, bytearray], open_streams: set[str], - wake_reader: socket.socket, + wake_reader: int, timeout: float, + input_state: dict[str, Any] | None = None, ) -> None: try: events = selector.select(max(0.0, timeout)) @@ -590,6 +917,29 @@ def _read_ready( if stream == "wake": self._drain_wakeup(wake_reader) continue + if stream == "stdin": + if input_state is None or not input_state.get("open"): + raise BackendFailure("backend stdin state is inconsistent") + payload = cast(bytes, input_state["payload"]) + offset = cast(int, input_state["offset"]) + try: + written = os.write(key.fd, payload[offset:offset + 64 * 1024]) + except BlockingIOError: + continue + except OSError as error: + raise BackendFailure("cannot write backend request") from error + if written <= 0: + raise BackendFailure("backend request write made no progress") + offset += written + input_state["offset"] = offset + if offset == len(payload): + self._close_selector_file(selector, key.fileobj) + try: + key.fileobj.close() + except OSError as error: + raise BackendFailure("cannot close backend request stream") from error + input_state["open"] = False + continue try: chunk = os.read(key.fd, min(64 * 1024, limit - len(buffers[stream]) + 1)) except BlockingIOError: @@ -609,7 +959,7 @@ def _drain_to_eof( selector: selectors.BaseSelector, buffers: dict[str, bytearray], open_streams: set[str], - wake_reader: socket.socket, + wake_reader: int, ) -> None: deadline = time.monotonic() + max(1.0, self.terminate_grace * 4) while open_streams: @@ -622,6 +972,7 @@ def _drain_to_eof( open_streams, wake_reader, min(self.leader_poll_interval, remaining), + None, ) @staticmethod @@ -634,37 +985,77 @@ def _parse_backend_output(raw: bytes) -> dict[str, Any]: raise BackendFailure("backend stdout is not a JSON object") return value + @staticmethod + def _unwrap_stdio_result( + value: dict[str, Any], request_id: str, + ) -> dict[str, Any]: + if set(value) != {"jsonrpc", "id", "result"} \ + or value.get("jsonrpc") != "2.0" \ + or value.get("id") != request_id \ + or not isinstance(value.get("result"), dict): + raise BackendFailure("backend stdio response envelope is invalid") + return cast(dict[str, Any], value["result"]) + def run(self) -> dict[str, Any]: """Run, bound, terminate, and reap one process group in one worker thread.""" + guardian_reader = -1 + guardian_writer = -1 + command = list(self.command) + popen_arguments: dict[str, object] = {} + if self.process_guardian is not None: + try: + guardian_reader, guardian_writer = os.pipe() + except OSError as error: + raise BackendFailure("backend guardian pipe creation failed") from error + command = [ + *self.process_guardian, + str(guardian_reader), + *command, + ] + popen_arguments["pass_fds"] = (guardian_reader,) try: process = subprocess.Popen( - list(self.command), + command, cwd=str(self.cwd), env=self.environment, - stdin=subprocess.DEVNULL, + stdin=(subprocess.PIPE if self.stdin_bytes is not None + else subprocess.DEVNULL), stdout=subprocess.PIPE, stderr=subprocess.PIPE, start_new_session=True, close_fds=True, bufsize=0, + **popen_arguments, ) except (OSError, ValueError) as error: + for descriptor in (guardian_reader, guardian_writer): + if descriptor >= 0: + with contextlib.suppress(OSError): + os.close(descriptor) raise BackendFailure("backend failed to start") from error + if guardian_reader >= 0: + os.close(guardian_reader) + guardian_reader = -1 self.state.process = process selector: selectors.BaseSelector | None = None - wake_reader: socket.socket | None = None - wake_writer: socket.socket | None = None + wake_reader: int | None = None + wake_writer: int | None = None buffers = {"stdout": bytearray(), "stderr": bytearray()} open_streams = {"stdout", "stderr"} + input_state: dict[str, Any] | None = None cleanup_done = False try: try: selector = selectors.DefaultSelector() - wake_reader, wake_writer = socket.socketpair() - wake_reader.setblocking(False) - wake_writer.setblocking(False) + wake_reader, wake_writer = os.pipe() + os.set_blocking(wake_reader, False) + os.set_blocking(wake_writer, False) except (OSError, ValueError) as error: + for descriptor in (wake_reader, wake_writer): + if descriptor is not None: + with contextlib.suppress(OSError): + os.close(descriptor) raise BackendFailure("backend monitor setup failed") from error if process.stdout is None or process.stderr is None: raise BackendFailure("backend pipes unavailable") @@ -677,11 +1068,23 @@ def run(self) -> dict[str, Any]: selector.register( process.stderr, selectors.EVENT_READ, ("stderr", self.stderr_limit) ) + if self.stdin_bytes is not None: + if process.stdin is None: + raise BackendFailure("backend request pipe is unavailable") + os.set_blocking(process.stdin.fileno(), False) + input_state = { + "payload": self.stdin_bytes, + "offset": 0, + "open": True, + } + selector.register( + process.stdin, selectors.EVENT_WRITE, ("stdin", len(self.stdin_bytes)) + ) with self._wake_lock: self._wake_writer = wake_writer if self._cancelled.is_set(): with contextlib.suppress(OSError): - wake_writer.send(b"\0") + os.write(wake_writer, b"\0") deadline = time.monotonic() + self.timeout outcome: BackendFailure | None = None @@ -703,10 +1106,15 @@ def run(self) -> dict[str, Any]: open_streams, wake_reader, min(self.leader_poll_interval, remaining), + input_state, ) except BackendFailure as error: outcome = error + if outcome is None and input_state is not None \ + and input_state.get("offset") != len(self.stdin_bytes or b""): + outcome = BackendFailure("backend exited before reading its complete request") + status = self._terminate_and_reap(process) cleanup_done = True if outcome is None and self._cancelled.is_set(): @@ -718,11 +1126,14 @@ def run(self) -> dict[str, Any]: if self._cancelled.is_set(): raise CallCancelled("request cancelled before backend result delivery") value = self._parse_backend_output(bytes(buffers["stdout"])) + if self.stdio_request_id is not None: + value = self._unwrap_stdio_result(value, self.stdio_request_id) if self._cancelled.is_set(): raise CallCancelled("request cancelled before backend result delivery") if status == 0: return value - if status == 1 and value.get("status") in {"ok", "refused", "indeterminate"}: + if self.stdio_request_id is None and status == 1 \ + and value.get("status") in {"ok", "refused", "indeterminate"}: return value raise BackendFailure("backend returned a non-domain failure") finally: @@ -734,7 +1145,7 @@ def run(self) -> dict[str, Any]: with self._wake_lock: if self._wake_writer is wake_writer: self._wake_writer = None - for file_object in (process.stdout, process.stderr): + for file_object in (process.stdin, process.stdout, process.stderr): if file_object is not None: if selector is not None: self._close_selector_file(selector, file_object) @@ -745,9 +1156,14 @@ def run(self) -> dict[str, Any]: self._close_selector_file(selector, wake_reader) selector.close() if wake_reader is not None: - wake_reader.close() + with contextlib.suppress(OSError): + os.close(wake_reader) if wake_writer is not None: - wake_writer.close() + with contextlib.suppress(OSError): + os.close(wake_writer) + if guardian_writer >= 0: + with contextlib.suppress(OSError): + os.close(guardian_writer) self.state.process = None @@ -987,6 +1403,78 @@ def _read_plugin_module_once( os.close(file_descriptor) +def _read_verified_plugin_blob( + plugin_root: Path | str, + relative_path: str, + records: object, + *, + limit: int, +) -> tuple[bytes, str]: + expected = _record_digest(records, relative_path) + raw, actual = _read_plugin_module_once(plugin_root, relative_path, limit=limit) + if not hmac.compare_digest(actual, expected): + raise StartupError("plugin data digest does not match inventory") + return raw, actual + + +def _decompress_certificate(raw: bytes) -> bytes: + if not raw or len(raw) > MAX_CERTIFICATE_COMPRESSED_BYTES: + raise StartupError("compressed certificate exceeds byte limit") + decompressor = zlib.decompressobj() + try: + result = decompressor.decompress(raw, MAX_CERTIFICATE_BYTES + 1) + if len(result) > MAX_CERTIFICATE_BYTES or decompressor.unconsumed_tail: + raise StartupError("decompressed certificate exceeds byte limit") + result += decompressor.flush(MAX_CERTIFICATE_BYTES - len(result) + 1) + except zlib.error as error: + raise StartupError("certificate compression stream is invalid") from error + if ( + len(result) > MAX_CERTIFICATE_BYTES + or not decompressor.eof + or decompressor.unused_data + or decompressor.unconsumed_tail + ): + raise StartupError("certificate compression stream is not canonical") + return result + + +def _hellgate_result_satisfies_startup_gate(value: object) -> bool: + """Pin the additive certificate result envelope before exposing the tool.""" + if not isinstance(value, dict): + return False + fields = value.get("fields") + if not isinstance(fields, dict): + return False + trial = fields.get("trial_diagnostics") + ground = fields.get("ground_state_transfer") + if not isinstance(trial, dict) or not isinstance(ground, dict): + return False + trial_nonclaims = trial.get("non_claims") + ground_nonclaims = ground.get("non_claims") + return bool( + value.get("status") == "bounded" + and value.get("checker_verdict") == "ACCEPT" + and value.get("formal") is False + and trial.get("schema") == "jackal-hellgate-trial-diagnostics-v1" + and trial.get("status") == "bounded" + and trial.get("subject") == "normalized-certificate-trial-phi" + and isinstance(trial_nonclaims, list) + and any( + isinstance(item, str) and "not the exact ground state u0" in item + for item in trial_nonclaims + ) + and ground.get("schema") == "jackal-hellgate-ground-transfer-v1" + and ground.get("status") == "bounded" + and ground.get("subject") == "positive-normalized-ground-state-u0" + and ground.get("method") == "lambda-strong-convexity-density-transfer-v1" + and isinstance(ground_nonclaims, list) + and any( + isinstance(item, str) and "does not enclose polynomial moments" in item + for item in ground_nonclaims + ) + ) + + def _record_digest(records: object, relative_path: str) -> str: if isinstance(records, Mapping): expected = records.get(relative_path) @@ -1162,6 +1650,13 @@ def __init__( terminate_grace: float = TERMINATE_GRACE_SECONDS, leader_poll_interval: float = LEADER_POLL_SECONDS, runtime_owner: object | None = None, + process_guardian: Sequence[str] | None = None, + measurement_module: ModuleType | None = None, + measurement_identity: str | None = None, + advanced_module: ModuleType | None = None, + advanced_identity: str | None = None, + stem_module: ModuleType | None = None, + stem_identity: str | None = None, ) -> None: if ( tool_timeout <= 0 @@ -1176,6 +1671,14 @@ def __init__( or leader_poll_interval <= 0 ): raise ValueError("invalid MCP process bounds") + if process_guardian is not None and ( + not process_guardian + or any( + not isinstance(argument, str) or not argument or "\x00" in argument + for argument in process_guardian + ) + ): + raise ValueError("invalid MCP process guardian") self.runtime_root = Path(runtime_root) self.launcher = Path(launcher) self.tool_definitions = tuple(copy.deepcopy(tuple(tool_definitions))) @@ -1197,6 +1700,74 @@ def __init__( self.stderr_limit = int(stderr_limit) self.terminate_grace = float(terminate_grace) self.leader_poll_interval = float(leader_poll_interval) + self.process_guardian = ( + None if process_guardian is None else tuple(process_guardian) + ) + if measurement_module is None: + if measurement_identity is not None: + raise ValueError("measurement identity has no module") + self._measurement_tools = frozenset() + else: + if ( + not isinstance(measurement_identity, str) + or re.fullmatch(r"[0-9a-f]{64}", measurement_identity) is None + ): + raise ValueError("measurement module identity is invalid") + module_names = getattr(measurement_module, "MEASUREMENT_TOOL_NAMES", None) + if module_names != MEASUREMENT_TOOL_NAMES: + raise ValueError("measurement module names are invalid") + self._measurement_tools = MEASUREMENT_TOOL_NAMES + if self._measurement_tools - set(self._tools): + raise ValueError("measurement module definitions are missing") + if measurement_module is None and set(self._tools) & MEASUREMENT_TOOL_NAMES: + raise ValueError("measurement definitions have no pinned dispatcher") + self.measurement_module = measurement_module + self.measurement_identity = measurement_identity + if advanced_module is None: + if advanced_identity is not None: + raise ValueError("advanced identity has no module") + self._advanced_tools = frozenset() + else: + if ( + not isinstance(advanced_identity, str) + or re.fullmatch(r"[0-9a-f]{64}", advanced_identity) is None + ): + raise ValueError("advanced module identity is invalid") + module_names = getattr(advanced_module, "ADVANCED_TOOL_NAMES", None) + module_routes = getattr(advanced_module, "CAS_ROUTES", None) + if ( + module_names != ADVANCED_TOOL_NAMES + or not isinstance(module_routes, dict) + or set(module_routes.values()) - ADVANCED_KERNEL_TOOLS + ): + raise ValueError("advanced module routes or names are invalid") + self._advanced_tools = ADVANCED_TOOL_NAMES + if self._advanced_tools - set(self._tools): + raise ValueError("advanced module definitions are missing") + if advanced_module is None and set(self._tools) & ADVANCED_TOOL_NAMES: + raise ValueError("advanced definitions have no pinned dispatcher") + self.advanced_module = advanced_module + self.advanced_identity = advanced_identity + if stem_module is None: + if stem_identity is not None: + raise ValueError("STEM identity has no module") + self._stem_tools = frozenset() + else: + if ( + not isinstance(stem_identity, str) + or re.fullmatch(r"[0-9a-f]{64}", stem_identity) is None + ): + raise ValueError("STEM module identity is invalid") + module_names = getattr(stem_module, "STEM_TOOL_NAMES", None) + if module_names != STEM_TOOL_NAMES: + raise ValueError("STEM module names are invalid") + self._stem_tools = STEM_TOOL_NAMES + if self._stem_tools - set(self._tools): + raise ValueError("STEM module definitions are missing") + if stem_module is None and set(self._tools) & STEM_TOOL_NAMES: + raise ValueError("STEM definitions have no pinned dispatcher") + self.stem_module = stem_module + self.stem_identity = stem_identity self._backend_lock = asyncio.Lock() self._active: dict[str | int, _CallState] = {} self._closed = False @@ -1307,11 +1878,21 @@ async def _dispatch( negotiated = protocol if protocol in SUPPORTED_PROTOCOL_VERSIONS else LATEST_PROTOCOL_VERSION return { "protocolVersion": negotiated, - "capabilities": {"tools": {"listChanged": False}}, + "capabilities": { + "tools": {"listChanged": False}, + "resources": {"subscribe": False, "listChanged": False}, + }, "serverInfo": {"name": "jackel-codex", "version": "0.1.0"}, "instructions": ( "Preserve JACKAL status and evidence class exactly. " - "Unsupported strong claims refuse; never silently downgrade." + "Unsupported strong claims refuse; never silently downgrade. " + "THOTH is JACKAL's identity-pinned measurement/provenance subsystem, " + "not a separate service; exact-given remains conditional on its given datum. " + "CAS routing preserves delegated assurance. Graph pixels are visualization, " + "never evidence. The HELLGATE lane returns bounded, not formal-bounded. " + "Matrices, regression, probability, sensors, aerospace models, and linked " + "views are additive identity-pinned workflows; field status, assumptions, " + "non-claims, and consequence ceilings remain controlling." ), } if method == "ping": @@ -1326,6 +1907,58 @@ async def _dispatch( if "cursor" in params and not isinstance(params["cursor"], str): raise ProtocolError(INVALID_PARAMS, "tools/list cursor must be a string", request_id) return {"tools": list(copy.deepcopy(self.tool_definitions))} + if method == "resources/list": + if set(params) - {"cursor", "_meta"}: + raise ProtocolError(INVALID_PARAMS, "invalid resources/list params", request_id) + _validate_meta(params) + if "cursor" in params and not isinstance(params["cursor"], str): + raise ProtocolError( + INVALID_PARAMS, "resources/list cursor must be a string", request_id + ) + if self.stem_module is None: + return {"resources": []} + return { + "resources": [ + { + "uri": LINKED_WORKSPACE_SHELL_URI, + "name": "jackal-linked-evidence-workspace", + "title": "JACKAL Linked Evidence Workspace", + "description": ( + "Professional linked symbolic, numeric, graph, table, sensor, " + "and evidence-route shell. Call jackal_linked_workspace to populate it." + ), + "mimeType": "text/html", + } + ] + } + if method == "resources/read": + if set(params) - {"uri", "_meta"} or "uri" not in params: + raise ProtocolError(INVALID_PARAMS, "resources/read requires uri", request_id) + _validate_meta(params) + if params["uri"] != LINKED_WORKSPACE_SHELL_URI or self.stem_module is None: + raise ProtocolError(INVALID_PARAMS, "unknown resource uri", request_id) + shell = getattr(self.stem_module, "workspace_shell", None) + if not callable(shell): + raise BackendFailure("STEM resource API changed") + try: + resource_text = shell() + except Exception as error: + raise BackendFailure("STEM resource generation failed closed") from error + if ( + not isinstance(resource_text, str) + or not resource_text.startswith("") + or len(resource_text.encode("utf-8")) > MAX_MCP_RESOURCE_TEXT_BYTES + ): + raise BackendFailure("STEM resource contents are invalid") + return { + "contents": [ + { + "uri": LINKED_WORKSPACE_SHELL_URI, + "mimeType": "text/html", + "text": resource_text, + } + ] + } if method == "tools/call": if set(params) - {"name", "arguments", "_meta"} or not { "name", "arguments" @@ -1391,42 +2024,361 @@ async def _invoke_serialized( try: if state.cancelled.is_set(): raise CallCancelled("request was cancelled before launch") + if name in self._measurement_tools: + return await self._invoke_measurement(state, name, arguments) + if name in self._advanced_tools: + return await self._invoke_advanced(state, name, arguments) + if name in self._stem_tools: + return await self._invoke_stem(state, name, arguments) return await self._invoke_backend(state, name, arguments) finally: self._backend_lock.release() - async def _invoke_backend( + def _new_backend_runner( self, state: _CallState, name: str, arguments: dict[str, Any] - ) -> dict[str, Any]: - compact_arguments = json.dumps( - arguments, + ) -> _AnchoredBackendRunner: + request = json.dumps( + { + "jsonrpc": "2.0", + "id": BACKEND_RPC_REQUEST_ID, + "method": name, + "params": arguments, + }, ensure_ascii=False, allow_nan=False, sort_keys=True, separators=(",", ":"), - ) - runner = _AnchoredBackendRunner( + ).encode("utf-8") + b"\n" + if len(request) > MAX_REQUEST_LINE_BYTES: + raise BackendFailure("encoded backend request exceeds byte limit") + return _AnchoredBackendRunner( state=state, - command=(str(self.launcher), "call", name, compact_arguments), + command=(str(self.launcher), "stdio"), cwd=self.runtime_root, environment=self.runtime_environment, timeout=self.tool_timeout, - stdout_limit=self.stdout_limit, + stdout_limit=self.stdout_limit + MAX_ERROR_RESPONSE_BYTES, stderr_limit=self.stderr_limit, terminate_grace=self.terminate_grace, leader_poll_interval=self.leader_poll_interval, + process_guardian=self.process_guardian, + stdin_bytes=request, + stdio_request_id=BACKEND_RPC_REQUEST_ID, ) + + def _invoke_backend_sync( + self, state: _CallState, name: str, arguments: dict[str, Any] + ) -> dict[str, Any]: + if state.cancelled.is_set(): + raise CallCancelled("request was cancelled before backend launch") + if state.process is not None or state.runner is not None: + raise BackendFailure("backend process lifecycle overlaps another launch") + # Cancellation belongs to the whole MCP request; process observation + # does not. Integrated measurement calls may legitimately delegate to + # the sealed runtime more than once, so each child starts with a fresh + # WNOWAIT/reap state instead of inheriting the preceding child's exit. + state.term_sent = False + state.kill_sent = False + state.anchor_lost = False + state.leader_status = None + state.reaped = False + runner = self._new_backend_runner(state, name, arguments) state.runner = runner - worker = asyncio.create_task(asyncio.to_thread(runner.run)) + try: + return runner.run() + finally: + if state.runner is runner: + state.runner = None + + def _invoke_measurement_sync( + self, state: _CallState, name: str, arguments: dict[str, Any] + ) -> dict[str, Any]: + module = self.measurement_module + identity = self.measurement_identity + if module is None or identity is None: + raise BackendFailure("measurement dispatcher is unavailable") + dispatcher = getattr(module, "dispatch_integrated", None) + refusal_type = getattr(module, "Refusal", None) + if not callable(dispatcher) or not isinstance(refusal_type, type): + raise BackendFailure("measurement dispatcher API changed") + + def kernel_call(tool: str, delegated_arguments: dict[str, Any]) -> dict[str, Any]: + if tool not in MEASUREMENT_KERNEL_TOOLS: + raise refusal_type( + "kernel-tool-forbidden", + f"measurement orchestration requested unauthorized runtime tool {tool!r}", + ) + if not isinstance(delegated_arguments, dict): + raise refusal_type( + "kernel-error", "measurement orchestration produced invalid arguments" + ) + try: + return self._invoke_backend_sync(state, tool, delegated_arguments) + except CallCancelled: + raise + except BackendTimedOut as error: + raise refusal_type( + "kernel-timeout", + "the JACKAL runtime timed out; no measurement-side arithmetic was substituted", + ) from error + except BackendFailure as error: + raise refusal_type( + "kernel-unavailable", + "the JACKAL runtime failed closed; no measurement-side arithmetic was substituted", + ) from error + + value = dispatcher(name, arguments, kernel_call, identity) + if not isinstance(value, dict): + raise BackendFailure("measurement dispatcher returned a non-object") + return value + + def _invoke_advanced_sync( + self, state: _CallState, name: str, arguments: dict[str, Any] + ) -> dict[str, Any]: + module = self.advanced_module + identity = self.advanced_identity + if module is None or identity is None: + raise BackendFailure("advanced dispatcher is unavailable") + dispatcher = getattr(module, "dispatch_integrated", None) + refusal_type = getattr(module, "Refusal", None) + if not callable(dispatcher) or not isinstance(refusal_type, type): + raise BackendFailure("advanced dispatcher API changed") + + def kernel_call(tool: str, delegated_arguments: dict[str, Any]) -> dict[str, Any]: + if tool not in ADVANCED_KERNEL_TOOLS: + raise refusal_type( + "kernel-tool-forbidden", + f"advanced orchestration requested unauthorized runtime tool {tool!r}", + ) + if not isinstance(delegated_arguments, dict): + raise refusal_type( + "kernel-error", "advanced orchestration produced invalid arguments" + ) + try: + return self._invoke_backend_sync(state, tool, delegated_arguments) + except CallCancelled: + raise + except BackendTimedOut as error: + raise refusal_type( + "kernel-timeout", + "the JACKAL runtime timed out; no advanced-side arithmetic was substituted", + ) from error + except BackendFailure as error: + raise refusal_type( + "kernel-unavailable", + "the JACKAL runtime failed closed; no advanced-side arithmetic was substituted", + ) from error + + value = dispatcher(name, arguments, kernel_call, identity) + if not isinstance(value, dict): + raise BackendFailure("advanced dispatcher returned a non-object") + return value + + def _invoke_stem_sync( + self, state: _CallState, name: str, arguments: dict[str, Any] + ) -> dict[str, Any]: + module = self.stem_module + identity = self.stem_identity + if module is None or identity is None: + raise BackendFailure("STEM dispatcher is unavailable") + dispatcher = getattr(module, "dispatch_integrated", None) + refusal_type = getattr(module, "Refusal", None) + if not callable(dispatcher) or not isinstance(refusal_type, type): + raise BackendFailure("STEM dispatcher API changed") + + def kernel_call(tool: str, delegated_arguments: dict[str, Any]) -> dict[str, Any]: + if tool not in STEM_KERNEL_TOOLS: + raise refusal_type( + "kernel-tool-forbidden", + f"STEM orchestration requested unauthorized runtime tool {tool!r}", + ) + if not isinstance(delegated_arguments, dict): + raise refusal_type( + "kernel-error", "STEM orchestration produced invalid arguments" + ) + try: + return self._invoke_backend_sync(state, tool, delegated_arguments) + except CallCancelled: + raise + except BackendTimedOut as error: + raise refusal_type( + "kernel-timeout", + "the JACKAL runtime timed out; no STEM-side arithmetic was substituted", + ) from error + except BackendFailure as error: + raise refusal_type( + "kernel-unavailable", + "the JACKAL runtime failed closed; no STEM-side arithmetic was substituted", + ) from error + + value = dispatcher(name, arguments, kernel_call, identity) + if not isinstance(value, dict): + raise BackendFailure("STEM dispatcher returned a non-object") + return value + + async def _run_sync_worker( + self, operation: Callable[[], dict[str, Any]] + ) -> dict[str, Any]: + """Run one process-owning operation without asyncio's global executor. + + A dedicated joinable thread keeps lifetime ownership local to this + server. The event loop polls a threading event at the existing leader + interval, so completion and cancellation do not depend on a platform's + cross-thread selector wakeup behavior. + """ + completed = threading.Event() + outcome: dict[str, object] = {} + + def run() -> None: + try: + outcome["value"] = operation() + except BaseException as error: + outcome["error"] = error + finally: + completed.set() + + thread = threading.Thread(target=run, name="jackal-backend", daemon=False) + thread.start() + while not completed.is_set(): + await asyncio.sleep(THREAD_WORKER_POLL_SECONDS) + thread.join() + error = outcome.get("error") + if isinstance(error, BaseException): + raise error + value = outcome.get("value") + if not isinstance(value, dict): + raise BackendFailure("backend worker returned a non-object") + return cast(dict[str, Any], value) + + async def _await_worker_result( + self, worker: asyncio.Task[dict[str, Any]] + ) -> dict[str, Any]: + """Await a thread worker with a bounded event-loop wake interval. + + Some supported Python/event-loop combinations can leave the selector + asleep after a thread-safe completion notification. A short bounded + wait preserves prompt completion and cancellation without ever + cancelling the process-owning worker task. + """ + while not worker.done(): + await asyncio.wait( + {worker}, timeout=THREAD_WORKER_POLL_SECONDS, + return_when=asyncio.FIRST_COMPLETED, + ) + return worker.result() + + async def _invoke_measurement( + self, state: _CallState, name: str, arguments: dict[str, Any] + ) -> dict[str, Any]: + worker = asyncio.create_task( + self._run_sync_worker( + lambda: self._invoke_measurement_sync(state, name, arguments) + ) + ) state.worker = worker try: - return await asyncio.shield(worker) + return await self._await_worker_result(worker) except asyncio.CancelledError: state.cancelled.set() - runner.cancel() + runner = state.runner + if runner is not None: + runner.cancel() while not worker.done(): try: - await asyncio.shield(worker) + await asyncio.wait( + {worker}, timeout=THREAD_WORKER_POLL_SECONDS, + return_when=asyncio.FIRST_COMPLETED, + ) + except asyncio.CancelledError: + continue + except Exception: + break + raise + finally: + state.worker = None + + async def _invoke_advanced( + self, state: _CallState, name: str, arguments: dict[str, Any] + ) -> dict[str, Any]: + worker = asyncio.create_task( + self._run_sync_worker( + lambda: self._invoke_advanced_sync(state, name, arguments) + ) + ) + state.worker = worker + try: + return await self._await_worker_result(worker) + except asyncio.CancelledError: + state.cancelled.set() + runner = state.runner + if runner is not None: + runner.cancel() + while not worker.done(): + try: + await asyncio.wait( + {worker}, timeout=THREAD_WORKER_POLL_SECONDS, + return_when=asyncio.FIRST_COMPLETED, + ) + except asyncio.CancelledError: + continue + except Exception: + break + raise + finally: + state.worker = None + + async def _invoke_stem( + self, state: _CallState, name: str, arguments: dict[str, Any] + ) -> dict[str, Any]: + worker = asyncio.create_task( + self._run_sync_worker( + lambda: self._invoke_stem_sync(state, name, arguments) + ) + ) + state.worker = worker + try: + return await self._await_worker_result(worker) + except asyncio.CancelledError: + state.cancelled.set() + runner = state.runner + if runner is not None: + runner.cancel() + while not worker.done(): + try: + await asyncio.wait( + {worker}, timeout=THREAD_WORKER_POLL_SECONDS, + return_when=asyncio.FIRST_COMPLETED, + ) + except asyncio.CancelledError: + continue + except Exception: + break + raise + finally: + state.worker = None + + async def _invoke_backend( + self, state: _CallState, name: str, arguments: dict[str, Any] + ) -> dict[str, Any]: + worker = asyncio.create_task( + self._run_sync_worker( + lambda: self._invoke_backend_sync(state, name, arguments) + ) + ) + state.worker = worker + try: + return await self._await_worker_result(worker) + except asyncio.CancelledError: + state.cancelled.set() + runner = state.runner + if runner is not None: + runner.cancel() + while not worker.done(): + try: + await asyncio.wait( + {worker}, timeout=THREAD_WORKER_POLL_SECONDS, + return_when=asyncio.FIRST_COMPLETED, + ) except asyncio.CancelledError: continue except Exception: @@ -1434,7 +2386,6 @@ async def _invoke_backend( raise finally: state.worker = None - state.runner = None def _cancel_request(self, request_id: str | int) -> None: state = self._active.get(request_id) @@ -1484,6 +2435,7 @@ def build_production_server( plugin_root: Path | str | None = None, environ: Mapping[str, str] | None = None, locator_path: Path | str | None = None, + snapshot_parent: Path | str | None = None, provisioner: _ProvisionerAPI | None = None, identity_verifier: Callable[[Path, Path], object] | None = None, runtime_validator: Callable[..., object] | None = None, @@ -1492,6 +2444,7 @@ def build_production_server( root = plugin_root_from_server() if plugin_root is None else Path(plugin_root) if not root.is_absolute(): raise StartupError("plugin root must be absolute") + require_integrated_modules = identity_verifier is None inventory: dict[str, str] | None = None if identity_verifier is None: inventory = _read_identity_inventory(root) @@ -1508,9 +2461,114 @@ def build_production_server( raise StartupError("plugin identity verification refused") from error if inventory is not None and _inventory_from_records(verified_records) != inventory: raise StartupError("plugin identity records changed during verification") + if inventory is None: + inventory = _inventory_from_records(verified_records) + + measurement_module: ModuleType | None = None + measurement_identity: str | None = None + measurement_definitions: tuple[dict[str, Any], ...] = () + if "mcp/measurement.py" in inventory: + measurement_module = _load_verified_module( + root, + "mcp/measurement.py", + "jackel_codex_measurement", + inventory, + ) + measurement_identity = _record_digest(inventory, "mcp/measurement.py") + try: + measurement_definitions = build_measurement_tool_definitions( + measurement_module + ) + except CatalogError as error: + raise StartupError("measurement tool surface refused") from error + elif require_integrated_modules: + raise StartupError("plugin identity omits the measurement module") + + advanced_module: ModuleType | None = None + advanced_identity: str | None = None + advanced_definitions: tuple[dict[str, Any], ...] = () + if "mcp/advanced.py" in inventory: + advanced_module = _load_verified_module( + root, + "mcp/advanced.py", + "jackel_codex_advanced", + inventory, + ) + checker_module = _load_verified_module( + root, + "mcp/hellgate_verify.py", + "jackel_codex_hellgate_verify", + inventory, + ) + certificate_path = "mcp/certificates/hellgate_v1.json.zlib" + compressed_certificate, certificate_file_identity = _read_verified_plugin_blob( + root, + certificate_path, + inventory, + limit=MAX_CERTIFICATE_COMPRESSED_BYTES, + ) + certificate = _decompress_certificate(compressed_certificate) + verifier = getattr(checker_module, "verify_bytes", None) + refusal_type = getattr(checker_module, "VerificationRefusal", None) + if ( + not callable(verifier) + or not isinstance(refusal_type, type) + or not issubclass(refusal_type, Exception) + ): + raise StartupError("HELLGATE checker API is invalid") + try: + hellgate_result = verifier(certificate) + except refusal_type as error: + raise StartupError("HELLGATE certificate verification refused") from error + except Exception as error: + raise StartupError("HELLGATE certificate checker failed closed") from error + if not _hellgate_result_satisfies_startup_gate(hellgate_result): + raise StartupError("HELLGATE certificate did not satisfy the startup gate") + advanced_identity = _record_digest(inventory, "mcp/advanced.py") + configure = getattr(advanced_module, "configure_hellgate", None) + if not callable(configure): + raise StartupError("advanced certificate configuration API is invalid") + try: + configure( + hellgate_result, + advanced_sha256=advanced_identity, + checker_sha256=_record_digest(inventory, "mcp/hellgate_verify.py"), + certificate_sha256=certificate_file_identity, + ) + advanced_definitions = build_advanced_tool_definitions(advanced_module) + except Exception as error: + raise StartupError("advanced tool surface refused") from error + elif require_integrated_modules: + raise StartupError("plugin identity omits the advanced module") + + stem_module: ModuleType | None = None + stem_identity: str | None = None + stem_definitions: tuple[dict[str, Any], ...] = () + if "mcp/stem.py" in inventory: + stem_module = _load_verified_module( + root, + "mcp/stem.py", + "jackel_codex_stem", + inventory, + ) + stem_identity = _record_digest(inventory, "mcp/stem.py") + try: + stem_definitions = build_stem_tool_definitions(stem_module) + shell = getattr(stem_module, "workspace_shell", None) + if not callable(shell): + raise CatalogError("STEM resource API is invalid") + shell_text = shell() + if ( + not isinstance(shell_text, str) + or not shell_text.startswith("") + or len(shell_text.encode("utf-8")) > MAX_MCP_RESOURCE_TEXT_BYTES + ): + raise CatalogError("STEM resource shell is invalid") + except Exception as error: + raise StartupError("STEM tool or resource surface refused") from error + elif require_integrated_modules: + raise StartupError("plugin identity omits the STEM module") if provisioner is None: - if inventory is None: - inventory = _inventory_from_records(verified_records) provisioner = cast( _ProvisionerAPI, _load_verified_module( @@ -1524,6 +2582,10 @@ def build_production_server( provisioner.validate_host() except Exception as error: raise StartupError("unsupported production host") from error + try: + provisioner.reap_orphaned_runtime_snapshots() + except Exception as error: + raise StartupError("orphaned runtime snapshot cleanup refused") from error runtime = resolve_runtime_path( environ=environ, @@ -1544,12 +2606,16 @@ def build_production_server( snapshot_owner: object | None = None try: - snapshot_owner = provisioner.create_runtime_snapshot( - runtime, - timeout=provisioner.SELFTEST_TIMEOUT, - output_limit=provisioner.SELFTEST_OUTPUT_LIMIT, - expected_tree_sha256=provisioner.effective_release_pins()["sha256sums_sha256"], - ) + snapshot_arguments: dict[str, object] = { + "timeout": provisioner.SELFTEST_TIMEOUT, + "output_limit": provisioner.SELFTEST_OUTPUT_LIMIT, + "expected_tree_sha256": provisioner.effective_release_pins()[ + "sha256sums_sha256" + ], + } + if snapshot_parent is not None: + snapshot_arguments["temporary_parent"] = os.fspath(snapshot_parent) + snapshot_owner = provisioner.create_runtime_snapshot(runtime, **snapshot_arguments) snapshot_value = getattr(snapshot_owner, "root", None) snapshot = _canonical_absolute_directory( os.fspath(snapshot_value) if isinstance(snapshot_value, (Path, str)) else None, @@ -1560,7 +2626,34 @@ def build_production_server( raise StartupError("runtime snapshot is not private and independent") _verify_package_metadata(snapshot, provisioner) catalog = _load_catalog(snapshot / "plugin/hermes/tools.json") - definitions = build_tool_definitions(catalog, expected_count=EXPECTED_TOOL_COUNT) + runtime_definitions = build_tool_definitions( + catalog, expected_count=EXPECTED_TOOL_COUNT + ) + definitions = ( + runtime_definitions + + measurement_definitions + + advanced_definitions + + stem_definitions + ) + expected_surface_count = EXPECTED_TOOL_COUNT + if measurement_module is not None: + expected_surface_count += EXPECTED_MEASUREMENT_TOOL_COUNT + if advanced_module is not None: + expected_surface_count += EXPECTED_ADVANCED_TOOL_COUNT + if stem_module is not None: + expected_surface_count += EXPECTED_STEM_TOOL_COUNT + if ( + measurement_module is not None + and advanced_module is not None + and stem_module is not None + and expected_surface_count != EXPECTED_UNIFIED_TOOL_COUNT + ): + raise StartupError("unified tool surface constant is inconsistent") + if len(definitions) != expected_surface_count: + raise StartupError("unified tool surface count is inconsistent") + definition_names = [definition["name"] for definition in definitions] + if len(set(definition_names)) != len(definition_names): + raise StartupError("unified tool surface contains duplicate names") launcher = snapshot / "plugin/hermes/jackal_hermes" try: launcher_info = launcher.lstat() @@ -1583,6 +2676,12 @@ def build_production_server( runtime_environment=runtime_environment, tool_timeout=TOOL_TIMEOUT_SECONDS, runtime_owner=snapshot_owner, + measurement_module=measurement_module, + measurement_identity=measurement_identity, + advanced_module=advanced_module, + advanced_identity=advanced_identity, + stem_module=stem_module, + stem_identity=stem_identity, ) except Exception as error: cleanup_error: Exception | None = None @@ -1853,9 +2952,496 @@ def _bounded_detail(error: Exception) -> str: return (" ".join(str(error).splitlines()).strip() or "startup failed")[:240] -def main() -> int: +class _GuardedProcessProxy: + """Keep the guardian liveness writer open for one delegated Popen.""" + + def __init__(self, process: subprocess.Popen, liveness_writer: int) -> None: + self._process = process + self._liveness_writer = liveness_writer + + def close_liveness(self) -> None: + if self._liveness_writer < 0: + return + with contextlib.suppress(OSError): + os.close(self._liveness_writer) + self._liveness_writer = -1 + + def __getattr__(self, name: str) -> Any: + return getattr(self._process, name) + + +def _guarded_popen_factory( + guardian_prefix: Sequence[str], + owners: list[_GuardedProcessProxy], +) -> Callable: + def spawn(command: Sequence[str], **arguments: Any) -> _GuardedProcessProxy: + reader = -1 + writer = -1 + try: + reader, writer = os.pipe() + process = subprocess.Popen( + [*guardian_prefix, str(reader), *command], + pass_fds=(reader,), + **arguments, + ) + except (OSError, ValueError, subprocess.SubprocessError): + for descriptor in (reader, writer): + if descriptor >= 0: + with contextlib.suppress(OSError): + os.close(descriptor) + raise + os.close(reader) + owner = _GuardedProcessProxy(process, writer) + owners.append(owner) + return owner + + return spawn + + +def _guarded_selftest_runner( + provisioner: _ProvisionerAPI, + guardian_prefix: Sequence[str] | None, +) -> Callable | None: + if guardian_prefix is None: + return None + selftest = getattr(provisioner, "_run_selftest", None) + if not callable(selftest): + return None + + def run(command: list[str], *, timeout: float, output_limit: int): + owners: list[_GuardedProcessProxy] = [] + try: + return selftest( + command, + timeout=timeout, + output_limit=output_limit, + popen_factory=_guarded_popen_factory(guardian_prefix, owners), + ) + finally: + for owner in owners: + owner.close_liveness() + + return run + + +def _process_guardian_prefix() -> tuple[str, ...]: + try: + python = os.fspath(Path(sys.executable).resolve(strict=True)) + server_path = os.fspath(Path(__file__).resolve(strict=True)) + except OSError as error: + raise StartupError("process guardian executable identity is unavailable") from error + return ( + python, + "-I", + "-S", + "-B", + server_path, + PROCESS_GUARDIAN_FLAG, + ) + + +def _parse_process_guardian( + arguments: Sequence[str], +) -> tuple[int, tuple[str, ...]] | None: + if not arguments or arguments[0] != PROCESS_GUARDIAN_FLAG: + return None + if len(arguments) < 3 or not arguments[1].isdecimal(): + raise StartupError("invalid process guardian arguments") + liveness_fd = int(arguments[1]) + command = tuple(arguments[2:]) + if ( + liveness_fd < 3 + or not command + or not Path(command[0]).is_absolute() + or any(not argument or "\x00" in argument for argument in command) + ): + raise StartupError("invalid process guardian arguments") + return liveness_fd, command + + +def _guarded_child_status(pid: int) -> int | None: + try: + result = os.waitid(os.P_PID, pid, os.WEXITED | os.WNOHANG | os.WNOWAIT) + except (ChildProcessError, OSError) as error: + raise StartupError("guarded process anchor is unavailable") from error + if result is None: + return None + if result.si_pid != pid: + raise StartupError("guarded process observation is inconsistent") + if result.si_code == os.CLD_EXITED: + return result.si_status + if result.si_code in (os.CLD_KILLED, os.CLD_DUMPED): + return -result.si_status + raise StartupError("guarded process has an unsupported wait status") + + +def _signal_guarded_group(process_group: int, requested_signal: int) -> None: try: - server = build_production_server() + os.killpg(process_group, requested_signal) + except ProcessLookupError: + return + except OSError as error: + if error.errno != errno.ESRCH: + raise StartupError("cannot signal guarded process group") from error + + +def _stop_guarded_process( + process: subprocess.Popen[bytes], + status: int | None, + *, + graceful: bool, +) -> int: + if graceful: + _signal_guarded_group(process.pid, signal.SIGTERM) + deadline = time.monotonic() + min(0.1, TERMINATE_GRACE_SECONDS / 2) + while status is None and time.monotonic() < deadline: + time.sleep(LEADER_POLL_SECONDS) + status = _guarded_child_status(process.pid) + _signal_guarded_group(process.pid, signal.SIGKILL) + deadline = time.monotonic() + max(1.0, TERMINATE_GRACE_SECONDS * 4) + while status is None: + if time.monotonic() >= deadline: + raise StartupError("guarded process did not exit after SIGKILL") + time.sleep(LEADER_POLL_SECONDS) + status = _guarded_child_status(process.pid) + try: + reaped = process.wait(timeout=max(1.0, TERMINATE_GRACE_SECONDS * 4)) + except (ChildProcessError, OSError, subprocess.TimeoutExpired) as error: + raise StartupError("guarded process could not be reaped") from error + if reaped != status: + raise StartupError("guarded process status changed during reap") + return status + + +def _run_process_guardian(liveness_fd: int, command: Sequence[str]) -> int: + if ( + os.getpid() != os.getpgrp() + or os.getpid() != os.getsid(0) + or not stat.S_ISFIFO(os.fstat(liveness_fd).st_mode) + ): + raise StartupError("process guardian isolation is invalid") + executable = Path(command[0]) + try: + executable_info = executable.lstat() + except OSError as error: + raise StartupError("guarded executable is unavailable") from error + if ( + not stat.S_ISREG(executable_info.st_mode) + or executable.is_symlink() + or not os.access(executable, os.X_OK) + ): + raise StartupError("guarded executable is unsafe") + + os.set_blocking(liveness_fd, False) + try: + initial = os.read(liveness_fd, 1) + except BlockingIOError: + initial = None + except OSError as error: + raise StartupError("process guardian liveness channel failed") from error + if initial is not None: + if initial: + raise StartupError("process guardian liveness protocol refused") + return 0 + + termination_requested = False + + def request_termination(unused_signal, unused_frame) -> None: + nonlocal termination_requested + termination_requested = True + + signal.signal(signal.SIGTERM, request_termination) + signal.signal(signal.SIGINT, request_termination) + try: + process = subprocess.Popen( + list(command), + stdin=subprocess.DEVNULL, + stdout=None, + stderr=None, + close_fds=True, + preexec_fn=os.setpgrp, + ) + except (OSError, ValueError, subprocess.SubprocessError) as error: + raise StartupError("guarded process failed to start") from error + + selector: selectors.BaseSelector | None = None + status: int | None = None + reaped = False + try: + selector = selectors.DefaultSelector() + selector.register(liveness_fd, selectors.EVENT_READ) + while True: + if termination_requested: + status = _stop_guarded_process(process, status, graceful=True) + reaped = True + return status + status = _guarded_child_status(process.pid) + if status is not None: + try: + quiescent = _exited_group_has_only_zombie_members(process.pid) + except BackendFailure: + quiescent = False + if quiescent: + reaped_status = process.wait() + reaped = True + if reaped_status != status: + raise StartupError( + "guarded process status changed during final reap" + ) + return status + status = _stop_guarded_process(process, status, graceful=True) + reaped = True + return status + if not selector.select(LEADER_POLL_SECONDS): + continue + try: + payload = os.read(liveness_fd, 1) + except BlockingIOError: + continue + if payload: + raise StartupError("process guardian liveness protocol refused") + status = _stop_guarded_process(process, status, graceful=False) + reaped = True + return 0 + finally: + if selector is not None: + selector.close() + with contextlib.suppress(OSError): + os.close(liveness_fd) + if not reaped: + with contextlib.suppress(Exception): + _stop_guarded_process(process, status, graceful=False) + + +def _read_namespace_metadata(path: Path | str, *, byte_limit: int) -> bytes: + if byte_limit < 1: + raise StartupError("invalid namespace metadata byte limit") + try: + fd = os.open(os.fspath(path), os.O_RDONLY | os.O_NONBLOCK | os.O_NOFOLLOW) + except OSError as error: + raise StartupError("namespace metadata is unavailable") from error + try: + if not stat.S_ISREG(os.fstat(fd).st_mode): + raise StartupError("namespace metadata is not a regular file") + chunks: list[bytes] = [] + count = 0 + while chunk := os.read(fd, min(4096, byte_limit - count + 1)): + count += len(chunk) + if count > byte_limit: + raise StartupError("namespace metadata exceeds byte limit") + chunks.append(chunk) + return b"".join(chunks) + finally: + os.close(fd) + + +def _mount_namespace_identity() -> str: + try: + identity = os.readlink("/proc/self/ns/mnt") + except OSError as error: + raise StartupError("mount namespace identity is unavailable") from error + if _MOUNT_NAMESPACE_IDENTITY.fullmatch(identity) is None: + raise StartupError("mount namespace identity has an invalid shape") + return identity + + +def _mapped_host_uid() -> int: + try: + text = _read_namespace_metadata( + "/proc/self/uid_map", byte_limit=4096 + ).decode("ascii") + except UnicodeDecodeError as error: + raise StartupError("user namespace mapping is not ASCII") from error + rows = [line.split() for line in text.splitlines() if line.strip()] + if ( + os.getuid() != 0 + or os.geteuid() != 0 + or len(rows) != 1 + or len(rows[0]) != 3 + or rows[0][0] != "0" + or rows[0][2] != "1" + or not rows[0][1].isdecimal() + ): + raise StartupError("private runtime requires an exact one-user mapping") + return int(rows[0][1]) + + +def _fixed_executable(candidates: Sequence[str]) -> str: + for candidate in candidates: + if os.path.isfile(candidate) and os.access(candidate, os.X_OK): + return candidate + raise StartupError("required namespace executable is unavailable") + + +def _mountinfo_confirms_tmpfs(path: Path) -> bool: + try: + text = _read_namespace_metadata( + "/proc/self/mountinfo", byte_limit=MAX_REQUEST_LINE_BYTES + ).decode("utf-8") + except UnicodeDecodeError as error: + raise StartupError("mount metadata is not UTF-8") from error + expected = os.fspath(path) + for line in text.splitlines(): + fields = line.split() + try: + separator = fields.index("-") + except ValueError: + continue + if ( + len(fields) > 5 + and separator + 1 < len(fields) + and fields[4] == expected + and fields[separator + 1] == "tmpfs" + ): + return True + return False + + +def _prepare_private_snapshot_parent(parent_namespace: str) -> Path: + if sys.platform != "linux" or _mount_namespace_identity() == parent_namespace: + raise StartupError("private mount namespace was not established") + host_uid = _mapped_host_uid() + temporary_root = Path("/tmp") + root_info = temporary_root.lstat() + if not stat.S_ISDIR(root_info.st_mode) or temporary_root.is_symlink(): + raise StartupError("system temporary root is unsafe") + mountpoint = temporary_root / f"{PRIVATE_SNAPSHOT_PARENT_PREFIX}{host_uid}" + try: + mountpoint.mkdir(mode=0o700, exist_ok=True) + before = mountpoint.lstat() + except OSError as error: + raise StartupError("private snapshot mountpoint is unavailable") from error + if ( + not stat.S_ISDIR(before.st_mode) + or mountpoint.is_symlink() + or before.st_uid != os.geteuid() + or before.st_mode & 0o077 + ): + raise StartupError("private snapshot mountpoint is unsafe") + try: + if any(os.scandir(mountpoint)): + raise StartupError("private snapshot mountpoint is not empty") + except OSError as error: + raise StartupError("private snapshot mountpoint is unreadable") from error + + mount = _fixed_executable(("/usr/bin/mount", "/bin/mount")) + try: + result = subprocess.run( + [ + mount, + "-t", + "tmpfs", + "-o", + "mode=0700,nosuid,nodev", + "tmpfs", + os.fspath(mountpoint), + ], + stdin=subprocess.DEVNULL, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + timeout=NAMESPACE_SETUP_TIMEOUT, + check=False, + env={"PATH": "/usr/bin:/bin:/usr/sbin:/sbin", "LC_ALL": "C"}, + ) + except (OSError, subprocess.SubprocessError) as error: + raise StartupError("private snapshot tmpfs mount failed") from error + if result.returncode != 0: + raise StartupError("private snapshot tmpfs mount refused") + mounted = mountpoint.lstat() + if ( + not stat.S_ISDIR(mounted.st_mode) + or mounted.st_uid != os.geteuid() + or mounted.st_mode & 0o077 + or mounted.st_dev == root_info.st_dev + or not _mountinfo_confirms_tmpfs(mountpoint) + ): + raise StartupError("private snapshot tmpfs verification refused") + return mountpoint + + +def _parse_namespace_child(arguments: Sequence[str]) -> str | None: + if not arguments: + return None + if ( + len(arguments) != 2 + or arguments[0] != PRIVATE_NAMESPACE_FLAG + or _MOUNT_NAMESPACE_IDENTITY.fullmatch(arguments[1]) is None + ): + raise StartupError("invalid private namespace arguments") + return arguments[1] + + +def _private_namespace_prefix(unshare: str) -> list[str]: + return [ + unshare, + "--user", + "--map-root-user", + "--mount", + "--pid", + "--fork", + "--kill-child=SIGKILL", + "--forward-signals", + # A PID namespace without a procfs of its own is a trap: /proc still + # shows the HOST namespace, so every /proc-based observation made inside + # it answers about the wrong processes. `/bin/ps -g ` then lists + # host PIDs (or fails "fatal library error, lookup self"), the group + # reaper concludes "backend process group survived SIGKILL", and EVERY + # tool call fails closed with -32002 while plugin identity still + # verifies. Measured, not inferred: without this flag `ps` inside the + # namespace printed this user's own systemd PIDs; with it, `1 R`. + "--mount-proc", + "--propagation", + "private", + ] + + +def _exec_in_private_snapshot_namespace() -> bool: + """Replace this process with a PID-namespace supervisor when available.""" + if sys.platform != "linux": + return False + try: + unshare = _fixed_executable(("/usr/bin/unshare", "/bin/unshare")) + true = _fixed_executable(("/usr/bin/true", "/bin/true")) + python = os.fspath(Path(sys.executable).resolve(strict=True)) + server_path = os.fspath(Path(__file__).resolve(strict=True)) + parent_namespace = _mount_namespace_identity() + except (OSError, StartupError): + return False + prefix = _private_namespace_prefix(unshare) + try: + probe = subprocess.run( + [*prefix, true], + stdin=subprocess.DEVNULL, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + timeout=NAMESPACE_SETUP_TIMEOUT, + check=False, + env={"PATH": "/usr/bin:/bin:/usr/sbin:/sbin", "LC_ALL": "C"}, + ) + except (OSError, subprocess.SubprocessError): + return False + if probe.returncode != 0: + return False + command = [ + *prefix, + python, + "-I", + "-S", + "-B", + server_path, + PRIVATE_NAMESPACE_FLAG, + parent_namespace, + ] + try: + os.execv(unshare, command) + except OSError: + return False + raise StartupError("private namespace exec unexpectedly returned") + + +def _run_production_server(snapshot_parent: Path | None) -> int: + try: + server = build_production_server(snapshot_parent=snapshot_parent) asyncio.run(_serve_stdio(server)) except (AdapterError, OSError, RuntimeError) as error: print(f"jackel_mcp=refused detail={_bounded_detail(error)}", file=sys.stderr) @@ -1866,5 +3452,24 @@ def main() -> int: return 0 +def main() -> int: + try: + child = _parse_namespace_child(sys.argv[1:]) + except (AdapterError, OSError, RuntimeError) as error: + print(f"jackel_mcp=refused detail={_bounded_detail(error)}", file=sys.stderr) + return 1 + if child is not None: + try: + snapshot_parent = _prepare_private_snapshot_parent(child) + except (AdapterError, OSError, RuntimeError): + # The exact PID/boot/start-time reaper remains the portable fallback + # if this kernel permits namespaces but refuses the private tmpfs. + snapshot_parent = None + return _run_production_server(snapshot_parent) + + _exec_in_private_snapshot_namespace() + return _run_production_server(None) + + if __name__ == "__main__": raise SystemExit(main()) diff --git a/plugins/jackel/mcp/stem.py b/plugins/jackel/mcp/stem.py new file mode 100644 index 0000000..6abb74b --- /dev/null +++ b/plugins/jackel/mcp/stem.py @@ -0,0 +1,1577 @@ +#!/usr/bin/env python3 -B +"""Additive AI-facing STEM workflows for JACKAL's single MCP surface. + +This module is identity-pinned wrapper orchestration, not a second calculator. +Every numeric value returned by a workflow is obtained from a delegated JACKAL +lane. Python selects and presents workflows, validates structure, and renders +views; it does not silently substitute local floating-point arithmetic when a +kernel lane refuses. + +The linked workspace is a visualization of delegated results. Its pixels, +SVG geometry, hover interpolation, and layout are never mathematical evidence. +""" + +from __future__ import annotations + +import copy +import decimal +import hashlib +import html +import json +import re +from typing import Callable + + +STEM_TOOL_NAMES = frozenset( + { + "jackal_aerospace", + "jackal_hypothesis", + "jackal_linked_workspace", + "jackal_matrix", + "jackal_probability", + "jackal_regression", + "jackal_sensor", + } +) + +CONSEQUENCE_CEILING = "informational" +MAX_TOKEN_BYTES = 512 +MAX_EXPRESSION_BYTES = 2048 +MAX_MATRIX_ROWS = 8 +MAX_MATRIX_COLUMNS = 8 +MAX_REGRESSION_POINTS = 128 +MAX_POLYNOMIAL_DEGREE = 5 +MAX_PROBABILITY_TRIALS = 512 +MAX_SENSOR_SAMPLES = 512 +MIN_WORKSPACE_SAMPLES = 17 +MAX_WORKSPACE_SAMPLES = 257 +MAX_RESOURCE_TEXT_BYTES = 2 * 1024 * 1024 + +RATIONAL_TOKEN = re.compile( + r"(?:" + r"-?(?:0|[1-9][0-9]*)(?:/[1-9][0-9]*)?" + r"|-?(?:0|[1-9][0-9]*)\.[0-9]+" + r"|-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?[eE][+-]?[0-9]+" + r")\Z", + re.ASCII, +) +CANONICAL_INTEGER = re.compile(r"(?:0|[1-9][0-9]*)\Z", re.ASCII) +SAFE_LABEL = re.compile(r"[A-Za-z0-9_.:/+-]{1,128}\Z", re.ASCII) +X_TOKEN = re.compile(r"(? str: + if _IDENTITY is None: + raise RuntimeError("STEM identity is unavailable outside integrated dispatch") + return _IDENTITY + + +def _refusal(reason: str, detail: str) -> dict: + return { + "status": "refused", + "reason": reason, + "detail": detail, + "consequence_ceiling": CONSEQUENCE_CEILING, + "identities": {"jackal_stem_sha256": _identity()}, + "non_claims": [ + "A refusal is an answer; no weaker lane or local arithmetic was substituted", + "No mathematical, statistical, sensor, aerospace, or visual conclusion was established", + ], + } + + +def _kernel_call(tool: str, arguments: dict, *, allow_refusal: bool = False) -> dict: + if _KERNEL is None: + raise Refusal("kernel-unavailable", "STEM module is not attached to JACKAL") + result = _KERNEL.call(tool, arguments) + if not isinstance(result, dict): + raise Refusal("kernel-error", "JACKAL returned a non-object") + trace = { + "tool": tool, + "arguments": copy.deepcopy(arguments), + "status": result.get("status", "unknown"), + } + fields = result.get("fields") + if isinstance(fields, dict) and isinstance(fields.get("parsed"), str): + trace["parsed"] = fields["parsed"] + if isinstance(result.get("engine_output"), str): + trace["engine_output"] = result["engine_output"] + _TRACE.append(trace) + if result.get("status") == "refused" and not allow_refusal: + raise Refusal( + f"kernel-refused:{result.get('reason', 'unknown')}", + str(result.get("detail", "the delegated JACKAL lane refused")), + ) + return result + + +def _token(value: object, subject: str) -> str: + if ( + not isinstance(value, str) + or not value + or len(value.encode("utf-8")) > MAX_TOKEN_BYTES + or RATIONAL_TOKEN.fullmatch(value) is None + ): + raise Refusal( + "args", + f"{subject} must be a bounded integer, decimal, scientific literal, or rational", + ) + return value + + +def _integer(value: object, subject: str, *, maximum: int) -> tuple[str, int]: + if ( + not isinstance(value, str) + or CANONICAL_INTEGER.fullmatch(value) is None + or len(value) > 6 + ): + raise Refusal("args", f"{subject} must be a canonical nonnegative integer string") + parsed = int(value) + if parsed > maximum: + raise Refusal("budget", f"{subject} exceeds the admitted resource budget") + return value, parsed + + +def _label(value: object, subject: str) -> str: + if not isinstance(value, str) or SAFE_LABEL.fullmatch(value) is None: + raise Refusal("args", f"{subject} must be a bounded ASCII identifier") + return value + + +def _exact(expression: str) -> str: + result = _kernel_call("jackal_exact", {"expression": expression}) + fields = result.get("fields") + exact = fields.get("exact") if isinstance(fields, dict) else None + if ( + result.get("status") != "exact" + or result.get("formal") is not False + or not isinstance(exact, str) + ): + raise Refusal("kernel-error", "jackal_exact returned no canonical exact value") + return exact + + +def _evaluate(expression: str) -> tuple[str, dict]: + result = _kernel_call("jackal_evaluate", {"expression": expression}) + rendered = result.get("engine_output") + if ( + result.get("status") != "estimated" + or result.get("formal") is not False + or not isinstance(rendered, str) + ): + raise Refusal("kernel-error", "jackal_evaluate returned no estimated value") + return rendered, result + + +def _add(left: str, right: str) -> str: + return _exact(f"({left})+({right})") + + +def _sub(left: str, right: str) -> str: + return _exact(f"({left})-({right})") + + +def _mul(left: str, right: str) -> str: + return _exact(f"({left})*({right})") + + +def _div(left: str, right: str) -> str: + return _exact(f"({left})/({right})") + + +def _neg(value: str) -> str: + return _exact(f"-({value})") + + +def _sum(values: list[str]) -> str: + if not values: + return _exact("0") + return _exact("+".join(f"({value})" for value in values)) + + +def _count_exact(count: int) -> str: + if count <= 0: + return _exact("0") + return _exact("+".join("1" for _ in range(count))) + + +def _sign(value: str) -> int: + canonical = _exact(value) + if canonical == "0": + return 0 + if canonical.startswith("-"): + return -1 + return 1 + + +def _compare(left: str, right: str) -> int: + return _sign(f"({left})-({right})") + + +def _require_positive(value: str, subject: str) -> None: + if _compare(value, "0") <= 0: + raise Refusal("domain", f"{subject} must be strictly positive") + + +def _matrix(value: object, subject: str) -> list[list[str]]: + if not isinstance(value, list) or not value or len(value) > MAX_MATRIX_ROWS: + raise Refusal("matrix-shape", f"{subject} must be a nonempty bounded row array") + width: int | None = None + result: list[list[str]] = [] + for row_index, row in enumerate(value): + if not isinstance(row, list) or not row or len(row) > MAX_MATRIX_COLUMNS: + raise Refusal("matrix-shape", f"{subject}[{row_index}] is not a bounded row") + if width is None: + width = len(row) + if len(row) != width: + raise Refusal("matrix-shape", f"{subject} rows must have equal length") + result.append( + [_exact(_token(cell, f"{subject}[{row_index}][{column_index}]")) + for column_index, cell in enumerate(row)] + ) + return result + + +def _matrix_clone(matrix: list[list[str]]) -> list[list[str]]: + return [list(row) for row in matrix] + + +def _matrix_rref_values(matrix: list[list[str]]) -> tuple[list[list[str]], int]: + values = _matrix_clone(matrix) + rows = len(values) + columns = len(values[0]) + pivot_row = 0 + for column in range(columns): + if pivot_row >= rows: + break + selected: int | None = None + for candidate in range(pivot_row, rows): + if _sign(values[candidate][column]) != 0: + selected = candidate + break + if selected is None: + continue + if selected != pivot_row: + values[pivot_row], values[selected] = values[selected], values[pivot_row] + pivot = values[pivot_row][column] + values[pivot_row] = [_div(cell, pivot) for cell in values[pivot_row]] + for row in range(rows): + if row == pivot_row or _sign(values[row][column]) == 0: + continue + factor = values[row][column] + values[row] = [ + _exact(f"({values[row][item]})-({factor})*({values[pivot_row][item]})") + for item in range(columns) + ] + pivot_row += 1 + return values, pivot_row + + +def _matrix_determinant(matrix: list[list[str]]) -> str: + size = len(matrix) + if len(matrix[0]) != size: + raise Refusal("matrix-shape", "determinant requires a square matrix") + values = _matrix_clone(matrix) + determinant = _exact("1") + odd_swaps = False + for column in range(size): + selected: int | None = None + for candidate in range(column, size): + if _sign(values[candidate][column]) != 0: + selected = candidate + break + if selected is None: + return _exact("0") + if selected != column: + values[column], values[selected] = values[selected], values[column] + odd_swaps = not odd_swaps + pivot = values[column][column] + determinant = _mul(determinant, pivot) + for row in range(column + 1, size): + if _sign(values[row][column]) == 0: + continue + factor = _div(values[row][column], pivot) + for item in range(column, size): + values[row][item] = _exact( + f"({values[row][item]})-({factor})*({values[column][item]})" + ) + if odd_swaps: + determinant = _neg(determinant) + return determinant + + +def _matrix_inverse(matrix: list[list[str]]) -> list[list[str]]: + size = len(matrix) + if len(matrix[0]) != size: + raise Refusal("matrix-shape", "inverse requires a square matrix") + augmented: list[list[str]] = [] + for row in range(size): + identity = ["1" if row == column else "0" for column in range(size)] + augmented.append(list(matrix[row]) + identity) + reduced, rank = _matrix_rref_values(augmented) + if rank != size: + raise Refusal("matrix-singular", "matrix has no exact inverse") + for row in range(size): + for column in range(size): + expected = "1" if row == column else "0" + if _compare(reduced[row][column], expected) != 0: + raise Refusal("matrix-singular", "matrix has no exact inverse") + return [row[size:] for row in reduced] + + +def _matrix_solve(matrix: list[list[str]], vector: object) -> list[str]: + size = len(matrix) + if len(matrix[0]) != size: + raise Refusal("matrix-shape", "solve requires a square coefficient matrix") + if not isinstance(vector, list) or len(vector) != size: + raise Refusal("matrix-shape", "vector length must equal the matrix row count") + rhs = [ + _exact(_token(item, f"vector[{index}]")) + for index, item in enumerate(vector) + ] + augmented = [list(matrix[row]) + [rhs[row]] for row in range(size)] + reduced, rank = _matrix_rref_values(augmented) + if rank != size: + raise Refusal("matrix-nonunique", "system does not have one exact solution") + for row in range(size): + for column in range(size): + expected = "1" if row == column else "0" + if _compare(reduced[row][column], expected) != 0: + raise Refusal("matrix-nonunique", "system does not have one exact solution") + return [row[-1] for row in reduced] + + +def _matrix_tool(arguments: dict) -> dict: + operation = arguments.get("operation") + if operation not in {"add", "determinant", "inverse", "multiply", "rref", "solve", "transpose"}: + raise Refusal("operation-unknown", "matrix operation is outside the closed route table") + matrix = _matrix(arguments.get("matrix"), "matrix") + fields: dict[str, object] = {} + field_status: dict[str, str] = {} + if operation == "transpose": + fields["matrix"] = [list(column) for column in zip(*matrix)] + field_status["matrix"] = "exact" + elif operation == "determinant": + fields["determinant"] = _matrix_determinant(matrix) + field_status["determinant"] = "exact" + elif operation == "rref": + reduced, rank = _matrix_rref_values(matrix) + fields["matrix"] = reduced + fields["rank"] = _count_exact(rank) + field_status.update({"matrix": "exact", "rank": "exact"}) + elif operation == "inverse": + fields["matrix"] = _matrix_inverse(matrix) + field_status["matrix"] = "exact" + elif operation == "solve": + fields["solution"] = _matrix_solve(matrix, arguments.get("vector")) + field_status["solution"] = "exact" + else: + second = _matrix(arguments.get("second_matrix"), "second_matrix") + if operation == "add": + if len(second) != len(matrix) or len(second[0]) != len(matrix[0]): + raise Refusal("matrix-shape", "matrix addition requires identical shapes") + fields["matrix"] = [ + [_add(matrix[row][column], second[row][column]) + for column in range(len(matrix[0]))] + for row in range(len(matrix)) + ] + else: + if len(matrix[0]) != len(second): + raise Refusal("matrix-shape", "matrix multiplication inner dimensions differ") + product: list[list[str]] = [] + for row in range(len(matrix)): + out_row: list[str] = [] + for column in range(len(second[0])): + terms = [ + f"({matrix[row][item]})*({second[item][column]})" + for item in range(len(second)) + ] + out_row.append(_exact("+".join(terms))) + product.append(out_row) + fields["matrix"] = product + field_status["matrix"] = "exact" + return { + "status": "exact", + "lane": "matrix-exact-delegated-v1", + "formal": False, + "consequence_ceiling": CONSEQUENCE_CEILING, + "parsed": { + "operation": operation, + "matrix": matrix, + "second_matrix": arguments.get("second_matrix"), + "vector": arguments.get("vector"), + }, + "fields": fields, + "field_status": field_status, + "delegated_to": list(_TRACE), + "identities": {"jackal_stem_sha256": _identity()}, + "non_claims": [ + "Every reported numeric matrix field was produced by delegated status=exact JACKAL rational calls", + "NOT formal-bounded: the row-operation orchestration is identity-pinned and tested, not Lean-proved", + "The delegation trace is reproducibility metadata, not an independent matrix certificate", + "No conditioning, measurement provenance, or physical interpretation is inferred", + ], + } + + +def _regression_tool(arguments: dict) -> dict: + model = arguments.get("model") + if model != "polynomial_ols": + raise Refusal("operation-unknown", "regression currently admits polynomial_ols") + raw_x = arguments.get("x") + raw_y = arguments.get("y") + if ( + not isinstance(raw_x, list) + or not isinstance(raw_y, list) + or len(raw_x) != len(raw_y) + or len(raw_x) < 2 + or len(raw_x) > MAX_REGRESSION_POINTS + ): + raise Refusal("sample-shape", "x and y must be equal bounded arrays with at least two points") + x = [_token(value, f"x[{index}]") for index, value in enumerate(raw_x)] + y = [_token(value, f"y[{index}]") for index, value in enumerate(raw_y)] + degree_text, degree = _integer( + arguments.get("degree"), "degree", maximum=MAX_POLYNOMIAL_DEGREE + ) + if degree < 1 or degree >= len(x): + raise Refusal("model-rank", "degree must be positive and below the sample count") + width = degree + 1 + normal: list[list[str]] = [] + rhs: list[str] = [] + for row in range(width): + normal_row: list[str] = [] + for column in range(width): + exponent = row + column + normal_row.append( + _sum([f"({value})^{exponent}" for value in x]) + if exponent > 0 else _count_exact(len(x)) + ) + normal.append(normal_row) + rhs.append( + _sum( + [ + f"({y[index]})*({x[index]})^{row}" + if row > 0 else y[index] + for index in range(len(x)) + ] + ) + ) + coefficients = _matrix_solve(normal, rhs) + fitted: list[str] = [] + for value in x: + terms = [ + coefficients[power] + if power == 0 else f"({coefficients[power]})*({value})^{power}" + for power in range(width) + ] + fitted.append(_exact("+".join(f"({term})" for term in terms))) + residual_squares = [ + f"(({y[index]})-({fitted[index]}))^2" for index in range(len(y)) + ] + sse = _sum(residual_squares) + mean_y = _div(_sum(y), _count_exact(len(y))) + sst = _sum([f"(({value})-({mean_y}))^2" for value in y]) + r_squared: str | None = None + if _sign(sst) != 0: + r_squared = _exact(f"1-({sse})/({sst})") + expression = "+".join( + coefficients[power] + if power == 0 + else f"({coefficients[power]})*x^{power}" + for power in range(width) + ) + fields: dict[str, object] = { + "coefficients_ascending": coefficients, + "expression": expression, + "fitted": fitted, + "sse": sse, + "sst": sst, + "r_squared": r_squared, + "normal_matrix": normal, + "normal_rhs": rhs, + } + return { + "status": "model-based", + "lane": "regression-polynomial-ols-exact-fields-v1", + "formal": False, + "consequence_ceiling": CONSEQUENCE_CEILING, + "parsed": {"model": model, "degree": degree_text, "x": x, "y": y}, + "fields": fields, + "field_status": { + "coefficients_ascending": "exact", + "fitted": "exact", + "sse": "exact", + "sst": "exact", + "r_squared": "undefined" if r_squared is None else "exact", + }, + "assumptions": [ + "ordinary least squares under the caller-selected polynomial basis", + "the supplied x and y tokens are treated as exact rational data", + ], + "delegated_to": list(_TRACE), + "identities": {"jackal_stem_sha256": _identity()}, + "non_claims": [ + "Exact coefficients do not establish that a polynomial model is appropriate", + "No distribution, independence, homoscedasticity, confidence interval, prediction interval, or causal interpretation is inferred", + "Supplied points are not promoted to measured or representative data", + "NOT formal-bounded: exact rational fields are outside the Lean certificate chain", + ], + } + + +def _binomial_pmf(n_text: str, n: int, k_text: str, k: int, p: str) -> str: + if k > n: + raise Refusal("domain", "k must not exceed n") + complement = _exact(f"({n_text})-({k_text})") + coefficient = "1" + for step in range(1, min(k, n - k) + 1): + coefficient = _exact( + f"({coefficient})*(({n_text})-({step})+1)/({step})" + ) + return _exact( + f"({coefficient})*({p})^({k_text})*(1-({p}))^({complement})" + ) + + +def _binomial_probability_range( + n_text: str, n: int, start: int, stop: int, p: str +) -> list[str]: + """Produce consecutive exact PMFs with one recurrence call per new term.""" + if start < 0 or stop < start or stop > n: + raise Refusal("domain", "binomial probability range is invalid") + if p == "0": + return [_exact("1" if index == 0 else "0") for index in range(start, stop + 1)] + if p == "1": + return [_exact("1" if index == n else "0") for index in range(start, stop + 1)] + probabilities = [_binomial_pmf(n_text, n, str(start), start, p)] + current = probabilities[0] + for index in range(start, stop): + current = _exact( + f"({current})*(({n_text})-({index}))/(({index})+1)*({p})/(1-({p}))" + ) + probabilities.append(current) + return probabilities + + +def _probability_tool(arguments: dict) -> dict: + operation = arguments.get("operation") + if operation not in {"binomial_cdf", "binomial_pmf", "normal_cdf"}: + raise Refusal("operation-unknown", "probability operation is outside the closed route table") + assumptions: list[str] + fields: dict[str, object] + field_status: dict[str, str] + if operation.startswith("binomial"): + n_text, n = _integer(arguments.get("n"), "n", maximum=MAX_PROBABILITY_TRIALS) + k_text, k = _integer(arguments.get("k"), "k", maximum=MAX_PROBABILITY_TRIALS) + p = _exact(_token(arguments.get("p"), "p")) + if k > n or _compare(p, "0") < 0 or _compare(p, "1") > 0: + raise Refusal("domain", "binomial requires 0 <= k <= n and 0 <= p <= 1") + if operation == "binomial_pmf": + probability = _binomial_pmf(n_text, n, k_text, k, p) + else: + probability = _sum(_binomial_probability_range(n_text, n, 0, k, p)) + fields = {"probability": probability} + field_status = {"probability": "exact"} + assumptions = [ + "fixed trial count", + "independent Bernoulli trials", + "constant caller-supplied success probability", + ] + else: + z = _token(arguments.get("z"), "z") + cutoff = _token(arguments.get("tail_cutoff"), "tail_cutoff") + tolerance = _token(arguments.get("tolerance"), "tolerance") + _require_positive(cutoff, "tail_cutoff") + _require_positive(tolerance, "tolerance") + if _compare(z, _neg(cutoff)) < 0 or _compare(z, cutoff) > 0: + raise Refusal("domain", "z must lie inside the caller-declared finite tail cutoff") + result = _kernel_call( + "jackal_integrate_adaptive", + { + "expression": "exp(-x^2/2)/sqrt(2*pi)", + "input_lo": _neg(cutoff), + "input_hi": z, + "tolerance": tolerance, + }, + ) + result_fields = result.get("fields") + probability = result_fields.get("integral") if isinstance(result_fields, dict) else None + if ( + result.get("status") != "estimated" + or result.get("formal") is not False + or not isinstance(probability, str) + ): + raise Refusal("kernel-error", "normal CDF integration returned no integral field") + fields = { + "finite_cutoff_cdf_estimate": probability, + "integration_result": result, + "omitted_left_tail_below": _neg(cutoff), + } + field_status = {"finite_cutoff_cdf_estimate": "estimated"} + assumptions = ["standard normal model", "caller-selected finite tail cutoff"] + return { + "status": "model-based", + "lane": f"probability-{operation}-v1", + "formal": False, + "consequence_ceiling": CONSEQUENCE_CEILING, + "parsed": copy.deepcopy(arguments), + "fields": fields, + "field_status": field_status, + "assumptions": assumptions, + "delegated_to": list(_TRACE), + "identities": {"jackal_stem_sha256": _identity()}, + "non_claims": [ + "A probability computed under a declared distribution does not establish that the data-generating process follows that distribution", + "No input provenance, independence, calibration, or sampling design is verified", + "Normal CDF output is an estimate over a finite caller-selected interval, not a bound on the full infinite-tail probability", + ], + } + + +def _hypothesis_tool(arguments: dict) -> dict: + operation = arguments.get("operation") + alternative = arguments.get("alternative") + if alternative not in {"less", "greater", "two_sided"}: + raise Refusal("args", "alternative must be less, greater, or two_sided") + if operation == "one_sample_z": + mean = _token(arguments.get("sample_mean"), "sample_mean") + null = _token(arguments.get("null_mean"), "null_mean") + sigma = _token(arguments.get("population_sd"), "population_sd") + n_text, _unused_n = _integer( + arguments.get("n"), "n", maximum=MAX_PROBABILITY_TRIALS + ) + cutoff = _token(arguments.get("tail_cutoff"), "tail_cutoff") + tolerance = _token(arguments.get("tolerance"), "tolerance") + _require_positive(sigma, "population_sd") + _require_positive(n_text, "n") + _require_positive(cutoff, "tail_cutoff") + z_expression = f"(({mean})-({null}))/(({sigma})/sqrt({n_text}))" + z, z_result = _evaluate(z_expression) + absolute_z, absolute_result = _evaluate(f"abs({z_expression})") + lower = _neg(cutoff) + if _compare(z, lower) < 0 or _compare(z, cutoff) > 0: + raise Refusal( + "domain", + "the estimated z statistic lies outside the caller-declared finite tail cutoff", + ) + if alternative == "less": + integration_lo, integration_hi = lower, z + multiplier = "1" + elif alternative == "greater": + integration_lo, integration_hi = z, cutoff + multiplier = "1" + else: + integration_lo, integration_hi = absolute_z, cutoff + multiplier = "2" + tail = _kernel_call( + "jackal_integrate_adaptive", + { + "expression": "exp(-x^2/2)/sqrt(2*pi)", + "input_lo": integration_lo, + "input_hi": integration_hi, + "tolerance": tolerance, + }, + ) + tail_fields = tail.get("fields") + tail_value = tail_fields.get("integral") if isinstance(tail_fields, dict) else None + if ( + tail.get("status") != "estimated" + or tail.get("formal") is not False + or not isinstance(tail_value, str) + ): + raise Refusal("kernel-error", "z-test integration returned no integral field") + p_value, p_result = _evaluate(f"({multiplier})*({tail_value})") + fields = { + "z": z, + "p_value_estimate": p_value, + "z_result": z_result, + "absolute_z_result": absolute_result, + "tail_integration_result": tail, + "p_value_render_result": p_result, + } + field_status = {"z": "estimated", "p_value_estimate": "estimated"} + assumptions = [ + "known caller-supplied population standard deviation", + "independent representative observations", + "normal sampling distribution for the standardized mean", + "caller-selected finite normal-tail cutoff", + ] + elif operation == "exact_binomial_tail": + n_text, n = _integer(arguments.get("n"), "n", maximum=MAX_PROBABILITY_TRIALS) + k_text, k = _integer(arguments.get("k"), "k", maximum=MAX_PROBABILITY_TRIALS) + p0 = _exact(_token(arguments.get("p0"), "p0")) + if alternative == "two_sided": + raise Refusal( + "test-definition-ambiguous", + "two-sided exact binomial tests have multiple conventions; choose less or greater", + ) + if k > n or _compare(p0, "0") < 0 or _compare(p0, "1") > 0: + raise Refusal("domain", "exact binomial tail requires 0 <= k <= n and 0 <= p0 <= 1") + start, stop = (0, k) if alternative == "less" else (k, n) + p_value = _sum(_binomial_probability_range(n_text, n, start, stop, p0)) + fields = {"p_value": p_value} + field_status = {"p_value": "exact"} + assumptions = [ + "fixed trial count", + "independent Bernoulli trials", + "constant null success probability", + "one-sided exact tail convention", + ] + else: + raise Refusal("operation-unknown", "hypothesis operation is outside the closed route table") + return { + "status": "model-based", + "lane": f"hypothesis-{operation}-v1", + "formal": False, + "consequence_ceiling": "advisory", + "parsed": copy.deepcopy(arguments), + "fields": fields, + "field_status": field_status, + "assumptions": assumptions, + "delegated_to": list(_TRACE), + "identities": {"jackal_stem_sha256": _identity()}, + "non_claims": [ + "A p-value is conditional on the declared test model and is not the probability that the null hypothesis is true", + "A z-test p-value is an estimate over a finite caller-selected tail interval, not a bound on the full infinite-tail probability", + "No sampling design, independence, distributional fit, multiple-testing correction, effect importance, or decision threshold is verified", + "This result is not a scientific, medical, engineering, or safety decision", + ], + } + + +def _sorted_exact(values: list[str]) -> list[str]: + result: list[str] = [] + for value in values: + position = len(result) + while position > 0 and _compare(value, result[position - 1]) < 0: + position -= 1 + result.insert(position, value) + return result + + +def _sensor_tool(arguments: dict) -> dict: + operation = arguments.get("operation") + if operation not in {"ingest_batch", "linear_calibration"}: + raise Refusal("operation-unknown", "sensor operation is outside the closed route table") + sensor_id = _label(arguments.get("sensor_id"), "sensor_id") + channel = _label(arguments.get("channel"), "channel") + quantity = _label(arguments.get("quantity"), "quantity") + unit = _label(arguments.get("unit"), "unit") + source = arguments.get("source") + observed_at = arguments.get("observed_at") + if not isinstance(source, str) or not source.strip() or len(source.encode("utf-8")) > 1024: + raise Refusal("undeclared-datum", "sensor source must be declared") + if not isinstance(observed_at, str) or not observed_at.strip() or len(observed_at) > 128: + raise Refusal("undeclared-datum", "sensor observation time must be declared") + raw_samples = arguments.get("samples") + if ( + not isinstance(raw_samples, list) + or not raw_samples + or len(raw_samples) > MAX_SENSOR_SAMPLES + ): + raise Refusal("sample-shape", "samples must be a nonempty bounded array") + samples = [_token(value, f"samples[{index}]") for index, value in enumerate(raw_samples)] + given: dict[str, object] = { + "sensor_id": sensor_id, + "channel": channel, + "quantity": quantity, + "unit": unit, + "source": source, + "observed_at": observed_at, + "input_provenance": "supplied", + } + if operation == "linear_calibration": + scale = _token(arguments.get("scale"), "scale") + offset = _token(arguments.get("offset"), "offset") + calibration_source = arguments.get("calibration_source") + calibration_as_of = arguments.get("calibration_as_of") + if ( + not isinstance(calibration_source, str) + or not calibration_source.strip() + or not isinstance(calibration_as_of, str) + or not calibration_as_of.strip() + ): + raise Refusal( + "undeclared-datum", + "linear calibration requires calibration_source and calibration_as_of", + ) + samples = [_exact(f"({scale})*({value})+({offset})") for value in samples] + given["calibration"] = { + "model": "y=scale*x+offset", + "scale": scale, + "offset": offset, + "source": calibration_source, + "as_of": calibration_as_of, + "verified": False, + } + ordered = _sorted_exact(samples) + count = _count_exact(len(samples)) + total = _sum(samples) + mean = _div(total, count) + variance = _div(_sum([f"(({value})-({mean}))^2" for value in samples]), count) + middle = len(ordered) // 2 + median = ( + ordered[middle] + if len(ordered) % 2 == 1 + else _div(_add(ordered[middle - 1], ordered[middle]), "2") + ) + stddev = _sqrt_formal(variance) + return { + "status": "exact-given", + "lane": "sensor-supplied-batch-v1", + "formal": False, + "consequence_ceiling": CONSEQUENCE_CEILING, + "parsed": { + "operation": operation, + "sensor_id": sensor_id, + "channel": channel, + "sample_count": count, + }, + "given": given, + "fields": { + "samples": samples, + "count": count, + "sum": total, + "mean": mean, + "median": median, + "minimum": ordered[0], + "maximum": ordered[-1], + "population_variance": variance, + "population_stddev_enclosure": stddev, + }, + "field_status": { + "samples": "exact-given", + "count": "exact", + "sum": "exact-given", + "mean": "exact-given", + "median": "exact-given", + "minimum": "exact-given", + "maximum": "exact-given", + "population_variance": "exact-given", + "population_stddev_enclosure": "formal-bounded", + }, + "delegated_to": list(_TRACE), + "identities": {"jackal_stem_sha256": _identity()}, + "non_claims": [ + "The samples, source, timestamps, sensor identity, unit, and calibration metadata are caller-supplied and were not authenticated", + "This tool does not claim it opened or read physical hardware; browser or device acquisition must remain separately observable", + "Descriptive summaries do not establish accuracy, calibration, uncertainty, representativeness, independence, or a probability distribution", + "The standard-deviation field is a formal-bounded enclosure of arithmetic over supplied values, not a certified sensor measurement", + ], + } + + +def _sqrt_formal(radicand: str) -> dict: + if _compare(radicand, "0") < 0: + raise Refusal("domain", "aerospace square-root radicand is negative") + result = _kernel_call( + "jackal_sqrt_rat_bound", + {"expression": "sqrt(x)", "input_lo": radicand, "input_hi": radicand}, + ) + if result.get("status") != "formal-bounded" or result.get("checker_rerun") != "ACCEPT": + raise Refusal( + "kernel-error", + "jackal_sqrt_rat_bound did not return a checker-accepted formal-bounded result", + ) + return result + + +def _ln_formal(value: str) -> dict: + _require_positive(value, "logarithm argument") + result = _kernel_call( + "jackal_ln_rat_bound", + {"expression": "ln(x)", "input_lo": value, "input_hi": value}, + ) + if result.get("status") != "formal-bounded" or result.get("checker_rerun") != "ACCEPT": + raise Refusal( + "kernel-error", + "jackal_ln_rat_bound did not return a checker-accepted formal-bounded result", + ) + return result + + +def _aerospace_tool(arguments: dict) -> dict: + operation = arguments.get("operation") + parameters = arguments.get("parameters") + if not isinstance(parameters, dict): + raise Refusal("args", "parameters must be an object") + + def need(name: str) -> str: + value = _token(parameters.get(name), name) + _require_positive(value, name) + return value + + fields: dict[str, object] = {} + field_status: dict[str, str] = {} + assumptions: list[str] = [] + if operation == "circular_orbit": + mu = need("mu") + radius = need("radius") + speed_radicand = _exact(f"({mu})/({radius})") + fields["speed_enclosure"] = _sqrt_formal(speed_radicand) + period, period_result = _evaluate(f"2*pi*sqrt(({radius})^3/({mu}))") + fields.update({"period_estimate": period, "period_result": period_result}) + field_status.update({"speed_enclosure": "formal-bounded", "period_estimate": "estimated"}) + assumptions = ["ideal circular two-body orbit", "point masses", "constant supplied gravitational parameter"] + elif operation == "vis_viva": + mu = need("mu") + radius = need("radius") + semi_major_axis = need("semi_major_axis") + radicand = _exact(f"({mu})*(2/({radius})-1/({semi_major_axis}))") + fields["speed_enclosure"] = _sqrt_formal(radicand) + field_status["speed_enclosure"] = "formal-bounded" + assumptions = ["ideal Keplerian two-body orbit", "osculating semi-major axis supplied by caller"] + elif operation == "rocket_equation": + exhaust_velocity = need("exhaust_velocity") + initial_mass = need("initial_mass") + final_mass = need("final_mass") + if _compare(initial_mass, final_mass) <= 0: + raise Refusal("domain", "initial_mass must exceed final_mass") + ratio = _exact(f"({initial_mass})/({final_mass})") + fields["mass_ratio"] = ratio + fields["ln_mass_ratio_enclosure"] = _ln_formal(ratio) + delta_v, delta_v_result = _evaluate(f"({exhaust_velocity})*ln({ratio})") + fields.update({"delta_v_estimate": delta_v, "delta_v_result": delta_v_result}) + field_status.update( + {"mass_ratio": "exact", "ln_mass_ratio_enclosure": "formal-bounded", "delta_v_estimate": "estimated"} + ) + assumptions = ["ideal Tsiolkovsky rocket equation", "constant effective exhaust velocity", "no gravity or drag losses"] + elif operation == "hohmann_transfer": + mu = need("mu") + r1 = need("r1") + r2 = need("r2") + if _compare(r1, r2) == 0: + raise Refusal("domain", "Hohmann transfer radii must differ") + a_transfer = _exact(f"(({r1})+({r2}))/2") + v1 = _sqrt_formal(_exact(f"({mu})/({r1})")) + v2 = _sqrt_formal(_exact(f"({mu})/({r2})")) + vt1 = _sqrt_formal(_exact(f"({mu})*(2/({r1})-1/({a_transfer}))")) + vt2 = _sqrt_formal(_exact(f"({mu})*(2/({r2})-1/({a_transfer}))")) + delta_v, delta_v_result = _evaluate( + f"abs(sqrt(({mu})*(2/({r1})-1/({a_transfer})))-sqrt(({mu})/({r1})))" + f"+abs(sqrt(({mu})/({r2}))-sqrt(({mu})*(2/({r2})-1/({a_transfer}))))" + ) + transfer_time, time_result = _evaluate(f"pi*sqrt(({a_transfer})^3/({mu}))") + fields.update( + { + "transfer_semi_major_axis": a_transfer, + "initial_circular_speed_enclosure": v1, + "final_circular_speed_enclosure": v2, + "transfer_speed_at_r1_enclosure": vt1, + "transfer_speed_at_r2_enclosure": vt2, + "total_delta_v_estimate": delta_v, + "transfer_time_estimate": transfer_time, + "delta_v_result": delta_v_result, + "time_result": time_result, + } + ) + field_status.update( + { + "transfer_semi_major_axis": "exact", + "initial_circular_speed_enclosure": "formal-bounded", + "final_circular_speed_enclosure": "formal-bounded", + "transfer_speed_at_r1_enclosure": "formal-bounded", + "transfer_speed_at_r2_enclosure": "formal-bounded", + "total_delta_v_estimate": "estimated", + "transfer_time_estimate": "estimated", + } + ) + assumptions = ["coplanar circular two-body endpoint orbits", "impulsive burns", "no perturbations or finite-burn losses"] + elif operation == "plane_change": + velocity = need("velocity") + angle_degrees = _token(parameters.get("angle_degrees"), "angle_degrees") + if _compare(angle_degrees, "0") < 0 or _compare(angle_degrees, "180") > 0: + raise Refusal("domain", "angle_degrees must lie in the closed interval [0,180]") + delta_v, result = _evaluate(f"2*({velocity})*sin(({angle_degrees})*pi/360)") + fields.update({"delta_v_estimate": delta_v, "evaluation_result": result}) + field_status["delta_v_estimate"] = "estimated" + assumptions = ["instantaneous pure plane change", "constant speed across the maneuver", "smallest plane-change angle supplied in degrees"] + else: + raise Refusal("operation-unknown", "aerospace operation is outside the closed model table") + return { + "status": "model-based", + "lane": f"aerospace-{operation}-v1", + "formal": False, + "consequence_ceiling": "advisory", + "parsed": {"operation": operation, "parameters": copy.deepcopy(parameters)}, + "fields": fields, + "field_status": field_status, + "assumptions": assumptions, + "delegated_to": list(_TRACE), + "identities": {"jackal_stem_sha256": _identity()}, + "non_claims": [ + "Formal-bounded scalar subfields certify only admitted arithmetic fragments, not the physical model or mission inputs", + "No perturbations, uncertainty, navigation error, actuator limits, finite-burn effects, atmosphere, ephemeris, or mission safety are inferred unless explicitly named in the selected model", + "This workflow is not the published JACKAL spacecraft finite-burn certificate and cannot inherit that certificate's verdict", + "No aerospace decision may exceed the advisory consequence ceiling of this wrapper result", + ], + } + + +def _json_for_script(value: object) -> str: + return ( + json.dumps(value, ensure_ascii=False, allow_nan=False, sort_keys=True, separators=(",", ":")) + .replace("<", "\\u003c") + .replace("\u2028", "\\u2028") + .replace("\u2029", "\\u2029") + ) + + +def _workspace_document(payload: dict, *, shell: bool = False) -> str: + data = _json_for_script(payload) + shell_note = ( + "This static resource is the linked-workspace shell. Call jackal_linked_workspace " + "to populate it with delegated evidence." + if shell + else "Hover the curve or table to move one evidence cursor through every view." + ) + document = r''' + + + + + +JACKAL Linked Evidence Workspace + + + +
+
+ +
JACKAL / THOTHLINKED EVIDENCE WORKSPACE
+
Active modelNo delegated expression loaded
+
checked view
+
+
+
+
+
Graph + numeric tabledelegated samples
+
+ +
#x exacty estimated
+
+
+
+
Symbolic viewstatus preserved
+
Linked inspectorone cursor
x / exact
f(x) / estimated
Move across the plot or focus a table row.
+
+
+ +
+
''' + html.escape(shell_note) + r'''Pixels are not proof. Use exact or bounded lanes for conclusions.
+
+ + + +''' + if len(document.encode("utf-8")) > MAX_RESOURCE_TEXT_BYTES: + raise Refusal("resource-budget", "linked workspace HTML exceeds the resource budget") + return document + + +def workspace_shell() -> str: + return _workspace_document( + { + "status": "checked", + "expression": "", + "points": [], + "finite_sample_count": "0", + "canonical_text": "", + "derivative_text": "", + "route": [], + }, + shell=True, + ) + + +def _workspace_tool(arguments: dict) -> dict: + expression = arguments.get("expression") + if ( + not isinstance(expression, str) + or not expression + or len(expression.encode("utf-8")) > MAX_EXPRESSION_BYTES + or any(ord(character) < 32 for character in expression) + ): + raise Refusal("args", "expression must be nonempty bounded printable text") + lower = _token(arguments.get("x_min"), "x_min") + upper = _token(arguments.get("x_max"), "x_max") + if _compare(lower, upper) >= 0: + raise Refusal("interval-order", "x_min must be strictly below x_max") + samples_text, samples = _integer( + arguments.get("samples"), "samples", maximum=MAX_WORKSPACE_SAMPLES + ) + if samples < MIN_WORKSPACE_SAMPLES: + raise Refusal("sample-budget", "workspace sample count is below the admitted minimum") + + canonical = _kernel_call("jackal_canon", {"expression": expression}, allow_refusal=True) + derivative = _kernel_call("jackal_diff", {"expression": expression}, allow_refusal=True) + points: list[dict[str, str]] = [] + finite_count = 0 + for index in range(samples): + coordinate = _exact( + f"({lower})+({index})*(({upper})-({lower}))/(({samples_text})-1)" + ) + substituted = X_TOKEN.sub(f"({coordinate})", expression) + evaluated = _kernel_call( + "jackal_evaluate", {"expression": substituted}, allow_refusal=True + ) + rendered = evaluated.get("engine_output") + if evaluated.get("status") != "estimated" or not isinstance(rendered, str): + points.append( + { + "x": coordinate, + "status": "refused" if evaluated.get("status") == "refused" else "indeterminate", + "reason": str(evaluated.get("reason", "no finite delegated value")), + } + ) + continue + try: + visual_value = decimal.Decimal(rendered) + except decimal.InvalidOperation: + visual_value = decimal.Decimal("NaN") + if not visual_value.is_finite(): + points.append({"x": coordinate, "status": "indeterminate", "reason": "non-finite"}) + continue + finite_count += 1 + points.append({"x": coordinate, "y": rendered, "status": "estimated"}) + + canonical_text = canonical.get("engine_output") + derivative_text = derivative.get("engine_output") + route: list[dict[str, str]] = [] + for item in _TRACE: + route.append( + { + "tool": str(item.get("tool", "unknown")), + "status": str(item.get("status", "unknown")), + "parsed": str(item.get("parsed", item.get("engine_output", "delegated call")))[:280], + } + ) + finite_count_exact = _count_exact(finite_count) + payload = { + "status": "estimated", + "expression": expression, + "points": points, + "finite_sample_count": finite_count_exact, + "canonical_text": canonical_text if isinstance(canonical_text, str) else "Canonical view refused", + "derivative_text": derivative_text if isinstance(derivative_text, str) else "Derivative view refused", + "route": route, + } + resource_text = _workspace_document(payload) + resource_digest = hashlib.sha256(resource_text.encode("utf-8")).hexdigest() + summary = ( + "JACKAL linked evidence workspace: symbolic, numeric, graph, table, sensor dock, " + "and evidence-route views synchronized over delegated results. Pixels are not proof." + ) + return { + "status": "checked", + "lane": "linked-evidence-workspace-v1", + "formal": False, + "consequence_ceiling": CONSEQUENCE_CEILING, + "parsed": { + "expression": expression, + "x_interval": [lower, upper], + "samples": samples_text, + }, + "fields": { + "points": points, + "finite_sample_count": finite_count_exact, + "canonical_result": canonical, + "derivative_result": derivative, + "resource_uri": f"ui://jackal/linked-workspace/{resource_digest}", + "resource_sha256": resource_digest, + "resource_mime_type": "text/html", + }, + "field_status": { + "points.x": "exact", + "points.y": "estimated", + "canonical_result": str(canonical.get("status", "indeterminate")), + "derivative_result": str(derivative.get("status", "indeterminate")), + "resource_sha256": "checked", + }, + "delegated_to": list(_TRACE), + "identities": {"jackal_stem_sha256": _identity()}, + "non_claims": [ + "The linked workspace is a presentation artifact and adds no assurance to any delegated result", + "SVG geometry, graph pixels, line segments, hover selection, table ordering, and browser sensor display are not evidence", + "Sampling cannot prove continuity, roots, extrema, absence of poles, or behavior between samples", + "The browser sensor dock does not mint observed or measured provenance; export data through jackal_sensor with its source metadata", + ], + "_mcp_content": [ + {"type": "text", "text": summary}, + { + "type": "resource", + "resource": { + "uri": f"ui://jackal/linked-workspace/{resource_digest}", + "mimeType": "text/html", + "text": resource_text, + }, + }, + ], + } + + +def dispatch_integrated( + name: str, + arguments: dict, + kernel_call: Callable[[str, dict], dict], + identity: str, +) -> dict: + global _KERNEL, _IDENTITY, _TRACE + if name not in STEM_TOOL_NAMES or not isinstance(arguments, dict): + return { + "status": "refused", + "reason": "tool-unknown", + "detail": "STEM tool name or arguments are invalid", + } + + class Kernel: + @staticmethod + def call(tool: str, delegated_arguments: dict) -> dict: + return kernel_call(tool, delegated_arguments) + + _KERNEL = Kernel() + _IDENTITY = identity + _TRACE = [] + try: + if name == "jackal_matrix": + return _matrix_tool(arguments) + if name == "jackal_regression": + return _regression_tool(arguments) + if name == "jackal_probability": + return _probability_tool(arguments) + if name == "jackal_hypothesis": + return _hypothesis_tool(arguments) + if name == "jackal_sensor": + return _sensor_tool(arguments) + if name == "jackal_aerospace": + return _aerospace_tool(arguments) + return _workspace_tool(arguments) + except Refusal as error: + return _refusal(error.reason, error.detail) + except Exception: + return _refusal("stem-error", "STEM orchestration failed closed") + finally: + _KERNEL = None + _IDENTITY = None + _TRACE = [] + + +def _schema(properties: dict, required: list[str]) -> dict: + return { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": properties, + "required": required, + "additionalProperties": False, + } + + +def _definition(name: str, title: str, description: str, schema: dict) -> dict: + return { + "name": name, + "title": title, + "description": description, + "inputSchema": schema, + "annotations": { + "readOnlyHint": True, + "destructiveHint": False, + "idempotentHint": True, + "openWorldHint": False, + }, + } + + +def _numeric_array(description: str) -> dict: + return { + "type": "array", + "items": {"type": "string"}, + "description": description, + } + + +def tool_definitions() -> list[dict]: + matrix_schema = { + "type": "array", + "items": {"type": "array", "items": {"type": "string"}}, + "description": "Rectangular array of exact integer, decimal, scientific, or rational tokens.", + } + return [ + _definition( + "jackal_matrix", + "JACKAL exact matrices", + "Exact-rational matrix addition, multiplication, transpose, determinant, RREF, inverse, and linear solve. Every reported numeric cell delegates to jackal_exact; orchestration is identity-pinned and tested, not formal-bounded.", + _schema( + { + "operation": {"type": "string", "enum": ["add", "determinant", "inverse", "multiply", "rref", "solve", "transpose"]}, + "matrix": matrix_schema, + "second_matrix": matrix_schema, + "vector": _numeric_array("Right-hand-side vector for solve."), + }, + ["operation", "matrix"], + ), + ), + _definition( + "jackal_regression", + "JACKAL exact-field regression", + "Polynomial ordinary-least-squares regression with exact-rational normal equations, coefficients, fitted values, SSE, SST, and R-squared. Top-level status is model-based because exact fitting does not validate the model.", + _schema( + { + "model": {"type": "string", "enum": ["polynomial_ols"]}, + "degree": {"type": "string", "description": "Canonical polynomial degree within the tool budget."}, + "x": _numeric_array("Exact-rational predictor values."), + "y": _numeric_array("Exact-rational response values."), + }, + ["model", "degree", "x", "y"], + ), + ), + _definition( + "jackal_probability", + "JACKAL probability models", + "Exact binomial PMF/CDF fields or estimated finite-cutoff normal CDF integration. All outputs remain model-based and preserve distributional assumptions.", + _schema( + { + "operation": {"type": "string", "enum": ["binomial_pmf", "binomial_cdf", "normal_cdf"]}, + "n": {"type": "string"}, + "k": {"type": "string"}, + "p": {"type": "string"}, + "z": {"type": "string"}, + "tail_cutoff": {"type": "string"}, + "tolerance": {"type": "string"}, + }, + ["operation"], + ), + ), + _definition( + "jackal_hypothesis", + "JACKAL hypothesis tests", + "One-sample z testing with estimated finite-tail p-values or exact one-sided binomial tails. Returns model-based with test assumptions and never interprets a p-value as the probability a hypothesis is true.", + _schema( + { + "operation": {"type": "string", "enum": ["one_sample_z", "exact_binomial_tail"]}, + "alternative": {"type": "string", "enum": ["less", "greater", "two_sided"]}, + "sample_mean": {"type": "string"}, + "null_mean": {"type": "string"}, + "population_sd": {"type": "string"}, + "n": {"type": "string"}, + "k": {"type": "string"}, + "p0": {"type": "string"}, + "tail_cutoff": {"type": "string"}, + "tolerance": {"type": "string"}, + }, + ["operation", "alternative"], + ), + ), + _definition( + "jackal_sensor", + "JACKAL sensor data", + "Ingest a caller-supplied sensor batch or apply a declared exact linear calibration, preserving supplied provenance and returning exact descriptive fields plus a formal-bounded standard-deviation enclosure.", + _schema( + { + "operation": {"type": "string", "enum": ["ingest_batch", "linear_calibration"]}, + "sensor_id": {"type": "string"}, + "channel": {"type": "string"}, + "quantity": {"type": "string"}, + "unit": {"type": "string"}, + "samples": _numeric_array("Raw caller-supplied sample tokens."), + "source": {"type": "string"}, + "observed_at": {"type": "string"}, + "scale": {"type": "string"}, + "offset": {"type": "string"}, + "calibration_source": {"type": "string"}, + "calibration_as_of": {"type": "string"}, + }, + ["operation", "sensor_id", "channel", "quantity", "unit", "samples", "source", "observed_at"], + ), + ), + _definition( + "jackal_aerospace", + "JACKAL aerospace models", + "Claim-aware circular-orbit, vis-viva, rocket-equation, Hohmann-transfer, and plane-change workflows. Exact/formal scalar fields remain conditional on explicit physical-model assumptions and never inherit the published finite-burn certificate.", + _schema( + { + "operation": {"type": "string", "enum": ["circular_orbit", "vis_viva", "rocket_equation", "hohmann_transfer", "plane_change"]}, + "parameters": {"type": "object", "description": "Named exact-rational parameters for the selected aerospace model."}, + }, + ["operation", "parameters"], + ), + ), + _definition( + "jackal_linked_workspace", + "JACKAL linked evidence workspace", + "Return a professional self-contained HTML workspace linking symbolic, numeric, graph, table, sensor-dock, and evidence-route views over delegated JACKAL results. The UI adds no assurance; pixels are not proof.", + _schema( + { + "expression": {"type": "string", "description": "JACKAL expression in plotting variable x."}, + "x_min": {"type": "string", "description": "Exact-rational lower x bound."}, + "x_max": {"type": "string", "description": "Exact-rational upper x bound."}, + "samples": {"type": "string", "description": "Canonical bounded sample count."}, + }, + ["expression", "x_min", "x_max", "samples"], + ), + ), + ] + + +if __name__ == "__main__": + raise SystemExit("stem.py is an identity-pinned JACKAL module, not a standalone service") diff --git a/plugins/jackel/scripts/provision_runtime.py b/plugins/jackel/scripts/provision_runtime.py index f12fced..b067a4c 100644 --- a/plugins/jackel/scripts/provision_runtime.py +++ b/plugins/jackel/scripts/provision_runtime.py @@ -23,6 +23,7 @@ import time import unicodedata import urllib.request +from dataclasses import dataclass from pathlib import Path, PurePosixPath from typing import Callable, Iterable, Mapping @@ -98,8 +99,26 @@ MAX_RUNTIME_TOTAL_BYTES = SNAPSHOT_BYTE_LIMIT RUNTIME_ENV_ALLOWLIST = ("JACKAL_HOME",) FIXED_SYSTEM_PATH = "/usr/bin:/bin:/usr/sbin:/sbin" +SNAPSHOT_PREFIX = "jackal-codex-runtime-" +SNAPSHOT_OWNER_FILE = ".owner" +SNAPSHOT_RUNTIME_DIRECTORY = "runtime" +SNAPSHOT_OWNER_SCHEMA = "jackal-runtime-snapshot-owner-v1" +MAX_SNAPSHOT_OWNER_BYTES = 1024 +MAX_SNAPSHOT_NAME_BYTES = 240 _CHECKSUM_LINE = re.compile(r"([0-9a-f]{64}) \./([^\n]+)", re.ASCII) +_LINUX_BOOT_ID = re.compile( + r"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + re.ASCII, +) +_DARWIN_BOOT_TIME = re.compile(r"\bsec = ([0-9]+), usec = ([0-9]+)\b", re.ASCII) +_SNAPSHOT_OWNER_NAME = re.compile( + re.escape(SNAPSHOT_PREFIX) + + r"v1\.([1-9][0-9]*)\.([0-9a-f]+)\.([0-9a-f]+)\.[a-z0-9_]+", + re.ASCII, +) +DARWIN_PROC_PIDTBSDINFO = 3 +DARWIN_MAXCOMLEN = 16 class ProvisionError(RuntimeError): @@ -110,6 +129,44 @@ class _LeaderAnchorLost(ProvisionError): pass +@dataclass(frozen=True) +class SnapshotOwnerIdentity: + """Exact process incarnation that owns one private runtime snapshot.""" + + pid: int + start_time: str + boot_id: str + + +class _DarwinBSDInfo(ctypes.Structure): + """Public `proc_bsdinfo` layout from Darwin's sys/proc_info.h.""" + + _fields_ = [ + ("pbi_flags", ctypes.c_uint32), + ("pbi_status", ctypes.c_uint32), + ("pbi_xstatus", ctypes.c_uint32), + ("pbi_pid", ctypes.c_uint32), + ("pbi_ppid", ctypes.c_uint32), + ("pbi_uid", ctypes.c_uint32), + ("pbi_gid", ctypes.c_uint32), + ("pbi_ruid", ctypes.c_uint32), + ("pbi_rgid", ctypes.c_uint32), + ("pbi_svuid", ctypes.c_uint32), + ("pbi_svgid", ctypes.c_uint32), + ("rfu_1", ctypes.c_uint32), + ("pbi_comm", ctypes.c_char * DARWIN_MAXCOMLEN), + ("pbi_name", ctypes.c_char * (2 * DARWIN_MAXCOMLEN)), + ("pbi_nfiles", ctypes.c_uint32), + ("pbi_pgid", ctypes.c_uint32), + ("pbi_pjobc", ctypes.c_uint32), + ("e_tdev", ctypes.c_uint32), + ("e_tpgid", ctypes.c_uint32), + ("pbi_nice", ctypes.c_int32), + ("pbi_start_tvsec", ctypes.c_uint64), + ("pbi_start_tvusec", ctypes.c_uint64), + ] + + def _data_home(root: Path, system: str | None = None) -> Path: """Per-host application data root. @@ -1138,13 +1195,495 @@ def validate_runtime( return records +class _ProcessGone(ProvisionError): + pass + + +class _SnapshotOwnerStampIncomplete(ProvisionError): + pass + + +def _read_kernel_file(path: Path | str, *, byte_limit: int) -> bytes: + """Read one kernel metadata file whose reported size may be zero.""" + if byte_limit < 1: + raise ProvisionError("invalid kernel metadata byte limit") + try: + fd = os.open(os.fspath(path), os.O_RDONLY | os.O_NONBLOCK | os.O_NOFOLLOW) + except FileNotFoundError as error: + raise _ProcessGone("process identity is absent") from error + except OSError as error: + raise ProvisionError("process identity metadata is unavailable") from error + try: + if not stat.S_ISREG(os.fstat(fd).st_mode): + raise ProvisionError("process identity metadata is not a regular file") + chunks: list[bytes] = [] + count = 0 + while chunk := os.read(fd, min(DOWNLOAD_CHUNK_SIZE, byte_limit - count + 1)): + count += len(chunk) + if count > byte_limit: + raise ProvisionError("process identity metadata exceeds byte limit") + chunks.append(chunk) + return b"".join(chunks) + finally: + os.close(fd) + + +def _parse_linux_process_stat(raw: bytes, *, expected_pid: int | None = None) -> tuple[int, str]: + """Return the procfs PID and field-22 start token without parsing `comm`.""" + try: + text = raw.decode("ascii").strip() + except UnicodeDecodeError as error: + raise ProvisionError("process stat is not ASCII") from error + left = text.find("(") + right = text.rfind(")") + if left < 1 or right <= left or right + 2 >= len(text): + raise ProvisionError("process stat has an invalid shape") + pid_text = text[:left].strip() + fields = text[right + 1 :].strip().split() + if not pid_text.isdecimal() or len(fields) <= 19 or not fields[19].isdecimal(): + raise ProvisionError("process stat omits an exact start token") + pid = int(pid_text) + if pid < 1 or (expected_pid is not None and pid != expected_pid): + raise ProvisionError("process stat PID does not match its path") + return pid, fields[19] + + +def _linux_process_identity(pid: int | None = None) -> tuple[int, str]: + path = Path("/proc/self/stat") if pid is None else Path("/proc") / str(pid) / "stat" + return _parse_linux_process_stat( + _read_kernel_file(path, byte_limit=MAX_SNAPSHOT_OWNER_BYTES), + expected_pid=pid, + ) + + +def _identity_command(command: list[str]) -> str: + try: + result = subprocess.run( + command, + stdin=subprocess.DEVNULL, + stdout=subprocess.PIPE, + stderr=subprocess.DEVNULL, + text=True, + encoding="ascii", + errors="strict", + timeout=2.0, + check=False, + env={"PATH": FIXED_SYSTEM_PATH, "LC_ALL": "C"}, + ) + except (OSError, subprocess.SubprocessError, UnicodeError) as error: + raise ProvisionError("process identity command is unavailable") from error + output = result.stdout.strip() + if result.returncode != 0 or not output or len(output.encode("ascii")) > MAX_SNAPSHOT_OWNER_BYTES: + raise ProvisionError("process identity command refused") + return output + + +def _darwin_process_identity(pid: int | None = None) -> tuple[int, str]: + actual_pid = os.getpid() if pid is None else pid + if actual_pid < 1: + raise ProvisionError("invalid process PID") + try: + libproc = ctypes.CDLL("/usr/lib/libproc.dylib", use_errno=True) + proc_pidinfo = libproc.proc_pidinfo + proc_pidinfo.argtypes = [ + ctypes.c_int, + ctypes.c_int, + ctypes.c_uint64, + ctypes.c_void_p, + ctypes.c_int, + ] + proc_pidinfo.restype = ctypes.c_int + info = _DarwinBSDInfo() + size = ctypes.sizeof(info) + ctypes.set_errno(0) + result = proc_pidinfo( + actual_pid, + DARWIN_PROC_PIDTBSDINFO, + 0, + ctypes.byref(info), + size, + ) + except (AttributeError, OSError) as error: + raise ProvisionError("Darwin process identity API is unavailable") from error + if result != size: + try: + os.kill(actual_pid, 0) + except ProcessLookupError as error: + raise _ProcessGone("process identity is absent") from error + except PermissionError as error: + raise ProvisionError("process identity is not inspectable") from error + raise ProvisionError("Darwin process identity API refused") + if ( + info.pbi_pid != actual_pid + or info.pbi_start_tvsec < 1 + or info.pbi_start_tvusec >= 1_000_000 + ): + raise ProvisionError("Darwin process identity has an invalid shape") + return actual_pid, f"{info.pbi_start_tvsec}:{info.pbi_start_tvusec}" + + +def _boot_identity(system: str | None = None) -> str: + actual_system = platform.system() if system is None else system + if actual_system == "Linux": + try: + token = _read_kernel_file( + "/proc/sys/kernel/random/boot_id", + byte_limit=MAX_SNAPSHOT_OWNER_BYTES, + ).decode("ascii").strip() + except _ProcessGone as error: + raise ProvisionError("Linux boot identity is unavailable") from error + except UnicodeDecodeError as error: + raise ProvisionError("Linux boot identity is not ASCII") from error + if _LINUX_BOOT_ID.fullmatch(token) is None: + raise ProvisionError("Linux boot identity has an invalid shape") + return f"linux:{token}" + if actual_system == "Darwin": + output = _identity_command(["/usr/sbin/sysctl", "-n", "kern.boottime"]) + match = _DARWIN_BOOT_TIME.search(output) + if match is None: + raise ProvisionError("Darwin boot identity has an invalid shape") + return f"darwin:{match.group(1)}:{match.group(2)}" + raise ProvisionError(f"snapshot ownership is unsupported on {actual_system}") + + +def _current_snapshot_owner() -> SnapshotOwnerIdentity: + system = platform.system() + if system == "Linux": + pid, start_time = _linux_process_identity() + elif system == "Darwin": + pid, start_time = _darwin_process_identity() + else: + raise ProvisionError(f"snapshot ownership is unsupported on {system}") + return SnapshotOwnerIdentity(pid=pid, start_time=start_time, boot_id=_boot_identity(system)) + + +def _process_start_time(pid: int) -> str: + system = platform.system() + if system == "Linux": + unused_pid, start_time = _linux_process_identity(pid) + return start_time + if system == "Darwin": + unused_pid, start_time = _darwin_process_identity(pid) + return start_time + raise ProvisionError(f"snapshot ownership is unsupported on {system}") + + +def _snapshot_owner_bytes(identity: SnapshotOwnerIdentity) -> bytes: + if ( + isinstance(identity.pid, bool) + or not isinstance(identity.pid, int) + or identity.pid < 1 + or not isinstance(identity.start_time, str) + or not identity.start_time + or not isinstance(identity.boot_id, str) + or not identity.boot_id + ): + raise ProvisionError("snapshot owner identity is invalid") + for value in (identity.start_time, identity.boot_id): + try: + encoded_value = value.encode("ascii") + except UnicodeEncodeError as error: + raise ProvisionError("snapshot owner identity is not bounded ASCII") from error + if len(encoded_value) > MAX_SNAPSHOT_OWNER_BYTES or any( + ord(character) < 32 or ord(character) == 127 for character in value + ): + raise ProvisionError("snapshot owner identity is not bounded ASCII") + document = { + "boot_id": identity.boot_id, + "pid": identity.pid, + "schema": SNAPSHOT_OWNER_SCHEMA, + "start_time": identity.start_time, + } + encoded = ( + json.dumps(document, ensure_ascii=True, sort_keys=True, separators=(",", ":")) + "\n" + ).encode("ascii") + if len(encoded) > MAX_SNAPSHOT_OWNER_BYTES: + raise ProvisionError("snapshot owner stamp exceeds byte limit") + return encoded + + +def _snapshot_owner_directory_prefix(identity: SnapshotOwnerIdentity) -> str: + """Encode ownership into the atomically created directory name.""" + _snapshot_owner_bytes(identity) + prefix = ( + f"{SNAPSHOT_PREFIX}v1.{identity.pid}." + f"{identity.boot_id.encode('ascii').hex()}." + f"{identity.start_time.encode('ascii').hex()}." + ) + if len(prefix.encode("ascii")) >= MAX_SNAPSHOT_NAME_BYTES: + raise ProvisionError("snapshot owner directory name exceeds byte limit") + return prefix + + +def _snapshot_owner_from_directory_name(path: Path) -> SnapshotOwnerIdentity: + match = _SNAPSHOT_OWNER_NAME.fullmatch(path.name) + if match is None or len(path.name.encode("ascii", "ignore")) > MAX_SNAPSHOT_NAME_BYTES: + raise ProvisionError("snapshot owner directory name is not stamped") + try: + boot_id = bytes.fromhex(match.group(2)).decode("ascii") + start_time = bytes.fromhex(match.group(3)).decode("ascii") + except (UnicodeDecodeError, ValueError) as error: + raise ProvisionError("snapshot owner directory name is invalid") from error + identity = SnapshotOwnerIdentity( + pid=int(match.group(1)), start_time=start_time, boot_id=boot_id + ) + _snapshot_owner_bytes(identity) + if not path.name.startswith(_snapshot_owner_directory_prefix(identity)): + raise ProvisionError("snapshot owner directory name is not canonical") + return identity + + +def _write_snapshot_owner(owner_root: Path, identity: SnapshotOwnerIdentity) -> None: + root_fd = os.open(owner_root, _directory_flags()) + fd = -1 + try: + fd = os.open( + SNAPSHOT_OWNER_FILE, + os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW, + 0o600, + dir_fd=root_fd, + ) + view = memoryview(_snapshot_owner_bytes(identity)) + while view: + written = os.write(fd, view) + if written <= 0: + raise ProvisionError("snapshot owner stamp write made no progress") + view = view[written:] + os.fchmod(fd, 0o600) + os.fsync(fd) + os.fsync(root_fd) + except OSError as error: + raise ProvisionError("snapshot owner stamp could not be written safely") from error + finally: + if fd >= 0: + os.close(fd) + os.close(root_fd) + + +def _load_snapshot_owner(owner_root: Path) -> SnapshotOwnerIdentity: + try: + root_fd = os.open(owner_root, _directory_flags()) + except FileNotFoundError as error: + raise _SnapshotOwnerStampIncomplete("snapshot owner stamp is absent") from error + except OSError as error: + raise ProvisionError("snapshot owner directory is unreadable") from error + fd = -1 + try: + fd = os.open(SNAPSHOT_OWNER_FILE, _file_read_flags(), dir_fd=root_fd) + raw = _read_fd(fd, byte_limit=MAX_SNAPSHOT_OWNER_BYTES) + except FileNotFoundError as error: + raise _SnapshotOwnerStampIncomplete("snapshot owner stamp is absent") from error + except OSError as error: + raise ProvisionError("snapshot owner stamp is unreadable") from error + finally: + if fd >= 0: + os.close(fd) + os.close(root_fd) + + def reject_duplicate_keys(pairs): + result = {} + for key, value in pairs: + if key in result: + raise _SnapshotOwnerStampIncomplete( + "snapshot owner stamp has duplicate keys" + ) + result[key] = value + return result + + try: + document = json.loads(raw.decode("ascii"), object_pairs_hook=reject_duplicate_keys) + except (UnicodeDecodeError, json.JSONDecodeError, RecursionError) as error: + raise _SnapshotOwnerStampIncomplete("snapshot owner stamp is invalid") from error + if not isinstance(document, dict) or set(document) != { + "boot_id", "pid", "schema", "start_time" + } or document.get("schema") != SNAPSHOT_OWNER_SCHEMA: + raise _SnapshotOwnerStampIncomplete( + "snapshot owner stamp has an invalid shape" + ) + identity = SnapshotOwnerIdentity( + pid=document.get("pid"), + start_time=document.get("start_time"), + boot_id=document.get("boot_id"), + ) + try: + canonical = _snapshot_owner_bytes(identity) + except ProvisionError as error: + raise _SnapshotOwnerStampIncomplete( + "snapshot owner stamp has invalid values" + ) from error + if raw != canonical: + raise _SnapshotOwnerStampIncomplete("snapshot owner stamp is not canonical") + return identity + + +def _private_owner_info(path: Path) -> os.stat_result: + info = path.lstat() + if ( + not stat.S_ISDIR(info.st_mode) + or path.is_symlink() + or info.st_uid != os.geteuid() + or info.st_mode & 0o077 + ): + raise ProvisionError("snapshot owner directory is not private") + return info + + +def _owner_identity_for_reaping(path: Path) -> SnapshotOwnerIdentity: + try: + named_owner = _snapshot_owner_from_directory_name(path) + except ProvisionError: + named_owner = None + try: + stamped_owner = _load_snapshot_owner(path) + except _SnapshotOwnerStampIncomplete: + if named_owner is None: + raise ProvisionError("snapshot owner identity is unavailable") + return named_owner + if named_owner is not None and stamped_owner != named_owner: + raise ProvisionError("snapshot owner name and stamp disagree") + return stamped_owner + + +def _remove_orphaned_snapshot( + path: Path, + expected_info: os.stat_result, + expected_owner: SnapshotOwnerIdentity, +) -> None: + try: + current_info = _private_owner_info(path) + current_owner = _owner_identity_for_reaping(path) + except FileNotFoundError: + return + if _file_signature(current_info) != _file_signature(expected_info) or current_owner != expected_owner: + raise ProvisionError("orphaned snapshot changed before cleanup") + parent_fd = os.open(path.parent, _directory_flags()) + root_fd = -1 + try: + root_fd = os.open(path.name, _directory_flags(), dir_fd=parent_fd) + opened_info = os.fstat(root_fd) + if _file_signature(opened_info) != _file_signature(expected_info): + raise ProvisionError("orphaned snapshot changed before cleanup") + entry_count = [0] + + def remove_contents(directory_fd: int, depth: int) -> None: + if depth > MAX_RUNTIME_DEPTH + 1: + raise ProvisionError("orphaned snapshot exceeds cleanup depth") + with os.scandir(directory_fd) as entries: + for entry in entries: + entry_count[0] += 1 + if entry_count[0] > MAX_RUNTIME_ENTRIES + 2: + raise ProvisionError("orphaned snapshot exceeds cleanup entry limit") + info = entry.stat(follow_symlinks=False) + if stat.S_ISDIR(info.st_mode): + child_fd = os.open( + entry.name, _directory_flags(), dir_fd=directory_fd + ) + try: + if _file_signature(os.fstat(child_fd)) != _file_signature(info): + raise ProvisionError( + "orphaned snapshot changed during cleanup" + ) + remove_contents(child_fd, depth + 1) + finally: + os.close(child_fd) + os.rmdir(entry.name, dir_fd=directory_fd) + elif stat.S_ISREG(info.st_mode): + os.unlink(entry.name, dir_fd=directory_fd) + else: + raise ProvisionError( + "orphaned snapshot contains a link or special entry" + ) + + remove_contents(root_fd, 0) + os.rmdir(path.name, dir_fd=parent_fd) + except FileNotFoundError: + return + except OSError as error: + raise ProvisionError("orphaned snapshot cleanup failed") from error + finally: + if root_fd >= 0: + os.close(root_fd) + os.close(parent_fd) + + +def _snapshot_parent_path(temporary_parent: Path | str | None) -> Path: + if temporary_parent is not None: + return Path(temporary_parent) + try: + return Path(tempfile.gettempdir()).resolve(strict=True) + except OSError as error: + raise ProvisionError("system snapshot parent is unavailable") from error + + +def reap_orphaned_runtime_snapshots( + temporary_parent: Path | str | None = None, + *, + current_boot_id: str | None = None, + process_start_reader: Callable[[int], str] | None = None, + remover: Callable[[Path, os.stat_result, SnapshotOwnerIdentity], None] | None = None, +) -> tuple[Path, ...]: + """Remove only snapshots whose exact stamped process incarnation is dead.""" + parent = _snapshot_parent_path(temporary_parent) + if not parent.exists(): + return () + try: + parent_info = parent.lstat() + except OSError as error: + raise ProvisionError("snapshot parent cannot be inspected safely") from error + if not stat.S_ISDIR(parent_info.st_mode) or parent.is_symlink(): + raise ProvisionError("snapshot parent is not a safe directory") + boot_id = _boot_identity() if current_boot_id is None else current_boot_id + read_start = _process_start_time if process_start_reader is None else process_start_reader + remove = _remove_orphaned_snapshot if remover is None else remover + removed: list[Path] = [] + try: + entries = tuple(os.scandir(parent)) + except OSError as error: + raise ProvisionError("snapshot parent cannot be scanned safely") from error + for entry in entries: + if not entry.name.startswith(SNAPSHOT_PREFIX): + continue + path = parent / entry.name + try: + info = _private_owner_info(path) + owner = _owner_identity_for_reaping(path) + except (OSError, ProvisionError): + continue + if owner.boot_id != boot_id: + continue + try: + current_start = read_start(owner.pid) + except _ProcessGone: + orphaned = True + except (OSError, ProvisionError): + continue + else: + orphaned = current_start != owner.start_time + if not orphaned: + continue + remove(path, info, owner) + removed.append(path) + return tuple(removed) + + class RuntimeSnapshot: - """Own one private runtime copy until the MCP server has reaped its workers.""" + """Own one stamped private runtime copy until the server reaps its workers.""" - def __init__(self, owner: tempfile.TemporaryDirectory[str]) -> None: + def __init__( + self, + owner: tempfile.TemporaryDirectory[str], + identity: SnapshotOwnerIdentity | None = None, + ) -> None: self._owner = owner - self.root = Path(owner.name).resolve(strict=True) + self.owner_root = Path(owner.name).resolve(strict=True) self._closed = False + os.chmod(self.owner_root, 0o700) + _write_snapshot_owner( + self.owner_root, + _current_snapshot_owner() if identity is None else identity, + ) + self.root = self.owner_root / SNAPSHOT_RUNTIME_DIRECTORY + self.root.mkdir(mode=0o700) def close(self) -> None: if self._closed: @@ -1278,21 +1817,27 @@ def create_runtime_snapshot( records = verify_sha256sums( source, expected_manifest_sha256=expected_tree_sha256 ) - parent: Path | None = None - if temporary_parent is not None: - parent = Path(temporary_parent) - try: - parent.mkdir(mode=0o700, parents=True, exist_ok=True) - except OSError as error: - raise ProvisionError("runtime snapshot parent is unavailable") from error + parent = _snapshot_parent_path(temporary_parent) try: + parent.mkdir(mode=0o700, parents=True, exist_ok=True) + reap_orphaned_runtime_snapshots(parent) + except (OSError, ProvisionError) as error: + raise ProvisionError("runtime snapshot parent is unavailable") from error + try: + identity = _current_snapshot_owner() owner = tempfile.TemporaryDirectory( - prefix="jackal-codex-runtime-", - dir=None if parent is None else os.fspath(parent), + prefix=_snapshot_owner_directory_prefix(identity), + dir=os.fspath(parent), ) - except OSError as error: + except (OSError, ProvisionError) as error: raise ProvisionError("cannot create private runtime snapshot") from error - snapshot = RuntimeSnapshot(owner) + try: + snapshot = RuntimeSnapshot(owner, identity) + except Exception as error: + owner.cleanup() + if isinstance(error, ProvisionError): + raise + raise ProvisionError("cannot initialize private runtime snapshot") from error try: os.chmod(snapshot.root, 0o700) source_root_fd = os.open(source, _directory_flags()) diff --git a/plugins/jackel/skills/jackel/SKILL.md b/plugins/jackel/skills/jackel/SKILL.md index 4f8b2fb..f9c8cd7 100644 --- a/plugins/jackel/skills/jackel/SKILL.md +++ b/plugins/jackel/skills/jackel/SKILL.md @@ -1,15 +1,20 @@ --- name: jackel -description: Route claim-aware computation, domain-pack, and Anubis program evidence through JACKAL without overstating assurance. +description: Route evidence-aware CAS, graphing, THOTH measurement, exact-field matrices, statistical models, sensors, aerospace workflows, linked views, claim bundles, nonlinear certificates, and Anubis program evidence through JACKAL without overstating assurance. --- -# JACKAL numerical-trust operator +# JACKAL + THOTH numerical-trust operator -The v1.7.3 release exposes the ordered 41-tool full inventory recorded in -`release/capability_inventory_v1.json`. Treat that generated file as the -capability-name and status source; the release tag, package receipt, and asset -must bind the same exact bytes. +The v1.7.3 sealed runtime exposes the ordered 41-tool inventory recorded in +`release/capability_inventory_v1.json`. The identity-pinned wrapper adds seven +THOTH measurement/provenance tools, three CAS/graph/certificate tools, and +seven additive STEM workflow tools, so clients see one 58-tool JACKAL MCP +surface. THOTH is a named JACKAL subsystem, not a standalone entity or server. +Treat the generated inventory as the +sealed-runtime capability/status source and the identity-pinned wrapper modules +as the source for their additions. The release tag, package receipt, and asset +must still bind the same exact runtime bytes. JACKAL exposes the full tool inventory on its supported hosts. Use it to @@ -29,6 +34,50 @@ and preserve the exact assurance boundary returned by the runtime. - Use a direct tool when the caller needs one narrow operation rather than a claim graph; direct tools remain available and must retain their returned epistemic class. +- Use `jackal_cas` when one evidence-aware front door is preferable. Its closed + operation table delegates to the corresponding sealed-runtime tool. Preserve + the complete nested result: the router adds no assurance and never retries a + refusal on a weaker lane. +- Use `jackal_graph` to render an expression. Its rational x coordinates come + from `jackal_exact`, its y samples are delegated `status=estimated` f64 + evaluations, and its PNG is visualization only. A refused or indeterminate + sample breaks the curve. Never infer continuity, roots, extrema, pole + absence, or between-sample behavior from the pixels; route those claims to a + separate exact or bounded tool. +- Use `jackal_hellgate_ground_state` only for `problem_id=hellgate-v1`. It + replays a startup-accepted, identity-pinned, exact-rational nonlinear Barta + certificate and returns `status=bounded`, not `formal-bounded`. Preserve the + stated comparison, density-transfer, and Python-rational assumptions. It + encloses the nonlinear ground-state eigenvalue, and its separately labelled + strong-convexity transfer encloses only the ground-state quartic norm and + energy functional. Trial moments and residuals remain scoped to `phi`; it + does not enclose ground-state polynomial moments, lambda sensitivity, + tunneling, or Bogoliubov frequencies. +- Use `jackal_matrix` for exact-rational matrix workflows. Every numeric cell + delegates to `jackal_exact`; the wrapper's row-operation orchestration is + identity-pinned and tested but is not `formal-bounded`. +- Use `jackal_regression`, `jackal_probability`, and `jackal_hypothesis` only + with explicitly declared models. Preserve top-level `model-based`, exact or + estimated field statuses, assumptions, non-claims, and the hypothesis tool's + advisory consequence ceiling. Exact coefficients or probabilities do not + validate a distribution, sampling design, causal claim, or decision. +- Use `jackal_sensor` for supplied batches or declared linear calibration. + Preserve `input_provenance=supplied`; the tool does not claim it opened + hardware or authenticated timestamps, units, sensor identity, or calibration. +- Use `jackal_aerospace` for its closed idealized model table. Preserve every + physical assumption and the advisory ceiling. A formal-bounded scalar + subfield certifies only admitted arithmetic and cannot certify mission safety + or inherit the spacecraft finite-burn certificate. +- Use `jackal_linked_workspace` for linked symbolic, numeric, graph, table, + inspector, sensor-dock, and evidence-route views. The HTML resource is + digest-bound, but SVG geometry, browser sensor display, sampling, and pixels + are not mathematical or measurement evidence. +- Use `jackal_convert`, `jackal_rate_apply`, `jackal_percent`, + `jackal_date_delta`, `jackal_stat`, `jackal_compare`, and `jackal_scan` for + THOTH measurement/provenance work. They are part of JACKAL's single MCP + surface and delegate arithmetic to its sealed runtime. Preserve + `delegated_to`, `given`, the `informational` consequence ceiling, and all + non-claims. - Use `jackal_test_exists` / `jackal_claim_cites_test` only for structural source facts. Preserve their `informational` consequence ceiling: existence and citation resolution are not correctness or coverage. @@ -58,12 +107,18 @@ the additive package/runtime epoch is v1.7.3. - `exact`: `jackal_exact` and the exact algebra/number-theory tools. Exact integer or rational computation is not a Lean-formal claim. +- `exact-given`: exact rational arithmetic conditional on the declared datum + carried in `given`; the datum itself remains unverified. This is not a weaker + synonym for `exact` or `estimated`. - `checked`: `jackal_diff`. Sampled numeric agreement is a check, not an identity proof. - `estimated`: `jackal_evaluate`, `jackal_integrate`, `jackal_integrate_adaptive`, and `jackal_solve`; an error estimate is not a bound. -- `bounded`: `jackal_integrate_bound`. Its enclosure is conditional on the - stated f64/libm rounding model and is never formal. +- `bounded`: `jackal_integrate_bound` is conditional on its stated f64/libm + rounding model. `jackal_hellgate_ground_state` instead uses an + identity-pinned exact-rational checker plus a stated nonlinear comparison + theorem. Both are bounded and neither is formal; preserve their different + assumptions rather than treating `bounded` as one implementation method. - `formal-bounded`: only the checker-admitted tools below, and only after the pinned checker accepts. - `model-based`: use a structured `jackal_claim` model step. Preserve every @@ -123,17 +178,16 @@ checker verdicts, or residual non-claims. ## Host runtime -The installer supports exactly two hosts, Darwin/arm64 and Linux/aarch64, and -each is admitted only because its atomic no-replace install primitive is +The provisioner recognizes Darwin/arm64, Linux/aarch64, and Linux/x86_64. A +host is admitted only when its atomic no-replace install primitive is implemented (`renameatx_np` with `RENAME_EXCL` on Darwin, `renameat2` with -`RENAME_NOREPLACE` on Linux). Do not bypass the host guard or substitute -another platform build. - -A supported host is not a published runtime. Only the macOS-arm64 release -asset is published today; on Linux/aarch64 the release table carries no pin, so -provisioning refuses with `no published release asset for host linux-aarch64` -rather than installing another host's bytes. Provision it from a separately -verified local tarball and its own pins. +`RENAME_NOREPLACE` on Linux) and an exact host package pin is available. +Do not bypass the host guard or substitute another platform build. + +A recognized host is not necessarily an available runtime. macOS-arm64 has a +published asset; Linux/aarch64 has an exact host-specific pin for a locally +built tarball and therefore requires `provision --tarball`; Linux/x86_64 has no +package pin and refuses rather than installing another host's bytes. Python >=3.10 is the fixed-path prerequisite: `/opt/homebrew/bin/python3` on Apple Silicon (install with `brew install python`), or `/usr/bin/python3` on diff --git a/release/capability_inventory_v1.json b/release/capability_inventory_v1.json index 1f89f20..e88d5eb 100644 --- a/release/capability_inventory_v1.json +++ b/release/capability_inventory_v1.json @@ -1 +1 @@ -{"catalog":{"path":"plugin/hermes/tools.json","sha256":"53c823f07db512b82e01a4f132ff43be426b4b227c436e8853c5144ae0504e87","version":"v1.7.3"},"inputs":[{"path":"tools/capability_inventory.py","sha256":"a966660ef94d7b788be9f92451a78e43b41e12ae2c4e942834c1703994c2ccc0"},{"path":"plugin/hermes/tools.json","sha256":"53c823f07db512b82e01a4f132ff43be426b4b227c436e8853c5144ae0504e87"},{"path":"plugin/hermes/profiles/core.json","sha256":"49f33ba23cca5ab940f1929604f61491bc914d092f291cda4fe4f06b37d042d3"},{"path":"plugin/hermes/profiles/formal.json","sha256":"9be2b3144486311d9ba7f1d41c5033eb8e2553e9d12b71d46e512401f57a084b"},{"path":"plugin/hermes/profiles/full.json","sha256":"0db937da01737bbc0341a591ecd23e55008d8ffc02368517c7d1e7da8b309dec"},{"path":"plugin/hermes/server.py","sha256":"4c42725d797ac78ed20d3e843e602b1c60c88bd13f74e06c65a6b4016b3b7daf"},{"path":"plugins/jackel/.codex-plugin/plugin.json","sha256":"49bbd046759b045add1caf1f19300431fe7d697b59bfd93b57daf1d7edb709ff"},{"path":"plugins/jackel/mcp/server.py","sha256":"5ae164132f21a8dfd19a5ab0c679ccd3ccfc6e2c35ce4a6a6d2968cd550bc07a"},{"path":"release/MANIFEST.sha256","sha256":"3886588b938986f4f6cfe0c7884d35b8140639408e8e9116d962fb46c3876c51"},{"path":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"path":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"path":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"}],"release":{"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"state":"v1.7.3","statement":"Published release identity; the annotated v1.7.3 tag and GitHub release must bind these exact bytes.","version":"v1.7.3"},"schema":"jackal-capability-inventory-v1","status_vocabulary":["bounded","checked","estimated","exact","formal-bounded","indeterminate","model-based","ok","refused","structural-exact","verified","verified-program-evidence","verified-program-receipt"],"tool_count":41,"tools":[{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_range_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"826bed7e2645735d5d333040eaa8c28425df90b6e87f8dd6aa94df1cc40ace45","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded receipt with the certificate embedded (or refuse). Inputs: expression: Anubis expression in the single variable x, restricted to the certified fragment.; input_lo: Interval lower bound as an integer or reduced ℚ (e.g. '1', '2/3').; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-gaussian","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_gaussian_integral","profiles":["formal","full"],"refusal_boundary":"Only the exact catalog-declared Gaussian form and canonical rational bounds/tolerance are admitted. Any other form, failed enclosure, checker rejection, or pin/identity mismatch refuses without downgrade.","release_state":"v1.7.3","schema_sha256":"4a43f67d68610c9e7b13f8bc8195c6c3e9ea24493494eb5aca8e768d707adb13","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a zero-libm formal-bounded Gaussian integral receipt, rerun the pinned checker, or refuse without downgrade. Inputs: expression: Exact canonical exp(-A*(x-mu)^2) expression; all other expressions refuse.; input_lo: Integration lower bound as a canonical rational.; input_hi: Integration upper bound as a canonical rational.; tolerance: Maximum enclosure width as a positive canonical rational."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-int-cert","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_bound_cert","profiles":["formal","full"],"refusal_boundary":"Only the request-bound v1.7.2 composed-integral fragment and canonical bounds/tolerance are admitted. Request-unbound v1.7.0 evidence, unsupported syntax, failed subdivision, checker rejection, or identity mismatch refuses without using the weaker float lane.","release_state":"v1.7.3","schema_sha256":"1229ede1ee518a9b19d3a201268e598fac6fd52fd2eef1bb379f920d6093b9cd","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a request-bound certified composed definite-integral formal receipt (v1.7.2): the untrusted exact-rational producer mirrors the engine's adaptive subdivision, the pinned Lean-proved jackal_int_cert_check binds the exact raw expression/bounds/tolerance and re-checks the whole subdivision-tree certificate (theorem int_cert_sound), and the receipt is independently re-verified before returning. Request-unbound v1.7.0 receipts are revoked. Certified fragment: num/var/neg/add/sub/mul/div/pow(0..4096)/sin/cos/abs in x. Everything else refuses. The weaker float lane jackal_integrate_bound stays status=bounded and is NOT this tool. Inputs: expression: Integrand in the single variable x, restricted to the certified fragment (num/var/neg/add/sub/mul/div/pow/sin/cos/abs).; input_lo: Integration lower bound as an integer or reduced canonical rational (e.g. '0', '2/3').; input_hi: Integration upper bound as a canonical rational, strictly above input_lo.; tolerance: Maximum enclosure width as a positive canonical rational (e.g. '1/100')."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-receipt-registry","identities":[{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_verify_receipt","profiles":["core","formal","full"],"refusal_boundary":"Only closed-registry range/rational, Gaussian, and current request-bound int-cert receipts matching independent caller expectations are replayed. Unknown epochs/variants, copied rather than caller-pinned expectations, revoked int-cert evidence, or checker/pin mismatch refuses.","release_state":"v1.7.3","schema_sha256":"988b83705212769a01eb2e5f5b44322b5728d5fd86eef4f64f7a4a37e378fc1f","status_classes":["verified","refused"],"supported_fragment":"Re-run the matching pinned Lean-proved checker over an embedded certificate using a closed epoch/variant registry: current v1.7.2 range/rational and request-bound int_cert, replay-only v1.5.0 range/rational, or Gaussian v1.5.0. Request-unbound v1.7.0 int_cert receipts refuse. Inputs: receipt: A jackal-formal-receipt-v1 JSON document.; expected_release_epoch: Caller-authorized release epoch, not copied from the receipt.; expected_command: Caller-authorized operation: range-bound-cert or integrate.; expected_expression: Exact raw expression supplied by the caller.; expected_input_lo: Exact raw lower-bound token supplied by the caller.; expected_input_hi: Exact raw upper-bound token supplied by the caller.; expected_tolerance: Exact raw tolerance token; required for Gaussian and int_cert receipts and forbidden for range receipts."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_sqrt_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"bc611de421d812aa6d6d8772fb986c17bcde74d7fe70ea31ff22433335d67c6d","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q sqrt(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'sqrt(x)' on a canonical rational interval; every other expression refuses without downgrade. v1.4.0 fragment extension. Inputs: expression: Must equal 'sqrt(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational (e.g. '2', '1/4'); must be >= 0.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_exp_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"9cc7bee07eebc566a9e267ad1b30c10a73cb25c18090ed2f9a3e9ec48550b928","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q exp(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'exp(x)' on a canonical rational interval [lo, hi] (general-sign since v1.5.0); every other expression refuses without downgrade. v1.4.1 fragment extension. Inputs: expression: Must equal 'exp(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational; any sign (general-sign since v1.5.0).; input_hi: Interval upper bound (canonical rational, hi >= lo); the producer picks a Taylor degree with 2*hi <= n+1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_ln_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"16dfb2b64dc9e290e1c062eba898233b04b187f1b244f6cc06433c48d1b7da45","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q ln(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'ln(x)' on a canonical rational interval with lo > 0; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'ln(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational; must be > 0.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_sin_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"d578799057048871ff13eca207bda2f9564261fce975801904d8cb34370cc7fe","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q sin(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'sin(x)' on a canonical rational interval whose midpoint m satisfies |m| <= 1; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'sin(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo); midpoint (lo+hi)/2 must satisfy |m| <= 1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_cos_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"d0f575ac0dbfe5e64aede075ae30bb1a625f05963e772febca6ac180b29f062b","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q cos(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'cos(x)' on a canonical rational interval whose midpoint m satisfies |m| <= 1; every other expression refuses without downgrade. Shares the sin_rat producer (--op cos). v1.5.0 fragment extension. Inputs: expression: Must equal 'cos(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo); midpoint (lo+hi)/2 must satisfy |m| <= 1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_atan_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"f16e48c7a37e284e124fe20766c7db2b90b4eed8fb748c2efebc9ee7c4b80767","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q atan(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'atan(x)' on a canonical rational interval; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'atan(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_tanh_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"6f9b24d732cc6fc2b0ad9ef7d51fa8cd88f2a344b3152c54f288f6a25a8fe05a","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q tanh enclosure via the untrusted composite producer + Lean-proved checker. NO libm on the proof-decision path. tanh is not an engine grammar token: admits ONLY the literal composite expression '1-2/(exp(2*x)+1)' (= tanh(x) mathematically) on a canonical rational interval with |lo|,|hi| <= 20; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal '1-2/(exp(2*x)+1)' after whitespace normalization (the frozen tanh-defining composite).; input_lo: Interval lower bound as an integer or reduced rational; |lo| <= 20.; input_hi: Interval upper bound (canonical rational, hi >= lo); |hi| <= 20."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_exact","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"42319cf6d3e3f7a8da025e880b8dfc02eb2c6e3128f8b93c11f41545d8bf1d8d","status_classes":["exact","refused"],"supported_fragment":"Exact big-rational arithmetic (status=exact). NOT formal: computationally exact, outside the Lean certificate chain. Inputs: expression: Integers, decimals, + - * / ^ (integer exponents), parentheses. Everything else refuses."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_evaluate","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"5baa3a344309d714a8b66c9fb4a14a97c8182b3cfe1326faa2e9967840eee17c","status_classes":["estimated","refused"],"supported_fragment":"IEEE f64 expression evaluation (status=estimated). A plain number, honestly labeled: no bound, no proof. Inputs: expression: Full expression grammar incl. transcendental functions and constants."},{"assurance_classes":["checked"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_diff","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"605972a25cde65779e921b8a27b7f1a0c19d540f5330791ec0fb571cccf858ad","status_classes":["checked","refused"],"supported_fragment":"Symbolic d/dx with numeric self-verification (status=checked). Sampled agreement is a check, not a proof of identity. Inputs: expression: Expression in x; non-differentiable functions fail closed."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"6d05a705ff580a831f75cbcd2079fe88c3b5d9c858bc6b0c3182ec55aa27cd27","status_classes":["estimated","refused"],"supported_fragment":"Fixed-grid Simpson + Richardson error estimate (status=estimated). Grid-limited: NOT a bound. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; panels: Panel count (e.g. '200')."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_adaptive","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"174132e83bff6d18972cf5d88b072b12d7102cad8fdf05197165c64bfac4fea1","status_classes":["estimated","refused"],"supported_fragment":"Adaptive Simpson with refusal semantics (status=estimated). Refuses when unconverged; agreement is still not a bound. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; tolerance: Local tolerance (e.g. '1e-9')."},{"assurance_classes":["bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_bound","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"9932617903499a2ed2baa4ac213f061f422bd8f2e60bca5bf05225a9f9f788a0","status_classes":["bounded","refused"],"supported_fragment":"Certified interval enclosure of an integral (status=bounded). CONDITIONAL on the stated f64/libm rounding model; implementation campaign-tested, NOT mechanized. Never labeled formal. For a Lean-checked formal-bounded composed enclosure over the certified fragment, use jackal_integrate_bound_cert instead. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; tolerance: Max enclosure width (e.g. '1e-6')."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_solve","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"caf1f55ca8ad1fef2e0fb4f5f5bb600edb147f257427de650335500979c13501","status_classes":["estimated","refused"],"supported_fragment":"Bisection root with residual + first-order conditioning diagnostics (status=estimated). Inputs: expression: f(x) whose root is sought.; input_lo: Bracket lower bound (sign change required).; input_hi: Bracket upper bound."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"ea4ca54f74334d678c3daf9c6686fca186041d27bb2f02dabca21a7747e7d416","status_classes":["exact","refused"],"supported_fragment":"Canonical s-expression + SHA-256 of any parsed expression (status=exact). NOT formal: exact computation outside the Lean certificate chain; no exact-cert emitted. Inputs: expression: Any expression the engine grammar parses."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"199fd63f51398c6e883a407d8e2435e42903e9c76f0227d815f3456b3568d9bc","status_classes":["exact","refused"],"supported_fragment":"Dense Q[x] canonical form, degree <= 64 (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Polynomial expression in x within the poly fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_eq","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"76d9390f705758c6ec2d5fe77cd6a1391908f93ef218ebfd5111c067dc32a819","status_classes":["exact","refused"],"supported_fragment":"Decidable polynomial identity over Q[x] (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: lhs: Left polynomial expression in x.; rhs: Right polynomial expression in x."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_gcd","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"dfff2a285e732d52520ea6fe5efabdab5bd6d956c224f30d163ccbbdbd406a5c","status_classes":["exact","refused"],"supported_fragment":"Monic polynomial gcd over Q[x] via Euclid (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: lhs: Left polynomial expression in x.; rhs: Right polynomial expression in x."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_ratfunc_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"3d4c7d73d13aa88606e9e005b7731c19ac63f9fe559b38e6ff777f979afd3b40","status_classes":["exact","refused"],"supported_fragment":"Rational-function canonical form P/Q, gcd-reduced, monic denominator, explicit denominator-nonzero side condition (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Rational-function expression in x within the ratfunc fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_roots_isolate","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"ea98289e6b6319b7c0b3e6e9832e07ff4a9dd06be1d7862956c50df6e1785978","status_classes":["exact","refused"],"supported_fragment":"Sturm-sequence isolation of all distinct real roots (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Polynomial expression in x within the poly fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_alg_sign","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"b4ad3c632887bc8875f8334dea3391017d73f30fa4895d988062882e89c2c1a5","status_classes":["exact","refused"],"supported_fragment":"Exact sign of a Q[x] polynomial at a rational point (status=exact). NOT formal; no exact-cert emitted. Inputs: expression: Polynomial expression in x within the poly fragment.; point: Rational evaluation point (e.g. '3/2')."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_alg_cmp","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"bfea42d3f97e6f0403d11155d667dfec7000719e2aa3af67c8897989a9e2eee4","status_classes":["exact","refused"],"supported_fragment":"Order decision between two isolated real algebraic numbers (status=exact). NOT formal; no exact-cert emitted. Inputs: p: First defining polynomial in x.; a1: First isolating interval lower bound (rational).; b1: First isolating interval upper bound (rational).; q: Second defining polynomial in x.; a2: Second isolating interval lower bound (rational).; b2: Second isolating interval upper bound (rational)."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_xgcd","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"1c7fb606e43e71eeb4ab288c08ea4a6c89efd95beb3f802e084d5d3c1a3beaf6","status_classes":["exact","refused"],"supported_fragment":"Extended gcd with Bezout certificate (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: a: First integer.; b: Second integer."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_mod_pow","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"b3edc74b3901989b9248f8b89feaed2cc396e218abf9ccfca7ab53a99a9c7bc1","status_classes":["exact","refused"],"supported_fragment":"Modular exponentiation via square-and-multiply (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: base: Base integer.; exp: Nonnegative exponent integer.; mod: Modulus integer >= 1."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_mod_inv","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"d0826f19759afacd20d4a5f0d6704a52bce158c6950bb852a5e0774886a4abd7","status_classes":["exact","refused"],"supported_fragment":"Modular inverse with product certificate (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: a: Integer to invert.; m: Modulus integer >= 2; gcd(a, m) must be 1."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_crt","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"d44aebbbcb3b00ad0d192581533c5cfdb164e26431f3ed850406c8ecfa5044b4","status_classes":["exact","refused"],"supported_fragment":"Chinese remainder reconstruction over pairwise-coprime moduli, up to 16 pairs (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: args: Space-separated residue/modulus pairs: 'r1 m1 r2 m2 [...]' (e.g. '2 3 3 5 2 7')."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_divides","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"1191b2b4ce3a9a5c3a1dafb0917fad46ca9c3375c73f4ae59ff7a389d513adb4","status_classes":["exact","refused"],"supported_fragment":"Exact divisibility decision (status=exact). NOT formal; no exact-cert emitted. Inputs: a: Candidate divisor integer.; b: Dividend integer."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_prime_cert","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"3ff03881b24f8fd94db68b210874010e66ce0e3d32666d98a21c1bc40ccc5646","status_classes":["exact","refused"],"supported_fragment":"Pratt primality certificate or composite divisor witness, budgeted and fail-closed (status=exact; n <= 10^60, Pratt tree depth <= 64, nodes <= 512). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: n: Integer >= 2, at most 61 digits."},{"assurance_classes":["estimated","model-based","checked","bounded","formal-bounded","exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"claim-router","identities":[{"label":"claim_kernel","locator":"tools/claim_kernel.py","sha256":"77b0f85ad5fb7214f88898b60ea29ea9fd7be740c38b655388444e6e5181f348"},{"label":"claim_router","locator":"tools/claim_router.py","sha256":"02328cf177a0423bdc5cbca6ec0ea946bb0679bbd3dc6c24140d32598e575afb"},{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"},{"label":"claim_inference_registry","locator":"release/claim/inference_registry_v1.json","sha256":"c70b33d5aee8071b5125e6a5f8ffe5226fc22a137d920c17d9b3463968be13f0"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_claim","profiles":["core","formal","full"],"refusal_boundary":"Only jackal-claim-request-v1 and its closed step vocabulary are compiled. Policy, identity, schema, route, or assurance failures refuse; fallback is off by default and any caller-enabled fallback remains explicit in the route trace rather than silently changing assurance.","release_state":"v1.7.3","schema_sha256":"4d2703ff772433f39ac8b6555727e856685b0e5042b9c2cc8fcaa4402d6b9153","status_classes":["ok","refused"],"supported_fragment":"Compile a structured jackal-claim-request-v1 into a canonical, content-addressed jackal-claim-bundle-v1 evidence graph through the deterministic policy router. Routes through exact, current/archival range-family, Gaussian, request-bound composed-integral, machine, and unit lanes; emits a route trace naming candidates and refusal reasons; and refuses rather than silently downgrading (allow_fallback defaults false). The bundle is independently replayable via jackal_verify_bundle. Inputs: request: jackal-claim-request-v1 object: {schema, steps:[{id, op, ...}], root, policy?, nonce?, emitted_at_unix?, max_age_seconds?, expires_at_unix?}. Step ops: input, exact, enclose, gaussian, integrate_cert, machine, interval_add/sub/mul/div, threshold, decision, convert, and, model, passthrough, attach."},{"assurance_classes":["estimated","model-based","checked","bounded","formal-bounded","exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"claim-verifier","identities":[{"label":"claim_verifier","locator":"tools/claim_bundle_verify.py","sha256":"e0fcb9540c730bd9bb492b528ed42d29d49fc775b3aa0f9b831b6264fd68fd22"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"},{"label":"claim_inference_registry","locator":"release/claim/inference_registry_v1.json","sha256":"c70b33d5aee8071b5125e6a5f8ffe5226fc22a137d920c17d9b3463968be13f0"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_verify_bundle","profiles":["core","formal","full"],"refusal_boundary":"Only canonical bundles matching separately caller-pinned epoch, policy, root proposition, time, and nonce are replayed. Semantic, graph, freshness, evidence, checker, or pin ambiguity returns refused or indeterminate exactly as declared; it is never converted to success.","release_state":"v1.7.3","schema_sha256":"9e3acec17637a352bc88e3b08e8679a34f1efae3539fe1cce05646212be4cb5f","status_classes":["verified","refused","indeterminate"],"supported_fragment":"Independently replay a jackal-claim-bundle-v1 against caller-pinned expectations. The standalone dependency-free verifier recomputes every canonical byte and hash, revalidates the DAG, selects only the closed current/archival range, Gaussian, or current request-bound int-cert checker/proof tuple, re-runs embedded evidence, recomputes machine/unit mathematics, re-evaluates every inference rule and assurance-axis propagation, enforces consequence-class floors and policy, and recomputes the deterministic rendering. Returns verified | refused | indeterminate with exact reasons — never a generic green badge. Inputs: bundle: The jackal-claim-bundle-v1 object to replay.; expected_release_epoch: Caller-pinned epoch (e.g. 'v1.6.0'); never copied from the bundle.; expected_policy_sha256: Caller-pinned SHA-256 of the canonical policy bytes.; expected_root_proposition: Caller-pinned canonical root proposition IR object.; verification_time_unix: Caller-supplied verification time (unix seconds) for freshness/expiry checks.; expected_nonce: Caller nonce; the bundle root must bind exactly this nonce."},{"assurance_classes":["structural-exact"],"consequence_ceiling":"informational","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"structural-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_test_exists_checker","locator":"tools/test_exists_verify.py","sha256":"598cb99e1eb70c9410ca87345efee346f73e43aaf3625427dca17ea04231caea"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_test_exists","profiles":["full"],"refusal_boundary":"Only byte-exact source/citation structure described by the schema is accepted after independent file-byte recomputation. Path traversal, malformed symbols/hashes, missing text/declarations, or checker mismatch refuses; the result never asserts test execution or correctness.","release_state":"v1.7.3","schema_sha256":"9685ecf3bcf78a3a26916455cc528cdeac137420e8694447e2865b33890f9d46","status_classes":["structural-exact","refused"],"supported_fragment":"Domain pack jackal.programming.source, operation programming.source.test_exists.v1, routed through pack-route. States one byte-exact STRUCTURAL fact: a declaration-shaped occurrence of `symbol` exists at `declaration_line` in a file whose content hash is exactly `file_sha256`, and the file contains exactly `declaration_count` such occurrences. The engine validates the canonical FORM; the manifest-pinned independent checker tools/test_exists_verify.py then recomputes every claimed field from the real bytes on disk and only an ACCEPT verdict returns success, so a misstated hash, line or count refuses instead of minting a certificate. ASSURANCE ceiling exact; CONSEQUENCE ceiling informational, and the second does not rise with the first: a test-exists-cert is NEVER evidence that the code under test is correct, that the test executes, that it is collected by any runner, or that it asserts anything at all. NOT formal: no Lean checker and no theorem are involved. Do not cite this certificate in support of a correctness claim. Inputs: file_path: Repository-relative path token; absolute paths and parent traversal refuse `prog-path`.; file_sha256: Exactly 64 lowercase hex characters; the checker recomputes it from the file bytes.; symbol: Identifier of the declaration; a non-identifier refuses `prog-symbol`.; declaration_line: 1-based line of the declaration as a canonical positive integer.; declaration_count: Total declaration-shaped occurrences of `symbol` in the file; `0` refuses `prog-absent`."},{"assurance_classes":["structural-exact"],"consequence_ceiling":"informational","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"structural-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_test_exists_checker","locator":"tools/test_exists_verify.py","sha256":"598cb99e1eb70c9410ca87345efee346f73e43aaf3625427dca17ea04231caea"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_claim_cites_test","profiles":["full"],"refusal_boundary":"Only byte-exact source/citation structure described by the schema is accepted after independent file-byte recomputation. Path traversal, malformed symbols/hashes, missing text/declarations, or checker mismatch refuses; the result never asserts test execution or correctness.","release_state":"v1.7.3","schema_sha256":"69a533155bde04bfd5dedd43e9d63acd02f3e2773757936e9e1714458e20abd4","status_classes":["structural-exact","refused"],"supported_fragment":"Domain pack jackal.programming.source, operation programming.source.claim_cites_test.v1, routed through pack-route. Resolves a citation: `claim_text` occurs verbatim in the document at `doc_path`/`doc_sha256`, and `symbol` has a declaration-shaped occurrence in the cited test file at `test_path`/`test_sha256`. Resolution is all this establishes. It does NOT establish that the cited test covers, exercises or supports the claim — the cited test may check something entirely different, which is the exact defect this operation exists to bound rather than hide. The manifest-pinned tools/test_exists_verify.py re-runs over the certificate and only ACCEPT returns success, so a claim text absent from the document or a dangling citation refuses. ASSURANCE ceiling exact; CONSEQUENCE ceiling informational, and the second does not rise with the first. NOT formal: no Lean checker and no theorem are involved. Inputs: doc_path: Repository-relative path of the document making the claim.; doc_sha256: Exactly 64 lowercase hex characters for the document bytes.; claim_text: The claim sentence, verbatim, 1..2048 bytes; it must occur in the document.; test_path: Repository-relative path of the cited test file.; test_sha256: Exactly 64 lowercase hex characters for the cited test file bytes.; symbol: Identifier the citation resolves to inside the cited test file."},{"assurance_classes":["exact"],"consequence_ceiling":"decision-boundary","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"decision-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_decision_checker","locator":"tools/decision_verify.py","sha256":"f1ad7c9fbd4c1d899dbb4bebabbbeb97e97a56bd4b279ad7d8ec3722bf12e0f6"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_decision_rank","profiles":["full"],"refusal_boundary":"Only 2..6 schema-valid options under a caller-declared admissible numeric criterion are ranked. Invalid shape/sense/unit, value-judgment criteria, zero top margin, or checker mismatch refuses; caller values are not treated as measurements or confidence intervals.","release_state":"v1.7.3","schema_sha256":"843fe08464d40d97094eeb6424c0c29a3e2617172ba56262ca4122468a8bb92f","status_classes":["exact","refused"],"supported_fragment":"Domain pack jackal.decision.matrix, operation decision.matrix.rank.v1, routed through pack-route. Orders 2..6 labelled options by a caller-declared numeric criterion and emits a jackal-decision-cert-v1 naming the selected option, the runner-up and the exact margin; the manifest-pinned tools/decision_verify.py recomputes the whole ordering from the certificate's own option values and only ACCEPT returns success. Criterion admissibility is decided by the engine against a fixed word list, so a bare value judgment refuses `decision-value-judgment`; a top-two tie refuses `decision-margin-zero`. ASSURANCE ceiling exact; CONSEQUENCE ceiling decision-boundary. The arithmetic is exact and the choice of criterion is not: the declared criterion and the declared option values remain the caller's, this result is not a claim that the criterion is the right one, the values are not measurements, and the margin is not a confidence interval. For the closed-unit lane that additionally requires a declared unit, use jackal_decision_rank_v2. NOT formal: no Lean checker and no theorem are involved. Inputs: decision_id: Caller's identifier for this decision, bound into the certificate. Bytes are restricted to [A-Za-z0-9_]; anything else refuses `prog-symbol`.; criterion: The declared numeric criterion (e.g. 'latency_ms'); a value judgment refuses `decision-value-judgment`.; sense: Exactly 'min' or 'max'; anything else refuses `decision-sense-unknown`.; options: 2..6 whitespace-separated `label value` pairs, e.g. 'a 10 b 20 c 30'. Values are canonical integers. A label containing whitespace shifts the pairing and refuses `pack-args-shape`; it is never silently re-paired."},{"assurance_classes":["exact"],"consequence_ceiling":"decision-boundary","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"decision-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_decision_checker","locator":"tools/decision_verify.py","sha256":"f1ad7c9fbd4c1d899dbb4bebabbbeb97e97a56bd4b279ad7d8ec3722bf12e0f6"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_decision_rank_v2","profiles":["full"],"refusal_boundary":"Only 2..6 schema-valid options under a caller-declared admissible numeric criterion are ranked. Invalid shape/sense/unit, value-judgment criteria, zero top margin, or checker mismatch refuses; caller values are not treated as measurements or confidence intervals.","release_state":"v1.7.3","schema_sha256":"cdc8abba09426977a5319b52410204f21e2e1eb7b38a9de31de751fcb862e78a","status_classes":["exact","refused"],"supported_fragment":"Domain pack jackal.decision.matrix, operation decision.matrix.rank.v2, routed through pack-route. Same deterministic ordering as jackal_decision_rank, plus a REQUIRED declared unit drawn from a closed vocabulary: the 65 canonical ids of release/claim/unit_registry_v1.json excluding the dimensionless identity `one` (66 ids in the registry, `one` is not admitted here). Matching is exact-token and case-sensitive; an alias, a spelled-out name such as 'millisecond', a different case, or the dimensionless identity all refuse `decision-unit-unknown`, and an empty unit refuses `decision-unit-missing`. Emits jackal-decision-cert-v2, re-checked by the manifest-pinned tools/decision_verify.py; only ACCEPT returns success. ASSURANCE ceiling exact; CONSEQUENCE ceiling decision-boundary. Honest residual: a declared unit is NOT a measurement. The closed vocabulary forces the caller to name a dimension, and nothing more — a value-judgment criterion that survives the engine's word list is still accepted when a real unit is declared (`most_elegant` in `ms` ranks), and the values themselves remain caller-declared. NOT formal: no Lean checker and no theorem are involved. Inputs: decision_id: Caller's identifier for this decision, bound into the certificate. Bytes are restricted to [A-Za-z0-9_]; anything else refuses `prog-symbol`.; criterion: The declared numeric criterion; a value judgment refuses `decision-value-judgment` even with an admissible unit.; unit: One canonical unit id from release/claim/unit_registry_v1.json, excluding `one`. Exact token, case-sensitive: 'ms' is admitted, 'millisecond' and 'MS' refuse `decision-unit-unknown`.; sense: Exactly 'min' or 'max'; anything else refuses `decision-sense-unknown`.; options: 2..6 whitespace-separated `label value` pairs, e.g. 'a 10 b 20 c 30'. Values are canonical integers. A label containing whitespace shifts the pairing and refuses `pack-args-shape`; it is never silently re-paired."},{"assurance_classes":["verified-program-evidence"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"cafbd25791225856c2914e9dc86b5dcd3e23d6cc0285b09800de34922f76d52e"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_check_program","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"177cfcf9dfcd6bbc6e657eb83b88f04bfedaa0f28f81307077a776e2052df1e2","status_classes":["verified-program-evidence","refused"],"supported_fragment":"Run a caller-pinned Anubis compiler only as `build --evidence` in Safe mode, never execute the compiled artifact, then independently close and replay the resulting strict anubis.program-evidence.v3 package under inventory-safe-v1. Emits only verified-program-evidence or a named refusal. This profile checks producer-attested function/policy inventories but explicitly does not establish policy-construct totality, source-to-VC proof, SMT-to-CNF proof, source-native refinement, runtime behavior, or universal soundness. Inputs: source_path: Local regular non-symlink Anubis source path.; anubis_bin: Local regular non-symlink Anubis executable; caller-pinned and hashed before/after build.; expected_source_sha256: Caller-pinned exact source SHA-256.; expected_compiler_sha256: Caller-pinned approved Anubis executable SHA-256.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1; contracted-safe-v1 refuses.; nonce: Caller nonce bound into the receipt.; out_root: New local output root; existing paths refuse."},{"assurance_classes":["verified-program-evidence"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"cafbd25791225856c2914e9dc86b5dcd3e23d6cc0285b09800de34922f76d52e"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_verify_program","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"45c7aae87c329925f6bd6b9100efc7d099d70fcaeaba915ee59937f019e1153d","status_classes":["verified-program-evidence","refused"],"supported_fragment":"Independently verify caller-selected Anubis Safe source and evidence bytes under inventory-safe-v1: strict v3 roster, exact manifest closure, source/compiler/artifact/policy pins, producer-summary reconciliation, one-to-one solver/proof paths and counters, approved Z3 UNSAT replay, and independent RUP replay. Never executes the artifact and never claims independent policy-construct totality or source-native refinement. Inputs: source_path: Caller-selected regular non-symlink Anubis source path.; evidence_dir: Caller-selected strict anubis.program-evidence.v3 directory.; expected_source_sha256: Caller-pinned exact source SHA-256.; expected_compiler_sha256: Caller-pinned producer executable SHA-256.; expected_artifact_sha256: Caller-pinned sealed artifact SHA-256; artifact bytes are read but never executed.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1.; nonce: Caller nonce bound into the receipt."},{"assurance_classes":["verified-program-receipt"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"cafbd25791225856c2914e9dc86b5dcd3e23d6cc0285b09800de34922f76d52e"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_verify_program_receipt","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"6bb75d81aebf6f2b3b20900357204e9ef0858cdac412ea016868028cdd2a67d3","status_classes":["verified-program-receipt","refused"],"supported_fragment":"Recompute a jackal-anubis-program-receipt-v1 from caller-selected source/evidence bytes and independent caller pins, rejecting outer-digest-consistent semantic laundering. Success is only verified-program-receipt; it does not raise the underlying inventory-safe-v1 assurance ceiling. Inputs: receipt: Program receipt object to replay; its own pins are never trusted.; source_path: Caller-selected regular source path.; evidence_dir: Caller-selected evidence directory.; expected_source_sha256: Caller-pinned source SHA-256.; expected_compiler_sha256: Caller-pinned compiler SHA-256.; expected_artifact_sha256: Caller-pinned artifact SHA-256.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1.; nonce: Caller nonce; never copied from the receipt."}],"unique_tool_count":41} +{"catalog":{"path":"plugin/hermes/tools.json","sha256":"53c823f07db512b82e01a4f132ff43be426b4b227c436e8853c5144ae0504e87","version":"v1.7.3"},"inputs":[{"path":"tools/capability_inventory.py","sha256":"a966660ef94d7b788be9f92451a78e43b41e12ae2c4e942834c1703994c2ccc0"},{"path":"plugin/hermes/tools.json","sha256":"53c823f07db512b82e01a4f132ff43be426b4b227c436e8853c5144ae0504e87"},{"path":"plugin/hermes/profiles/core.json","sha256":"49f33ba23cca5ab940f1929604f61491bc914d092f291cda4fe4f06b37d042d3"},{"path":"plugin/hermes/profiles/formal.json","sha256":"9be2b3144486311d9ba7f1d41c5033eb8e2553e9d12b71d46e512401f57a084b"},{"path":"plugin/hermes/profiles/full.json","sha256":"0db937da01737bbc0341a591ecd23e55008d8ffc02368517c7d1e7da8b309dec"},{"path":"plugin/hermes/server.py","sha256":"4c42725d797ac78ed20d3e843e602b1c60c88bd13f74e06c65a6b4016b3b7daf"},{"path":"plugins/jackel/.codex-plugin/plugin.json","sha256":"0a02d80c9dca90aa91d62c311d669392e485efe4f52987795ce0d3621b6669cf"},{"path":"plugins/jackel/mcp/server.py","sha256":"1fcc4c9793c6f36da5700674d07b5eeb202dd99209c419171f34174cd4d7f001"},{"path":"release/MANIFEST.sha256","sha256":"3886588b938986f4f6cfe0c7884d35b8140639408e8e9116d962fb46c3876c51"},{"path":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"path":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"path":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"}],"release":{"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"state":"v1.7.3","statement":"Published release identity; the annotated v1.7.3 tag and GitHub release must bind these exact bytes.","version":"v1.7.3"},"schema":"jackal-capability-inventory-v1","status_vocabulary":["bounded","checked","estimated","exact","formal-bounded","indeterminate","model-based","ok","refused","structural-exact","verified","verified-program-evidence","verified-program-receipt"],"tool_count":41,"tools":[{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_range_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"826bed7e2645735d5d333040eaa8c28425df90b6e87f8dd6aa94df1cc40ace45","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded receipt with the certificate embedded (or refuse). Inputs: expression: Anubis expression in the single variable x, restricted to the certified fragment.; input_lo: Interval lower bound as an integer or reduced ℚ (e.g. '1', '2/3').; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-gaussian","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_gaussian_integral","profiles":["formal","full"],"refusal_boundary":"Only the exact catalog-declared Gaussian form and canonical rational bounds/tolerance are admitted. Any other form, failed enclosure, checker rejection, or pin/identity mismatch refuses without downgrade.","release_state":"v1.7.3","schema_sha256":"4a43f67d68610c9e7b13f8bc8195c6c3e9ea24493494eb5aca8e768d707adb13","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a zero-libm formal-bounded Gaussian integral receipt, rerun the pinned checker, or refuse without downgrade. Inputs: expression: Exact canonical exp(-A*(x-mu)^2) expression; all other expressions refuse.; input_lo: Integration lower bound as a canonical rational.; input_hi: Integration upper bound as a canonical rational.; tolerance: Maximum enclosure width as a positive canonical rational."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-int-cert","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_bound_cert","profiles":["formal","full"],"refusal_boundary":"Only the request-bound v1.7.2 composed-integral fragment and canonical bounds/tolerance are admitted. Request-unbound v1.7.0 evidence, unsupported syntax, failed subdivision, checker rejection, or identity mismatch refuses without using the weaker float lane.","release_state":"v1.7.3","schema_sha256":"1229ede1ee518a9b19d3a201268e598fac6fd52fd2eef1bb379f920d6093b9cd","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a request-bound certified composed definite-integral formal receipt (v1.7.2): the untrusted exact-rational producer mirrors the engine's adaptive subdivision, the pinned Lean-proved jackal_int_cert_check binds the exact raw expression/bounds/tolerance and re-checks the whole subdivision-tree certificate (theorem int_cert_sound), and the receipt is independently re-verified before returning. Request-unbound v1.7.0 receipts are revoked. Certified fragment: num/var/neg/add/sub/mul/div/pow(0..4096)/sin/cos/abs in x. Everything else refuses. The weaker float lane jackal_integrate_bound stays status=bounded and is NOT this tool. Inputs: expression: Integrand in the single variable x, restricted to the certified fragment (num/var/neg/add/sub/mul/div/pow/sin/cos/abs).; input_lo: Integration lower bound as an integer or reduced canonical rational (e.g. '0', '2/3').; input_hi: Integration upper bound as a canonical rational, strictly above input_lo.; tolerance: Maximum enclosure width as a positive canonical rational (e.g. '1/100')."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-receipt-registry","identities":[{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_verify_receipt","profiles":["core","formal","full"],"refusal_boundary":"Only closed-registry range/rational, Gaussian, and current request-bound int-cert receipts matching independent caller expectations are replayed. Unknown epochs/variants, copied rather than caller-pinned expectations, revoked int-cert evidence, or checker/pin mismatch refuses.","release_state":"v1.7.3","schema_sha256":"988b83705212769a01eb2e5f5b44322b5728d5fd86eef4f64f7a4a37e378fc1f","status_classes":["verified","refused"],"supported_fragment":"Re-run the matching pinned Lean-proved checker over an embedded certificate using a closed epoch/variant registry: current v1.7.2 range/rational and request-bound int_cert, replay-only v1.5.0 range/rational, or Gaussian v1.5.0. Request-unbound v1.7.0 int_cert receipts refuse. Inputs: receipt: A jackal-formal-receipt-v1 JSON document.; expected_release_epoch: Caller-authorized release epoch, not copied from the receipt.; expected_command: Caller-authorized operation: range-bound-cert or integrate.; expected_expression: Exact raw expression supplied by the caller.; expected_input_lo: Exact raw lower-bound token supplied by the caller.; expected_input_hi: Exact raw upper-bound token supplied by the caller.; expected_tolerance: Exact raw tolerance token; required for Gaussian and int_cert receipts and forbidden for range receipts."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_sqrt_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"bc611de421d812aa6d6d8772fb986c17bcde74d7fe70ea31ff22433335d67c6d","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q sqrt(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'sqrt(x)' on a canonical rational interval; every other expression refuses without downgrade. v1.4.0 fragment extension. Inputs: expression: Must equal 'sqrt(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational (e.g. '2', '1/4'); must be >= 0.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_exp_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"9cc7bee07eebc566a9e267ad1b30c10a73cb25c18090ed2f9a3e9ec48550b928","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q exp(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'exp(x)' on a canonical rational interval [lo, hi] (general-sign since v1.5.0); every other expression refuses without downgrade. v1.4.1 fragment extension. Inputs: expression: Must equal 'exp(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational; any sign (general-sign since v1.5.0).; input_hi: Interval upper bound (canonical rational, hi >= lo); the producer picks a Taylor degree with 2*hi <= n+1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_ln_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"16dfb2b64dc9e290e1c062eba898233b04b187f1b244f6cc06433c48d1b7da45","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q ln(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'ln(x)' on a canonical rational interval with lo > 0; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'ln(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational; must be > 0.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_sin_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"d578799057048871ff13eca207bda2f9564261fce975801904d8cb34370cc7fe","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q sin(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'sin(x)' on a canonical rational interval whose midpoint m satisfies |m| <= 1; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'sin(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo); midpoint (lo+hi)/2 must satisfy |m| <= 1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_cos_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"d0f575ac0dbfe5e64aede075ae30bb1a625f05963e772febca6ac180b29f062b","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q cos(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'cos(x)' on a canonical rational interval whose midpoint m satisfies |m| <= 1; every other expression refuses without downgrade. Shares the sin_rat producer (--op cos). v1.5.0 fragment extension. Inputs: expression: Must equal 'cos(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo); midpoint (lo+hi)/2 must satisfy |m| <= 1."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_atan_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"f16e48c7a37e284e124fe20766c7db2b90b4eed8fb748c2efebc9ee7c4b80767","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q atan(x) enclosure via the untrusted producer + Lean-proved checker. NO libm on the proof-decision path. Admits ONLY the exact form 'atan(x)' on a canonical rational interval; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal 'atan(x)' after whitespace normalization.; input_lo: Interval lower bound as an integer or reduced rational.; input_hi: Interval upper bound (canonical rational, hi >= lo)."},{"assurance_classes":["formal-bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"lean-range","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"coverage-inventory","locator":"release/coverage/formal_coverage_inventory.json","sha256":"6373641cd7833bb46a08f44acf683a119e0a637c8acb88d22797b81188d896b6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_tanh_rat_bound","profiles":["formal","full"],"refusal_boundary":"Only the catalog-declared expression and canonical-rational interval fragment is admitted. Unsupported syntax, invalid intervals, missing or mismatched pins, producer/checker rejection, or identity drift refuses; there is no weaker-lane fallback.","release_state":"v1.7.3","schema_sha256":"6f9b24d732cc6fc2b0ad9ef7d51fa8cd88f2a344b3152c54f288f6a25a8fe05a","status_classes":["formal-bounded","refused"],"supported_fragment":"Emit a formal-bounded pure-Q tanh enclosure via the untrusted composite producer + Lean-proved checker. NO libm on the proof-decision path. tanh is not an engine grammar token: admits ONLY the literal composite expression '1-2/(exp(2*x)+1)' (= tanh(x) mathematically) on a canonical rational interval with |lo|,|hi| <= 20; every other expression refuses without downgrade. v1.5.0 fragment extension. Inputs: expression: Must equal '1-2/(exp(2*x)+1)' after whitespace normalization (the frozen tanh-defining composite).; input_lo: Interval lower bound as an integer or reduced rational; |lo| <= 20.; input_hi: Interval upper bound (canonical rational, hi >= lo); |hi| <= 20."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_exact","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"42319cf6d3e3f7a8da025e880b8dfc02eb2c6e3128f8b93c11f41545d8bf1d8d","status_classes":["exact","refused"],"supported_fragment":"Exact big-rational arithmetic (status=exact). NOT formal: computationally exact, outside the Lean certificate chain. Inputs: expression: Integers, decimals, + - * / ^ (integer exponents), parentheses. Everything else refuses."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_evaluate","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"5baa3a344309d714a8b66c9fb4a14a97c8182b3cfe1326faa2e9967840eee17c","status_classes":["estimated","refused"],"supported_fragment":"IEEE f64 expression evaluation (status=estimated). A plain number, honestly labeled: no bound, no proof. Inputs: expression: Full expression grammar incl. transcendental functions and constants."},{"assurance_classes":["checked"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_diff","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"605972a25cde65779e921b8a27b7f1a0c19d540f5330791ec0fb571cccf858ad","status_classes":["checked","refused"],"supported_fragment":"Symbolic d/dx with numeric self-verification (status=checked). Sampled agreement is a check, not a proof of identity. Inputs: expression: Expression in x; non-differentiable functions fail closed."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"6d05a705ff580a831f75cbcd2079fe88c3b5d9c858bc6b0c3182ec55aa27cd27","status_classes":["estimated","refused"],"supported_fragment":"Fixed-grid Simpson + Richardson error estimate (status=estimated). Grid-limited: NOT a bound. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; panels: Panel count (e.g. '200')."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_adaptive","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"174132e83bff6d18972cf5d88b072b12d7102cad8fdf05197165c64bfac4fea1","status_classes":["estimated","refused"],"supported_fragment":"Adaptive Simpson with refusal semantics (status=estimated). Refuses when unconverged; agreement is still not a bound. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; tolerance: Local tolerance (e.g. '1e-9')."},{"assurance_classes":["bounded"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_integrate_bound","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"9932617903499a2ed2baa4ac213f061f422bd8f2e60bca5bf05225a9f9f788a0","status_classes":["bounded","refused"],"supported_fragment":"Certified interval enclosure of an integral (status=bounded). CONDITIONAL on the stated f64/libm rounding model; implementation campaign-tested, NOT mechanized. Never labeled formal. For a Lean-checked formal-bounded composed enclosure over the certified fragment, use jackal_integrate_bound_cert instead. Inputs: expression: Integrand in x.; input_lo: Lower limit.; input_hi: Upper limit.; tolerance: Max enclosure width (e.g. '1e-6')."},{"assurance_classes":["estimated"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_solve","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"caf1f55ca8ad1fef2e0fb4f5f5bb600edb147f257427de650335500979c13501","status_classes":["estimated","refused"],"supported_fragment":"Bisection root with residual + first-order conditioning diagnostics (status=estimated). Inputs: expression: f(x) whose root is sought.; input_lo: Bracket lower bound (sign change required).; input_hi: Bracket upper bound."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"ea4ca54f74334d678c3daf9c6686fca186041d27bb2f02dabca21a7747e7d416","status_classes":["exact","refused"],"supported_fragment":"Canonical s-expression + SHA-256 of any parsed expression (status=exact). NOT formal: exact computation outside the Lean certificate chain; no exact-cert emitted. Inputs: expression: Any expression the engine grammar parses."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"199fd63f51398c6e883a407d8e2435e42903e9c76f0227d815f3456b3568d9bc","status_classes":["exact","refused"],"supported_fragment":"Dense Q[x] canonical form, degree <= 64 (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Polynomial expression in x within the poly fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_eq","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"76d9390f705758c6ec2d5fe77cd6a1391908f93ef218ebfd5111c067dc32a819","status_classes":["exact","refused"],"supported_fragment":"Decidable polynomial identity over Q[x] (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: lhs: Left polynomial expression in x.; rhs: Right polynomial expression in x."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_poly_gcd","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"dfff2a285e732d52520ea6fe5efabdab5bd6d956c224f30d163ccbbdbd406a5c","status_classes":["exact","refused"],"supported_fragment":"Monic polynomial gcd over Q[x] via Euclid (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: lhs: Left polynomial expression in x.; rhs: Right polynomial expression in x."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_ratfunc_canon","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"3d4c7d73d13aa88606e9e005b7731c19ac63f9fe559b38e6ff777f979afd3b40","status_classes":["exact","refused"],"supported_fragment":"Rational-function canonical form P/Q, gcd-reduced, monic denominator, explicit denominator-nonzero side condition (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Rational-function expression in x within the ratfunc fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_roots_isolate","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"ea98289e6b6319b7c0b3e6e9832e07ff4a9dd06be1d7862956c50df6e1785978","status_classes":["exact","refused"],"supported_fragment":"Sturm-sequence isolation of all distinct real roots (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: expression: Polynomial expression in x within the poly fragment."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_alg_sign","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"b4ad3c632887bc8875f8334dea3391017d73f30fa4895d988062882e89c2c1a5","status_classes":["exact","refused"],"supported_fragment":"Exact sign of a Q[x] polynomial at a rational point (status=exact). NOT formal; no exact-cert emitted. Inputs: expression: Polynomial expression in x within the poly fragment.; point: Rational evaluation point (e.g. '3/2')."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_alg_cmp","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"bfea42d3f97e6f0403d11155d667dfec7000719e2aa3af67c8897989a9e2eee4","status_classes":["exact","refused"],"supported_fragment":"Order decision between two isolated real algebraic numbers (status=exact). NOT formal; no exact-cert emitted. Inputs: p: First defining polynomial in x.; a1: First isolating interval lower bound (rational).; b1: First isolating interval upper bound (rational).; q: Second defining polynomial in x.; a2: Second isolating interval lower bound (rational).; b2: Second isolating interval upper bound (rational)."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_xgcd","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"1c7fb606e43e71eeb4ab288c08ea4a6c89efd95beb3f802e084d5d3c1a3beaf6","status_classes":["exact","refused"],"supported_fragment":"Extended gcd with Bezout certificate (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: a: First integer.; b: Second integer."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_mod_pow","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"b3edc74b3901989b9248f8b89feaed2cc396e218abf9ccfca7ab53a99a9c7bc1","status_classes":["exact","refused"],"supported_fragment":"Modular exponentiation via square-and-multiply (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: base: Base integer.; exp: Nonnegative exponent integer.; mod: Modulus integer >= 1."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_mod_inv","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"d0826f19759afacd20d4a5f0d6704a52bce158c6950bb852a5e0774886a4abd7","status_classes":["exact","refused"],"supported_fragment":"Modular inverse with product certificate (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: a: Integer to invert.; m: Modulus integer >= 2; gcd(a, m) must be 1."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_crt","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"d44aebbbcb3b00ad0d192581533c5cfdb164e26431f3ed850406c8ecfa5044b4","status_classes":["exact","refused"],"supported_fragment":"Chinese remainder reconstruction over pairwise-coprime moduli, up to 16 pairs (status=exact). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: args: Space-separated residue/modulus pairs: 'r1 m1 r2 m2 [...]' (e.g. '2 3 3 5 2 7')."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"runtime-only","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_divides","profiles":["full"],"refusal_boundary":"Only the catalog-declared engine command, grammar, side conditions, and budgets are admitted. Parse/domain/validation/non-convergence failures and unsupported fragments return refused; no other lane is substituted and the returned status is not promoted.","release_state":"v1.7.3","schema_sha256":"1191b2b4ce3a9a5c3a1dafb0917fad46ca9c3375c73f4ae59ff7a389d513adb4","status_classes":["exact","refused"],"supported_fragment":"Exact divisibility decision (status=exact). NOT formal; no exact-cert emitted. Inputs: a: Candidate divisor integer.; b: Dividend integer."},{"assurance_classes":["exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"exact-cert-verifier","identities":[{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_prime_cert","profiles":["full"],"refusal_boundary":"Only the catalog-declared exact fragment and budgets are admitted. Invalid grammar, side conditions, limits, certificate mismatch, or independent verifier rejection refuses; exact is not relabeled formal.","release_state":"v1.7.3","schema_sha256":"3ff03881b24f8fd94db68b210874010e66ce0e3d32666d98a21c1bc40ccc5646","status_classes":["exact","refused"],"supported_fragment":"Pratt primality certificate or composite divisor witness, budgeted and fail-closed (status=exact; n <= 10^60, Pratt tree depth <= 64, nodes <= 512). Emits a jackal-exact-cert-v1 certificate independently re-checkable by tools/exact_verify.py. NOT formal. Inputs: n: Integer >= 2, at most 61 digits."},{"assurance_classes":["estimated","model-based","checked","bounded","formal-bounded","exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"claim-router","identities":[{"label":"claim_kernel","locator":"tools/claim_kernel.py","sha256":"77b0f85ad5fb7214f88898b60ea29ea9fd7be740c38b655388444e6e5181f348"},{"label":"claim_router","locator":"tools/claim_router.py","sha256":"02328cf177a0423bdc5cbca6ec0ea946bb0679bbd3dc6c24140d32598e575afb"},{"label":"evaluator","locator":"jackal-native","sha256":"f11f3a429aa64dc0f09eb930e82bc3250e19eeb5a8a74b26b86683fafd72a655"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"},{"label":"claim_inference_registry","locator":"release/claim/inference_registry_v1.json","sha256":"c70b33d5aee8071b5125e6a5f8ffe5226fc22a137d920c17d9b3463968be13f0"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_claim","profiles":["core","formal","full"],"refusal_boundary":"Only jackal-claim-request-v1 and its closed step vocabulary are compiled. Policy, identity, schema, route, or assurance failures refuse; fallback is off by default and any caller-enabled fallback remains explicit in the route trace rather than silently changing assurance.","release_state":"v1.7.3","schema_sha256":"4d2703ff772433f39ac8b6555727e856685b0e5042b9c2cc8fcaa4402d6b9153","status_classes":["ok","refused"],"supported_fragment":"Compile a structured jackal-claim-request-v1 into a canonical, content-addressed jackal-claim-bundle-v1 evidence graph through the deterministic policy router. Routes through exact, current/archival range-family, Gaussian, request-bound composed-integral, machine, and unit lanes; emits a route trace naming candidates and refusal reasons; and refuses rather than silently downgrading (allow_fallback defaults false). The bundle is independently replayable via jackal_verify_bundle. Inputs: request: jackal-claim-request-v1 object: {schema, steps:[{id, op, ...}], root, policy?, nonce?, emitted_at_unix?, max_age_seconds?, expires_at_unix?}. Step ops: input, exact, enclose, gaussian, integrate_cert, machine, interval_add/sub/mul/div, threshold, decision, convert, and, model, passthrough, attach."},{"assurance_classes":["estimated","model-based","checked","bounded","formal-bounded","exact"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"claim-verifier","identities":[{"label":"claim_verifier","locator":"tools/claim_bundle_verify.py","sha256":"e0fcb9540c730bd9bb492b528ed42d29d49fc775b3aa0f9b831b6264fd68fd22"},{"label":"checker","locator":"jackal_cert_check","sha256":"f7a82524d082b51a8d66f9bed653b9c8da51b5424386659c9048b9c0ae276545"},{"label":"range-proof-identity","locator":"release/evidence/range_proof_identity_v172.json","sha256":"84963be9b0a8851a03a38ae71da558b3e9d2c37d9d55ad7da31afbd23188499c"},{"label":"range-proof-digest","locator":null,"sha256":"7b5e76c38fb9bf60f247b42bca75ab378d7dbe4f32c07858759a62470de53d6d"},{"label":"archival-range-checker","locator":"jackal_cert_check_v170","sha256":"05c3518b836f239712f897c483a2ddadad9f544e0887b1b7bb1424a27289de8a"},{"label":"archival-range-coverage-inventory","locator":"formal_coverage_inventory_v170.json","sha256":"18ff7b1d428dbc6f807fd4de27751ba415b33ef0b356088d7fa316ed74bb0ba6"},{"label":"archival-range-proof-identity","locator":"release/evidence/range_proof_identity.json","sha256":"1b2d623904930d748bfbf489637e0e8aa720188e7d68f5250e5bd8f257b89a67"},{"label":"archival-range-proof-digest","locator":null,"sha256":"5d6a1d70289794a7653cd6d854f1239b9f1de6767bad90aab34cc17fb3f7372e"},{"label":"gaussian-checker","locator":"jackal_gaussian_check","sha256":"ccac690bf916f71a4e3baeb0622dac19aa47e3ca4af858c0800c295581ecfacb"},{"label":"gaussian-proof-identity","locator":"release/evidence/gaussian_proof_identity.json","sha256":"7d2ff9ed4934604eba30f3111a147d7e295fd79302f640f57aacd986a23e243c"},{"label":"gaussian-proof-digest","locator":null,"sha256":"828ed69d9e04784e1f750536ebe8c12f4563dd62a37a85397f2aa08769fce1fd"},{"label":"int-cert-checker","locator":"jackal_int_cert_check","sha256":"f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617"},{"label":"int-cert-proof-identity","locator":"release/evidence/int_cert_proof_identity_v172.json","sha256":"a8aefff85666d35cfd5412b10ae3d404260e91a98de53d5f0d2bb9f88f4ffbdf"},{"label":"int-cert-proof-digest","locator":null,"sha256":"8ce4d8ceeaf2eaa47b97838bfcb2e35880f4fc20fb744c6ef2bf175f0b32f91e"},{"label":"exact_verifier","locator":"tools/exact_verify.py","sha256":"2c07e6257ce1524de3e31374371c6d5859dce710767156de2566ec77fa1883a7"},{"label":"claim_inference_registry","locator":"release/claim/inference_registry_v1.json","sha256":"c70b33d5aee8071b5125e6a5f8ffe5226fc22a137d920c17d9b3463968be13f0"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_verify_bundle","profiles":["core","formal","full"],"refusal_boundary":"Only canonical bundles matching separately caller-pinned epoch, policy, root proposition, time, and nonce are replayed. Semantic, graph, freshness, evidence, checker, or pin ambiguity returns refused or indeterminate exactly as declared; it is never converted to success.","release_state":"v1.7.3","schema_sha256":"9e3acec17637a352bc88e3b08e8679a34f1efae3539fe1cce05646212be4cb5f","status_classes":["verified","refused","indeterminate"],"supported_fragment":"Independently replay a jackal-claim-bundle-v1 against caller-pinned expectations. The standalone dependency-free verifier recomputes every canonical byte and hash, revalidates the DAG, selects only the closed current/archival range, Gaussian, or current request-bound int-cert checker/proof tuple, re-runs embedded evidence, recomputes machine/unit mathematics, re-evaluates every inference rule and assurance-axis propagation, enforces consequence-class floors and policy, and recomputes the deterministic rendering. Returns verified | refused | indeterminate with exact reasons — never a generic green badge. Inputs: bundle: The jackal-claim-bundle-v1 object to replay.; expected_release_epoch: Caller-pinned epoch (e.g. 'v1.6.0'); never copied from the bundle.; expected_policy_sha256: Caller-pinned SHA-256 of the canonical policy bytes.; expected_root_proposition: Caller-pinned canonical root proposition IR object.; verification_time_unix: Caller-supplied verification time (unix seconds) for freshness/expiry checks.; expected_nonce: Caller nonce; the bundle root must bind exactly this nonce."},{"assurance_classes":["structural-exact"],"consequence_ceiling":"informational","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"structural-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_test_exists_checker","locator":"tools/test_exists_verify.py","sha256":"598cb99e1eb70c9410ca87345efee346f73e43aaf3625427dca17ea04231caea"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_test_exists","profiles":["full"],"refusal_boundary":"Only byte-exact source/citation structure described by the schema is accepted after independent file-byte recomputation. Path traversal, malformed symbols/hashes, missing text/declarations, or checker mismatch refuses; the result never asserts test execution or correctness.","release_state":"v1.7.3","schema_sha256":"9685ecf3bcf78a3a26916455cc528cdeac137420e8694447e2865b33890f9d46","status_classes":["structural-exact","refused"],"supported_fragment":"Domain pack jackal.programming.source, operation programming.source.test_exists.v1, routed through pack-route. States one byte-exact STRUCTURAL fact: a declaration-shaped occurrence of `symbol` exists at `declaration_line` in a file whose content hash is exactly `file_sha256`, and the file contains exactly `declaration_count` such occurrences. The engine validates the canonical FORM; the manifest-pinned independent checker tools/test_exists_verify.py then recomputes every claimed field from the real bytes on disk and only an ACCEPT verdict returns success, so a misstated hash, line or count refuses instead of minting a certificate. ASSURANCE ceiling exact; CONSEQUENCE ceiling informational, and the second does not rise with the first: a test-exists-cert is NEVER evidence that the code under test is correct, that the test executes, that it is collected by any runner, or that it asserts anything at all. NOT formal: no Lean checker and no theorem are involved. Do not cite this certificate in support of a correctness claim. Inputs: file_path: Repository-relative path token; absolute paths and parent traversal refuse `prog-path`.; file_sha256: Exactly 64 lowercase hex characters; the checker recomputes it from the file bytes.; symbol: Identifier of the declaration; a non-identifier refuses `prog-symbol`.; declaration_line: 1-based line of the declaration as a canonical positive integer.; declaration_count: Total declaration-shaped occurrences of `symbol` in the file; `0` refuses `prog-absent`."},{"assurance_classes":["structural-exact"],"consequence_ceiling":"informational","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"structural-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_test_exists_checker","locator":"tools/test_exists_verify.py","sha256":"598cb99e1eb70c9410ca87345efee346f73e43aaf3625427dca17ea04231caea"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_claim_cites_test","profiles":["full"],"refusal_boundary":"Only byte-exact source/citation structure described by the schema is accepted after independent file-byte recomputation. Path traversal, malformed symbols/hashes, missing text/declarations, or checker mismatch refuses; the result never asserts test execution or correctness.","release_state":"v1.7.3","schema_sha256":"69a533155bde04bfd5dedd43e9d63acd02f3e2773757936e9e1714458e20abd4","status_classes":["structural-exact","refused"],"supported_fragment":"Domain pack jackal.programming.source, operation programming.source.claim_cites_test.v1, routed through pack-route. Resolves a citation: `claim_text` occurs verbatim in the document at `doc_path`/`doc_sha256`, and `symbol` has a declaration-shaped occurrence in the cited test file at `test_path`/`test_sha256`. Resolution is all this establishes. It does NOT establish that the cited test covers, exercises or supports the claim — the cited test may check something entirely different, which is the exact defect this operation exists to bound rather than hide. The manifest-pinned tools/test_exists_verify.py re-runs over the certificate and only ACCEPT returns success, so a claim text absent from the document or a dangling citation refuses. ASSURANCE ceiling exact; CONSEQUENCE ceiling informational, and the second does not rise with the first. NOT formal: no Lean checker and no theorem are involved. Inputs: doc_path: Repository-relative path of the document making the claim.; doc_sha256: Exactly 64 lowercase hex characters for the document bytes.; claim_text: The claim sentence, verbatim, 1..2048 bytes; it must occur in the document.; test_path: Repository-relative path of the cited test file.; test_sha256: Exactly 64 lowercase hex characters for the cited test file bytes.; symbol: Identifier the citation resolves to inside the cited test file."},{"assurance_classes":["exact"],"consequence_ceiling":"decision-boundary","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"decision-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_decision_checker","locator":"tools/decision_verify.py","sha256":"f1ad7c9fbd4c1d899dbb4bebabbbeb97e97a56bd4b279ad7d8ec3722bf12e0f6"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_decision_rank","profiles":["full"],"refusal_boundary":"Only 2..6 schema-valid options under a caller-declared admissible numeric criterion are ranked. Invalid shape/sense/unit, value-judgment criteria, zero top margin, or checker mismatch refuses; caller values are not treated as measurements or confidence intervals.","release_state":"v1.7.3","schema_sha256":"843fe08464d40d97094eeb6424c0c29a3e2617172ba56262ca4122468a8bb92f","status_classes":["exact","refused"],"supported_fragment":"Domain pack jackal.decision.matrix, operation decision.matrix.rank.v1, routed through pack-route. Orders 2..6 labelled options by a caller-declared numeric criterion and emits a jackal-decision-cert-v1 naming the selected option, the runner-up and the exact margin; the manifest-pinned tools/decision_verify.py recomputes the whole ordering from the certificate's own option values and only ACCEPT returns success. Criterion admissibility is decided by the engine against a fixed word list, so a bare value judgment refuses `decision-value-judgment`; a top-two tie refuses `decision-margin-zero`. ASSURANCE ceiling exact; CONSEQUENCE ceiling decision-boundary. The arithmetic is exact and the choice of criterion is not: the declared criterion and the declared option values remain the caller's, this result is not a claim that the criterion is the right one, the values are not measurements, and the margin is not a confidence interval. For the closed-unit lane that additionally requires a declared unit, use jackal_decision_rank_v2. NOT formal: no Lean checker and no theorem are involved. Inputs: decision_id: Caller's identifier for this decision, bound into the certificate. Bytes are restricted to [A-Za-z0-9_]; anything else refuses `prog-symbol`.; criterion: The declared numeric criterion (e.g. 'latency_ms'); a value judgment refuses `decision-value-judgment`.; sense: Exactly 'min' or 'max'; anything else refuses `decision-sense-unknown`.; options: 2..6 whitespace-separated `label value` pairs, e.g. 'a 10 b 20 c 30'. Values are canonical integers. A label containing whitespace shifts the pairing and refuses `pack-args-shape`; it is never silently re-paired."},{"assurance_classes":["exact"],"consequence_ceiling":"decision-boundary","containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"decision-checker","identities":[{"label":"domain_pack_registry","locator":"domain_packs/registry_v1.json","sha256":"b71fb06d36cdee13e7fbf271a80dfe12e6378072ce38d92358cc54ce748aca03"},{"label":"domain_pack_verifier","locator":"tools/domain_pack_verify.py","sha256":"53553ba75d7f233e79fba68597642e7a01d60dec340246147c95a2e8e3ecb08b"},{"label":"domain_pack_decision_checker","locator":"tools/decision_verify.py","sha256":"f1ad7c9fbd4c1d899dbb4bebabbbeb97e97a56bd4b279ad7d8ec3722bf12e0f6"},{"label":"claim_unit_registry","locator":"release/claim/unit_registry_v1.json","sha256":"d2d30dfe2a74d58a5ef31b551ea628106390bfccd72ad34d1cb37381c58d114c"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_decision_rank_v2","profiles":["full"],"refusal_boundary":"Only 2..6 schema-valid options under a caller-declared admissible numeric criterion are ranked. Invalid shape/sense/unit, value-judgment criteria, zero top margin, or checker mismatch refuses; caller values are not treated as measurements or confidence intervals.","release_state":"v1.7.3","schema_sha256":"cdc8abba09426977a5319b52410204f21e2e1eb7b38a9de31de751fcb862e78a","status_classes":["exact","refused"],"supported_fragment":"Domain pack jackal.decision.matrix, operation decision.matrix.rank.v2, routed through pack-route. Same deterministic ordering as jackal_decision_rank, plus a REQUIRED declared unit drawn from a closed vocabulary: the 65 canonical ids of release/claim/unit_registry_v1.json excluding the dimensionless identity `one` (66 ids in the registry, `one` is not admitted here). Matching is exact-token and case-sensitive; an alias, a spelled-out name such as 'millisecond', a different case, or the dimensionless identity all refuse `decision-unit-unknown`, and an empty unit refuses `decision-unit-missing`. Emits jackal-decision-cert-v2, re-checked by the manifest-pinned tools/decision_verify.py; only ACCEPT returns success. ASSURANCE ceiling exact; CONSEQUENCE ceiling decision-boundary. Honest residual: a declared unit is NOT a measurement. The closed vocabulary forces the caller to name a dimension, and nothing more — a value-judgment criterion that survives the engine's word list is still accepted when a real unit is declared (`most_elegant` in `ms` ranks), and the values themselves remain caller-declared. NOT formal: no Lean checker and no theorem are involved. Inputs: decision_id: Caller's identifier for this decision, bound into the certificate. Bytes are restricted to [A-Za-z0-9_]; anything else refuses `prog-symbol`.; criterion: The declared numeric criterion; a value judgment refuses `decision-value-judgment` even with an admissible unit.; unit: One canonical unit id from release/claim/unit_registry_v1.json, excluding `one`. Exact token, case-sensitive: 'ms' is admitted, 'millisecond' and 'MS' refuse `decision-unit-unknown`.; sense: Exactly 'min' or 'max'; anything else refuses `decision-sense-unknown`.; options: 2..6 whitespace-separated `label value` pairs, e.g. 'a 10 b 20 c 30'. Values are canonical integers. A label containing whitespace shifts the pairing and refuses `pack-args-shape`; it is never silently re-paired."},{"assurance_classes":["verified-program-evidence"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"cafbd25791225856c2914e9dc86b5dcd3e23d6cc0285b09800de34922f76d52e"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_check_program","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"177cfcf9dfcd6bbc6e657eb83b88f04bfedaa0f28f81307077a776e2052df1e2","status_classes":["verified-program-evidence","refused"],"supported_fragment":"Run a caller-pinned Anubis compiler only as `build --evidence` in Safe mode, never execute the compiled artifact, then independently close and replay the resulting strict anubis.program-evidence.v3 package under inventory-safe-v1. Emits only verified-program-evidence or a named refusal. This profile checks producer-attested function/policy inventories but explicitly does not establish policy-construct totality, source-to-VC proof, SMT-to-CNF proof, source-native refinement, runtime behavior, or universal soundness. Inputs: source_path: Local regular non-symlink Anubis source path.; anubis_bin: Local regular non-symlink Anubis executable; caller-pinned and hashed before/after build.; expected_source_sha256: Caller-pinned exact source SHA-256.; expected_compiler_sha256: Caller-pinned approved Anubis executable SHA-256.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1; contracted-safe-v1 refuses.; nonce: Caller nonce bound into the receipt.; out_root: New local output root; existing paths refuse."},{"assurance_classes":["verified-program-evidence"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"cafbd25791225856c2914e9dc86b5dcd3e23d6cc0285b09800de34922f76d52e"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_verify_program","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"45c7aae87c329925f6bd6b9100efc7d099d70fcaeaba915ee59937f019e1153d","status_classes":["verified-program-evidence","refused"],"supported_fragment":"Independently verify caller-selected Anubis Safe source and evidence bytes under inventory-safe-v1: strict v3 roster, exact manifest closure, source/compiler/artifact/policy pins, producer-summary reconciliation, one-to-one solver/proof paths and counters, approved Z3 UNSAT replay, and independent RUP replay. Never executes the artifact and never claims independent policy-construct totality or source-native refinement. Inputs: source_path: Caller-selected regular non-symlink Anubis source path.; evidence_dir: Caller-selected strict anubis.program-evidence.v3 directory.; expected_source_sha256: Caller-pinned exact source SHA-256.; expected_compiler_sha256: Caller-pinned producer executable SHA-256.; expected_artifact_sha256: Caller-pinned sealed artifact SHA-256; artifact bytes are read but never executed.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1.; nonce: Caller nonce bound into the receipt."},{"assurance_classes":["verified-program-receipt"],"consequence_ceiling":null,"containing_ref":{"kind":"surface-origin-commit","value":"d25bcd9818e0d106f337798f80527ae611cc3acc"},"dependency":{"family":"program-verifier","identities":[{"label":"anubis_program_verifier","locator":"tools/anubis_program_verify.py","sha256":"cafbd25791225856c2914e9dc86b5dcd3e23d6cc0285b09800de34922f76d52e"},{"label":"anubis_program_policy","locator":"release/program/inventory_safe_v1.json","sha256":"361979bf89b7c71a4b2c692d64756548833a2c363c269511b037726cab3ebacb"},{"label":"program-compatibility-floor","locator":"release/compat/v173_floor.json","sha256":"5b4e78e1f2b3e1ed7d0459a12f229ffe27886c179198a656a5a9dc5343f8b45e"},{"label":"approved_program_compiler","locator":"release/compat/v173_floor.json#approved_check_compiler_sha256","sha256":"0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6"}]},"exposure":{"codex":true,"hermes":true,"kernel":true},"name":"jackal_anubis_verify_program_receipt","profiles":["full"],"refusal_boundary":"Only caller-pinned Safe-source anubis.program-evidence.v3 under inventory-safe-v1 is admitted. Any source/compiler/artifact/policy mismatch, roster or proof-path discrepancy, replay failure, symlink/path violation, or unsupported profile refuses. Artifacts are never executed, and success does not establish construct totality, source-to-VC, SMT-to-CNF, source-native refinement, runtime behavior, or universal soundness.","release_state":"v1.7.3","schema_sha256":"6bb75d81aebf6f2b3b20900357204e9ef0858cdac412ea016868028cdd2a67d3","status_classes":["verified-program-receipt","refused"],"supported_fragment":"Recompute a jackal-anubis-program-receipt-v1 from caller-selected source/evidence bytes and independent caller pins, rejecting outer-digest-consistent semantic laundering. Success is only verified-program-receipt; it does not raise the underlying inventory-safe-v1 assurance ceiling. Inputs: receipt: Program receipt object to replay; its own pins are never trusted.; source_path: Caller-selected regular source path.; evidence_dir: Caller-selected evidence directory.; expected_source_sha256: Caller-pinned source SHA-256.; expected_compiler_sha256: Caller-pinned compiler SHA-256.; expected_artifact_sha256: Caller-pinned artifact SHA-256.; expected_policy_sha256: Caller-pinned inventory-safe-v1 policy digest.; verification_time_unix: Caller-supplied Unix verification time bound into the receipt.; profile: Must be inventory-safe-v1.; nonce: Caller nonce; never copied from the receipt."}],"unique_tool_count":41} diff --git a/tests/capability_drift_gate_test.py b/tests/capability_drift_gate_test.py index ec1d5f9..242a9e2 100644 --- a/tests/capability_drift_gate_test.py +++ b/tests/capability_drift_gate_test.py @@ -85,7 +85,7 @@ def test_current_repository_surface_verifies(self) -> None: result = DRIFT.verify_surface(ROOT) self.assertEqual(result["tool_count"], 41) self.assertEqual(result["unique_tool_count"], 41) - self.assertEqual(result["codex_tool_count"], 41) + self.assertEqual(result["codex_tool_count"], 58) self.assertEqual(result["package_epoch"], "v1.7.3") def test_historical_34_tool_fact_outside_current_contract_is_allowed(self) -> None: @@ -106,6 +106,10 @@ def test_historical_34_tool_fact_outside_current_contract_is_allowed(self) -> No def test_skill_tool_parser_returns_only_real_current_names(self) -> None: inventory = read_json(ROOT / ARTIFACT_PATH) known = {row["name"] for row in inventory["tools"]} + _unified_count, additive = DRIFT._verify_codex_adapter( + ROOT, inventory["tool_count"], known + ) + known.update(additive) skill = (ROOT / "plugins/jackel/skills/jackel/SKILL.md").read_text( encoding="utf-8" ) @@ -130,7 +134,7 @@ def test_cli_reports_bound_counts_and_package_epoch(self) -> None: self.assertEqual(completed.returncode, 0, completed.stderr) self.assertEqual( completed.stdout.strip(), - "CAPABILITY_DRIFT_PASS tools=41 unique=41 codex=41 package=v1.7.3", + "CAPABILITY_DRIFT_PASS tools=41 unique=41 codex=58 package=v1.7.3", ) @@ -217,6 +221,66 @@ def test_refuses_codex_wrapper_count_mismatch(self) -> None: finally: fixture.cleanup() + def test_refuses_codex_unified_count_mismatch(self) -> None: + fixture = DriftFixture() + try: + server = fixture.root / "plugins/jackel/mcp/server.py" + source = self.replace_once( + server.read_text(encoding="utf-8"), + "EXPECTED_UNIFIED_TOOL_COUNT = 58", + "EXPECTED_UNIFIED_TOOL_COUNT = 57", + ) + server.write_text(source, encoding="utf-8") + with self.assertRaisesRegex(DRIFT.DriftError, "codex-tool-count"): + DRIFT.verify_surface(fixture.root) + finally: + fixture.cleanup() + + def test_refuses_structured_content_copy_mechanism_drift(self) -> None: + fixture = DriftFixture() + try: + server = fixture.root / "plugins/jackel/mcp/server.py" + source = self.replace_once( + server.read_text(encoding="utf-8"), + "structured = copy.deepcopy(value)", + "structured = value", + ) + server.write_text(source, encoding="utf-8") + with self.assertRaisesRegex(DRIFT.DriftError, "adapter-mechanism"): + DRIFT.verify_surface(fixture.root) + finally: + fixture.cleanup() + + def test_refuses_structured_content_envelope_drift(self) -> None: + fixture = DriftFixture() + try: + server = fixture.root / "plugins/jackel/mcp/server.py" + source = self.replace_once( + server.read_text(encoding="utf-8"), + 'structured.pop("_mcp_content", None)', + 'structured.pop("content", None)', + ) + server.write_text(source, encoding="utf-8") + with self.assertRaisesRegex(DRIFT.DriftError, "adapter-mechanism"): + DRIFT.verify_surface(fixture.root) + finally: + fixture.cleanup() + + def test_refuses_additive_name_collision_with_runtime(self) -> None: + fixture = DriftFixture() + try: + server = fixture.root / "plugins/jackel/mcp/server.py" + source = self.replace_once( + server.read_text(encoding="utf-8"), + '"jackal_compare",', + '"jackal_exact",', + ) + server.write_text(source, encoding="utf-8") + with self.assertRaisesRegex(DRIFT.DriftError, "codex-tool-count"): + DRIFT.verify_surface(fixture.root) + finally: + fixture.cleanup() + def test_refuses_missing_current_surface_marker(self) -> None: fixture = DriftFixture() try: diff --git a/tests/codex_plugin/live_acceptance.py b/tests/codex_plugin/live_acceptance.py index b071f0a..b6f7ea1 100644 --- a/tests/codex_plugin/live_acceptance.py +++ b/tests/codex_plugin/live_acceptance.py @@ -11,6 +11,7 @@ import argparse import base64 +import binascii import copy import hashlib import json @@ -47,7 +48,30 @@ # Anti-shrink floor for the sealed v1.7.3 runtime and matching repository # surface. Exact catalog equality and uniqueness are enforced below; this floor # makes a coordinated truncation refuse before any happy-path calls run. -MIN_TOOL_COUNT = 41 +MIN_RUNTIME_TOOL_COUNT = 41 +MEASUREMENT_TOOLS = ( + "jackal_convert", + "jackal_rate_apply", + "jackal_percent", + "jackal_date_delta", + "jackal_stat", + "jackal_compare", + "jackal_scan", +) +ADVANCED_TOOLS = ( + "jackal_cas", + "jackal_graph", + "jackal_hellgate_ground_state", +) +STEM_TOOLS = ( + "jackal_matrix", + "jackal_regression", + "jackal_probability", + "jackal_hypothesis", + "jackal_sensor", + "jackal_aerospace", + "jackal_linked_workspace", +) HOST_TRANSCRIPT_LIMIT = 4 * 1024 * 1024 HOST_REGISTRY_LIMIT = 1024 * 1024 HOST_REGISTRY_ENTRY_LIMIT = 256 @@ -61,9 +85,14 @@ HOST_BINARY_BYTE_LIMIT = 512 * 1024 * 1024 HOST_BINARY_PATH_LIMIT = 4096 -HERMES_BUNDLE_SHA256 = "c6a27483077b89d899d8c73c03bfeb3191f25db2a22f8021254a7dec763ba5fe" -INT_CERT_PRODUCER_SHA256 = "b4240fdac3c77b2abd751595303b2b3a0e4bebd492b2ae57fa5ccf052cd50af4" -INT_CERT_CHECKER_SHA256 = "f8347cbd18d520852aff56920d41f5e5b496ff192f584e41d84d1a818ff29617" +FORMAL_IDENTITY_FIELDS = frozenset({ + "evaluator_sha256", "producer_sha256", "checker_sha256", "plugin_sha256", +}) +FORMAL_IDENTITY_MANIFEST_ROWS = { + "plugin_hermes": ("plugin_sha256", 2), + "int_cert_producer": ("producer_sha256", 3), + "int_cert_checker": ("checker_sha256", 3), +} CLAIM_TIME = "1786752000" CLAIM_NONCE = "jackal-codex-task5-v1" @@ -1346,12 +1375,13 @@ def run_host_discovery_acceptance( raise AcceptanceError("host acceptance identities changed during the task") if binary_after != binary_before: raise AcceptanceError("host binary identity changed during the task") + runtime_pins = effective_runtime_pins() return { "status": "accepted", "acceptance_kind": "fresh-codex-host-discovery", "wrapper_aggregate_sha256": source_aggregate, - "runtime_package_sha256": provisioner.PACKAGE_SHA256, - "runtime_tree_sha256": provisioner.SHA256SUMS_SHA256, + "runtime_package_sha256": runtime_pins["package_sha256"], + "runtime_tree_sha256": runtime_pins["sha256sums_sha256"], "evidence_path": os.fspath(evidence), "active_mcp_cwd": os.fspath(active_before), "codex_binary_invocation_path": binary_before.invocation_path, @@ -1366,7 +1396,7 @@ def run_host_discovery_acceptance( os.close(evidence_fd) -def tool_payload(response: object) -> dict[str, Any]: +def _tool_result(response: object) -> tuple[dict[str, Any], list[dict[str, Any]]]: if not isinstance(response, dict) or response.get("jsonrpc") != "2.0" \ or "error" in response: raise AcceptanceError("MCP call did not return a successful JSON-RPC response") @@ -1378,9 +1408,16 @@ def tool_payload(response: object) -> dict[str, Any]: structured = result["structuredContent"] content = result["content"] if not isinstance(structured, dict) or not isinstance(content, list) \ - or len(content) != 1 or content[0].get("type") != "text" \ - or not isinstance(content[0].get("text"), str): + or not content or any(not isinstance(block, dict) for block in content): raise AcceptanceError("MCP tool result content shape is invalid") + return structured, content + + +def tool_payload(response: object) -> dict[str, Any]: + structured, content = _tool_result(response) + if len(content) != 1 or content[0].get("type") != "text" \ + or not isinstance(content[0].get("text"), str): + raise AcceptanceError("MCP text fallback shape is invalid") try: text_value = strict_json_loads(content[0]["text"]) except (ValueError, json.JSONDecodeError) as error: @@ -1402,7 +1439,27 @@ def validate_exact(mcp_response: object, direct: object) -> dict[str, Any]: return value -def _verify_formal_receipt(receipt: object) -> dict[str, Any]: +def _validated_formal_identities( + expected_identities: Mapping[str, str], +) -> dict[str, str]: + if not isinstance(expected_identities, Mapping) \ + or set(expected_identities) != FORMAL_IDENTITY_FIELDS: + raise AcceptanceError("formal identity expectations have an unsupported shape") + result = dict(expected_identities) + if any( + not isinstance(value, str) + or re.fullmatch(r"[0-9a-f]{64}", value, re.ASCII) is None + for value in result.values() + ): + raise AcceptanceError("formal identity expectation is not a SHA-256 digest") + if result["evaluator_sha256"] != result["producer_sha256"]: + raise AcceptanceError("int-cert evaluator and producer expectations diverge") + return result + + +def _verify_formal_receipt( + receipt: object, expected_identities: Mapping[str, str], +) -> dict[str, Any]: if not isinstance(receipt, dict): raise AcceptanceError("formal result omitted its receipt") expected_request = { @@ -1427,12 +1484,7 @@ def _verify_formal_receipt(receipt: object) -> dict[str, Any]: "producer_sha256": identities.get("producer_sha256"), "checker_sha256": identities.get("checker_sha256"), "plugin_sha256": identities.get("plugin_sha256"), - } != { - "evaluator_sha256": INT_CERT_PRODUCER_SHA256, - "producer_sha256": INT_CERT_PRODUCER_SHA256, - "checker_sha256": INT_CERT_CHECKER_SHA256, - "plugin_sha256": HERMES_BUNDLE_SHA256, - }: + } != expected_identities: raise AcceptanceError("formal receipt identity binding is invalid") certificate = receipt.get("certificate") if not isinstance(certificate, dict) \ @@ -1459,7 +1511,9 @@ def _normalized_formal(value: dict[str, Any]) -> dict[str, Any]: def validate_formal_int_cert( mcp_response: object, direct: object, + expected_identities: Mapping[str, str], ) -> dict[str, Any]: + expected = _validated_formal_identities(expected_identities) value = tool_payload(mcp_response) if not isinstance(direct, dict): raise AcceptanceError("direct formal backend result is not an object") @@ -1467,7 +1521,7 @@ def validate_formal_int_cert( if result.get("status") != "formal-bounded" \ or result.get("checker_rerun") != "ACCEPT": raise AcceptanceError("formal result was not checker-attested") - _verify_formal_receipt(result.get("receipt")) + _verify_formal_receipt(result.get("receipt"), expected) if _normalized_formal(value) != _normalized_formal(direct): raise AcceptanceError("formal result failed normalized direct backend parity") return value @@ -1553,15 +1607,17 @@ def _validate_bundle_verification(response: object) -> dict[str, Any]: def _validate_receipt_verification( response: object, receipt: dict[str, Any], + expected_identities: Mapping[str, str], ) -> dict[str, Any]: + identities = _validated_formal_identities(expected_identities) value = tool_payload(response) result = receipt["result"] expected = { "receipt_digest_sha256": receipt["receipt_digest_sha256"], "certificate_sha256": receipt["certificate"]["sha256"], - "checker_sha256": INT_CERT_CHECKER_SHA256, - "evaluator_sha256": INT_CERT_PRODUCER_SHA256, - "plugin_sha256": HERMES_BUNDLE_SHA256, + "checker_sha256": identities["checker_sha256"], + "evaluator_sha256": identities["evaluator_sha256"], + "plugin_sha256": identities["plugin_sha256"], "enclosure": [result["enclosure_lo"], result["enclosure_hi"]], } if value.get("status") != "verified" or value.get("verdict") != "ACCEPT" \ @@ -1586,26 +1642,246 @@ def _validate_inventory(response: object, runtime_document: object) -> list[str] if not isinstance(runtime_document, dict) \ or not isinstance(runtime_document.get("tools"), list): raise AcceptanceError("runtime tools document is malformed") - expected = [record.get("name") for record in runtime_document["tools"] - if isinstance(record, dict)] + runtime_expected = [record.get("name") for record in runtime_document["tools"] + if isinstance(record, dict)] + expected = ( + runtime_expected + + list(MEASUREMENT_TOOLS) + + list(ADVANCED_TOOLS) + + list(STEM_TOOLS) + ) result = response.get("result") if isinstance(response, dict) else None tools = result.get("tools") if isinstance(result, dict) else None if not isinstance(tools, list): raise AcceptanceError("MCP tools/list returned no tool inventory") discovered = [record.get("name") for record in tools if isinstance(record, dict)] - if len(expected) < MIN_TOOL_COUNT: + if len(runtime_expected) < MIN_RUNTIME_TOOL_COUNT: raise AcceptanceError("runtime catalog shrank below the frozen floor") if len(discovered) != len(expected) \ or len(set(discovered)) != len(discovered) \ or discovered != expected: - raise AcceptanceError("MCP inventory differs from the exact runtime catalog") + raise AcceptanceError("MCP inventory differs from the exact unified JACKAL surface") return discovered +def _validate_measurement_payload( + response: object, *, status: str, delegated: bool = True, +) -> dict[str, Any]: + value = tool_payload(response) + identity_value = value.get("identities", {}).get("jackal_measurement_sha256") + trace = value.get("delegated_to") + if ( + value.get("status") != status + or value.get("consequence_ceiling") != "informational" + or not isinstance(value.get("parsed"), str) + or not value["parsed"] + or not isinstance(value.get("non_claims"), list) + or re.fullmatch(r"[0-9a-f]{64}", identity_value or "") is None + or not isinstance(trace, list) + or bool(trace) is not delegated + ): + raise AcceptanceError("integrated measurement envelope is invalid") + if status == "exact-given": + given = value.get("given") + if ( + not isinstance(given, dict) + or not isinstance(given.get("source"), str) + or not given["source"] + or not isinstance(given.get("as_of"), str) + or not given["as_of"] + ): + raise AcceptanceError("exact-given measurement omitted provenance") + return value + + +def _validate_measurement_refusal(response: object, *, reason: str) -> dict[str, Any]: + value = tool_payload(response) + if ( + value.get("status") != "refused" + or value.get("reason") != reason + or value.get("consequence_ceiling") != "informational" + or "fields" in value + or not isinstance(value.get("non_claims"), list) + ): + raise AcceptanceError("measurement refusal semantics changed") + return value + + +def _validate_cas_payload(response: object, direct: object) -> dict[str, Any]: + value = tool_payload(response) + trace = value.get("delegated_to") + if ( + value.get("status") != "exact" + or value.get("lane") != "cas-route" + or value.get("formal") is not False + or value.get("result") != direct + or not isinstance(trace, list) + or len(trace) != 1 + or trace[0].get("tool") != "jackal_exact" + or re.fullmatch( + r"[0-9a-f]{64}", + value.get("identities", {}).get("jackal_advanced_sha256", ""), + ) is None + or not isinstance(value.get("non_claims"), list) + ): + raise AcceptanceError("advanced CAS assurance envelope is invalid") + return value + + +def _validate_graph_payload(response: object) -> dict[str, Any]: + value, content = _tool_result(response) + if ( + value.get("status") != "estimated" + or value.get("lane") != "graph-delegated-f64-v1" + or value.get("formal") is not False + or value.get("consequence_ceiling") != "informational" + or "_mcp_content" in value + or len(content) != 2 + or content[0].get("type") != "text" + or content[1].get("type") != "image" + or content[1].get("mimeType") != "image/png" + or not isinstance(content[1].get("data"), str) + or not isinstance(value.get("delegated_to"), list) + or not isinstance(value.get("non_claims"), list) + ): + raise AcceptanceError("advanced graph assurance envelope is invalid") + try: + image = base64.b64decode(content[1]["data"], validate=True) + except (ValueError, binascii.Error) as error: + raise AcceptanceError("advanced graph image is not base64") from error + if not image.startswith(b"\x89PNG\r\n\x1a\n"): + raise AcceptanceError("advanced graph image is not PNG") + return value + + +def _validate_hellgate_payload(response: object) -> dict[str, Any]: + value = tool_payload(response) + fields = value.get("fields") + identities = value.get("identities") + trial = fields.get("trial_diagnostics") if isinstance(fields, dict) else None + ground = fields.get("ground_state_transfer") if isinstance(fields, dict) else None + required_identities = { + "jackal_advanced_sha256", + "hellgate_checker_sha256", + "hellgate_certificate_file_sha256", + } + if ( + value.get("status") != "bounded" + or value.get("lane") != "nonlinear-barta-exact-rational-v1" + or value.get("formal") is not False + or value.get("checker_verdict") != "ACCEPT" + or not isinstance(fields, dict) + or not isinstance(fields.get("eigenvalue_interval"), list) + or len(fields["eigenvalue_interval"]) != 2 + or not isinstance(fields.get("eigenvalue_decimal_interval"), list) + or len(fields["eigenvalue_decimal_interval"]) != 2 + or not isinstance(fields.get("interval_width"), str) + or not isinstance(trial, dict) + or trial.get("schema") != "jackal-hellgate-trial-diagnostics-v1" + or trial.get("status") != "bounded" + or trial.get("subject") != "normalized-certificate-trial-phi" + or not isinstance(trial.get("non_claims"), list) + or not any( + isinstance(item, str) and "not the exact ground state u0" in item + for item in trial["non_claims"] + ) + or not isinstance(ground, dict) + or ground.get("schema") != "jackal-hellgate-ground-transfer-v1" + or ground.get("status") != "bounded" + or ground.get("subject") != "positive-normalized-ground-state-u0" + or ground.get("method") != "lambda-strong-convexity-density-transfer-v1" + or not isinstance(ground.get("non_claims"), list) + or not any( + isinstance(item, str) and "does not enclose polynomial moments" in item + for item in ground["non_claims"] + ) + or not isinstance(identities, dict) + or not required_identities.issubset(identities) + or any( + not isinstance(identities[key], str) + or re.fullmatch(r"[0-9a-f]{64}", identities[key]) is None + for key in required_identities + ) + or not isinstance(value.get("theorem"), dict) + or not isinstance(value.get("assumptions"), list) + or not isinstance(value.get("non_claims"), list) + or not any( + isinstance(item, str) and "not formal-bounded" in item + for item in value["non_claims"] + ) + ): + raise AcceptanceError("HELLGATE certificate assurance envelope is invalid") + return value + + +def _validate_stem_payload( + response: object, *, status: str, consequence_ceiling: str = "informational", +) -> dict[str, Any]: + value = tool_payload(response) + if ( + value.get("status") != status + or value.get("formal") is not False + or value.get("consequence_ceiling") != consequence_ceiling + or not isinstance(value.get("lane"), str) + or not isinstance(value.get("parsed"), dict) + or not isinstance(value.get("fields"), dict) + or not isinstance(value.get("field_status"), dict) + or not isinstance(value.get("delegated_to"), list) + or not isinstance(value.get("non_claims"), list) + or re.fullmatch( + r"[0-9a-f]{64}", + value.get("identities", {}).get("jackal_stem_sha256", ""), + ) is None + ): + raise AcceptanceError("STEM assurance envelope is invalid") + return value + + +def _validate_linked_workspace_payload(response: object) -> dict[str, Any]: + value, content = _tool_result(response) + if ( + value.get("status") != "checked" + or value.get("formal") is not False + or value.get("consequence_ceiling") != "informational" + or "_mcp_content" in value + or len(content) != 2 + or content[0].get("type") != "text" + or not isinstance(content[0].get("text"), str) + or content[1].get("type") != "resource" + or not isinstance(content[1].get("resource"), dict) + or not isinstance(value.get("delegated_to"), list) + or not isinstance(value.get("non_claims"), list) + or re.fullmatch( + r"[0-9a-f]{64}", + value.get("identities", {}).get("jackal_stem_sha256", ""), + ) is None + ): + raise AcceptanceError("linked workspace assurance envelope is invalid") + resource = content[1]["resource"] + text = resource.get("text") + uri = resource.get("uri") + if ( + set(resource) != {"uri", "mimeType", "text"} + or resource.get("mimeType") != "text/html" + or not isinstance(text, str) + or not text.startswith("") + or not isinstance(uri, str) + or uri != "ui://jackal/linked-workspace/" + hashlib.sha256( + text.encode("utf-8") + ).hexdigest() + or value.get("fields", {}).get("resource_uri") != uri + or "Pixels are not proof" not in text + ): + raise AcceptanceError("linked workspace resource binding is invalid") + return value + + def run_acceptance( *, client: Any, runtime_document: dict[str, Any], direct_call: Callable[[str, dict[str, Any]], dict[str, Any]], + formal_identities: Mapping[str, str], ) -> dict[str, Any]: + expected_formal_identities = _validated_formal_identities(formal_identities) initialize = client.request( "initialize-1", "initialize", { @@ -1636,6 +1912,7 @@ def run_acceptance( formal = validate_formal_int_cert( formal_response, direct_call("jackal_integrate_bound_cert", copy.deepcopy(FORMAL_ARGUMENTS)), + expected_formal_identities, ) refused_response = client.request( @@ -1651,6 +1928,366 @@ def run_acceptance( ), ) + measurement_calls = ( + ( + "jackal_convert", + {"value": "1", "from_unit": "mi", "to_unit": "km"}, + "exact", + ), + ( + "jackal_rate_apply", + { + "value": "100", "rate": "3/2", "rate_source": "acceptance fixture", + "rate_asof": "2026-08-27", "from_label": "a", "to_label": "b", + }, + "exact-given", + ), + ("jackal_percent", {"op": "change", "a": "200", "b": "250"}, "exact"), + ( + "jackal_date_delta", + {"op": "diff", "start": "2026-01-01", "end": "2026-08-27"}, + "exact-given", + ), + ( + "jackal_compare", + {"a_value": "1", "a_unit": "mi", "b_value": "1", "b_unit": "km"}, + "exact", + ), + ) + measurement_results: dict[str, dict[str, Any]] = {} + for name, arguments, expected_status in measurement_calls: + measurement_results[name] = _validate_measurement_payload( + client.request( + f"measurement-{name}", "tools/call", + {"name": name, "arguments": copy.deepcopy(arguments)}, + ), + status=expected_status, + ) + + stat = _validate_measurement_payload( + client.request( + "measurement-stat", "tools/call", + { + "name": "jackal_stat", + "arguments": {"sample": [0, 4, 6, 2], "include_stddev": True}, + }, + ), + status="exact", + ) + variance = direct_call( + "jackal_exact", + {"expression": "((0-3)^2+(4-3)^2+(6-3)^2+(2-3)^2)/4"}, + ).get("fields", {}).get("exact") + sqrt_traces = [ + item for item in stat.get("delegated_to", []) + if isinstance(item, dict) and item.get("tool") == "jackal_sqrt_rat_bound" + ] + if ( + not isinstance(variance, str) + or stat.get("fields", {}).get("population_variance") != variance + or stat.get("fields", {}).get("field_status", {}).get( + "population_stddev_enclosure" + ) != "formal-bounded" + or not sqrt_traces + or sqrt_traces[-1].get("parsed") + != f"sqrt(x) on [{variance},{variance}]" + or "/1" in sqrt_traces[-1].get("parsed", "") + ): + raise AcceptanceError("integer-variance measurement regression returned") + + scan_text = "Bounds: 10^-12, 2e-12, and 1×10⁻¹²." + scan = _validate_measurement_payload( + client.request( + "measurement-scan", "tools/call", + {"name": "jackal_scan", "arguments": {"text": scan_text}}, + ), + status="checked", + delegated=False, + ) + if [item.get("text") for item in scan.get("fields", {}).get("numerals", [])] != [ + "10^-12", "2e-12", "1×10⁻¹²" + ]: + raise AcceptanceError("scientific notation was split by the lexical scanner") + + measurement_refusal = _validate_measurement_refusal( + client.request( + "measurement-refusal", "tools/call", + { + "name": "jackal_rate_apply", + "arguments": {"value": "1", "rate": "2"}, + }, + ), + reason="undeclared-datum", + ) + + cas_direct = direct_call("jackal_exact", copy.deepcopy(EXACT_ARGUMENTS)) + cas = _validate_cas_payload( + client.request( + "advanced-cas", "tools/call", + { + "name": "jackal_cas", + "arguments": { + "operation": "exact", + "arguments": copy.deepcopy(EXACT_ARGUMENTS), + }, + }, + ), + cas_direct, + ) + graph = _validate_graph_payload( + client.request( + "advanced-graph", "tools/call", + { + "name": "jackal_graph", + "arguments": { + "expression": "x^2-1", + "x_min": "-2", + "x_max": "2", + "samples": "17", + }, + }, + ) + ) + hellgate = _validate_hellgate_payload( + client.request( + "advanced-hellgate", "tools/call", + { + "name": "jackal_hellgate_ground_state", + "arguments": {"problem_id": "hellgate-v1"}, + }, + ) + ) + + matrix = _validate_stem_payload( + client.request( + "stem-matrix", + "tools/call", + { + "name": "jackal_matrix", + "arguments": { + "operation": "determinant", + "matrix": [["1", "2"], ["3", "4"]], + }, + }, + ), + status="exact", + ) + if matrix.get("field_status", {}).get("determinant") != "exact": + raise AcceptanceError("matrix exact-field status is missing") + matrix_branch_arguments = ( + {"operation": "add", "matrix": [["1", "2"], ["3", "4"]], "second_matrix": [["5", "6"], ["7", "8"]]}, + {"operation": "multiply", "matrix": [["1", "2"], ["3", "4"]], "second_matrix": [["5", "6"], ["7", "8"]]}, + {"operation": "transpose", "matrix": [["1", "2", "3"], ["4", "5", "6"]]}, + {"operation": "rref", "matrix": [["1", "2"], ["2", "4"]]}, + {"operation": "inverse", "matrix": [["1", "2"], ["3", "5"]]}, + {"operation": "solve", "matrix": [["1", "0"], ["0", "1"]], "vector": ["7", "9"]}, + ) + for index, arguments in enumerate(matrix_branch_arguments): + _validate_stem_payload( + client.request( + f"stem-matrix-branch-{index}", + "tools/call", + {"name": "jackal_matrix", "arguments": copy.deepcopy(arguments)}, + ), + status="exact", + ) + + regression = _validate_stem_payload( + client.request( + "stem-regression", + "tools/call", + { + "name": "jackal_regression", + "arguments": { + "model": "polynomial_ols", + "degree": "1", + "x": ["0", "1", "2"], + "y": ["1", "3", "5"], + }, + }, + ), + status="model-based", + ) + if regression.get("field_status", {}).get("coefficients_ascending") != "exact": + raise AcceptanceError("regression exact-field status is missing") + + probability = _validate_stem_payload( + client.request( + "stem-probability", + "tools/call", + { + "name": "jackal_probability", + "arguments": { + "operation": "binomial_cdf", + "n": "3", + "k": "1", + "p": "1/2", + }, + }, + ), + status="model-based", + ) + if probability.get("field_status", {}).get("probability") != "exact": + raise AcceptanceError("probability exact-field status is missing") + for index, arguments in enumerate( + ( + {"operation": "binomial_pmf", "n": "3", "k": "2", "p": "1/2"}, + {"operation": "normal_cdf", "z": "0", "tail_cutoff": "6", "tolerance": "1e-8"}, + ) + ): + _validate_stem_payload( + client.request( + f"stem-probability-branch-{index}", + "tools/call", + {"name": "jackal_probability", "arguments": copy.deepcopy(arguments)}, + ), + status="model-based", + ) + + hypothesis = _validate_stem_payload( + client.request( + "stem-hypothesis", + "tools/call", + { + "name": "jackal_hypothesis", + "arguments": { + "operation": "exact_binomial_tail", + "alternative": "greater", + "n": "3", + "k": "2", + "p0": "1/2", + }, + }, + ), + status="model-based", + consequence_ceiling="advisory", + ) + if hypothesis.get("field_status", {}).get("p_value") != "exact": + raise AcceptanceError("hypothesis exact-field status is missing") + for alternative in ("less", "greater", "two_sided"): + _validate_stem_payload( + client.request( + f"stem-hypothesis-{alternative}", + "tools/call", + { + "name": "jackal_hypothesis", + "arguments": { + "operation": "one_sample_z", + "alternative": alternative, + "sample_mean": "1", + "null_mean": "1", + "population_sd": "2", + "n": "4", + "tail_cutoff": "6", + "tolerance": "1e-8", + }, + }, + ), + status="model-based", + consequence_ceiling="advisory", + ) + + sensor = _validate_stem_payload( + client.request( + "stem-sensor", + "tools/call", + { + "name": "jackal_sensor", + "arguments": { + "operation": "ingest_batch", + "sensor_id": "acceptance-imu", + "channel": "accel-x", + "quantity": "acceleration", + "unit": "m/s2", + "samples": ["1", "2", "3"], + "source": "acceptance supplied fixture", + "observed_at": "2026-08-28T00:00:00Z", + }, + }, + ), + status="exact-given", + ) + if ( + sensor.get("given", {}).get("input_provenance") != "supplied" + or sensor.get("field_status", {}).get("population_stddev_enclosure") + != "formal-bounded" + ): + raise AcceptanceError("sensor provenance or formal scalar field is invalid") + _validate_stem_payload( + client.request( + "stem-sensor-calibration", + "tools/call", + { + "name": "jackal_sensor", + "arguments": { + "operation": "linear_calibration", + "sensor_id": "acceptance-imu", + "channel": "accel-x", + "quantity": "acceleration", + "unit": "m/s2", + "samples": ["1", "2", "3"], + "source": "acceptance supplied fixture", + "observed_at": "2026-08-28T00:00:00Z", + "scale": "2", + "offset": "1", + "calibration_source": "acceptance calibration fixture", + "calibration_as_of": "2026-08-28", + }, + }, + ), + status="exact-given", + ) + + aerospace = _validate_stem_payload( + client.request( + "stem-aerospace", + "tools/call", + { + "name": "jackal_aerospace", + "arguments": { + "operation": "vis_viva", + "parameters": {"mu": "10", "radius": "2", "semi_major_axis": "3"}, + }, + }, + ), + status="model-based", + consequence_ceiling="advisory", + ) + if aerospace.get("field_status", {}).get("speed_enclosure") != "formal-bounded": + raise AcceptanceError("aerospace formal scalar field is missing") + aerospace_branch_arguments = ( + {"operation": "circular_orbit", "parameters": {"mu": "10", "radius": "2"}}, + {"operation": "rocket_equation", "parameters": {"exhaust_velocity": "3", "initial_mass": "5", "final_mass": "2"}}, + {"operation": "hohmann_transfer", "parameters": {"mu": "10", "r1": "2", "r2": "3"}}, + {"operation": "plane_change", "parameters": {"velocity": "7", "angle_degrees": "30"}}, + ) + for index, arguments in enumerate(aerospace_branch_arguments): + _validate_stem_payload( + client.request( + f"stem-aerospace-branch-{index}", + "tools/call", + {"name": "jackal_aerospace", "arguments": copy.deepcopy(arguments)}, + ), + status="model-based", + consequence_ceiling="advisory", + ) + + workspace = _validate_linked_workspace_payload( + client.request( + "stem-workspace", + "tools/call", + { + "name": "jackal_linked_workspace", + "arguments": { + "expression": "x^2-1", + "x_min": "-2", + "x_max": "2", + "samples": "17", + }, + }, + ) + ) + claim_response = client.request( "claim-1", "tools/call", {"name": "jackal_claim", "arguments": {"request": copy.deepcopy(CLAIM_REQUEST)}}, @@ -1667,7 +2304,7 @@ def run_acceptance( "receipt-verify-1", "tools/call", {"name": "jackal_verify_receipt", "arguments": receipt_verification_arguments(receipt)}, - ), receipt) + ), receipt, expected_formal_identities) return { "discovered_tool_count": len(discovered), @@ -1675,6 +2312,26 @@ def run_acceptance( "exact": exact["status"], "formal": formal["status"], "unsupported_formal": refused["reason"], + "measurement": { + **{name: result["status"] for name, result in measurement_results.items()}, + "jackal_stat": stat["status"], + "jackal_scan": scan["status"], + "refusal": measurement_refusal["reason"], + }, + "advanced": { + "cas": cas["status"], + "graph": graph["status"], + "hellgate": hellgate["status"], + }, + "stem": { + "matrix": matrix["status"], + "regression": regression["status"], + "probability": probability["status"], + "hypothesis": hypothesis["status"], + "sensor": sensor["status"], + "aerospace": aerospace["status"], + "linked_workspace": workspace["status"], + }, "claim_bundle": bundle_verified["status"], "formal_receipt": receipt_verified["status"], }, @@ -1760,7 +2417,11 @@ def request( if response.get("jsonrpc") != "2.0" or response.get("id") != request_id: raise AcceptanceError("MCP response correlation failed") if "error" in response: - raise AcceptanceError("MCP request returned a protocol error") + error = response.get("error") + code = error.get("code") if isinstance(error, dict) else None + raise AcceptanceError( + f"MCP request {request_id!r} returned protocol error code {code!r}" + ) return response def notification(self, method: str, params: dict[str, Any]) -> None: @@ -1870,6 +2531,62 @@ def load_runtime_document(runtime_root: Path | str) -> dict[str, Any]: return document +def load_runtime_formal_identities(runtime_root: Path | str) -> dict[str, str]: + """Load int-cert expectations from the independently package-bound manifest.""" + runtime = Path(runtime_root) + if not runtime.is_absolute(): + raise AcceptanceError("formal identity source requires an absolute runtime root") + try: + release_pins = effective_runtime_pins() + expected_tree = release_pins["sha256sums_sha256"] + if not isinstance(expected_tree, str): + raise AcceptanceError("runtime tree pin is not a digest") + records = provisioner.verify_sha256sums( + runtime, expected_manifest_sha256=expected_tree, + ) + expected_manifest = records.get("MANIFEST.sha256") + if not isinstance(expected_manifest, str): + raise AcceptanceError("runtime package omitted its formal identity manifest") + raw = identity._read_regular_file_nofollow( + runtime / "MANIFEST.sha256", "runtime formal identity manifest", + byte_limit=provisioner.MAX_RUNTIME_MANIFEST_BYTES, + ) + except (identity.ManifestError, OSError, KeyError, + provisioner.ProvisionError) as error: + raise AcceptanceError("runtime formal identity manifest is untrusted") from error + if not secrets.compare_digest(hashlib.sha256(raw).hexdigest(), expected_manifest): + raise AcceptanceError("runtime formal identity manifest changed after validation") + if not raw or not raw.endswith(b"\n"): + raise AcceptanceError("runtime formal identity manifest is not canonical") + try: + lines = raw.decode("utf-8").splitlines() + except UnicodeDecodeError as error: + raise AcceptanceError("runtime formal identity manifest is not UTF-8") from error + + rows: dict[str, list[str]] = {} + for line in lines: + if line.startswith("#"): + continue + parts = line.split(" ") + if not parts or any(not part for part in parts) \ + or re.fullmatch(r"[a-z0-9_]+", parts[0], re.ASCII) is None: + raise AcceptanceError("runtime formal identity manifest row is malformed") + if parts[0] in rows: + raise AcceptanceError("runtime formal identity manifest has a duplicate key") + rows[parts[0]] = parts + + selected: dict[str, str] = {} + for row_name, (identity_name, expected_fields) in \ + FORMAL_IDENTITY_MANIFEST_ROWS.items(): + parts = rows.get(row_name) + if parts is None or len(parts) != expected_fields \ + or re.fullmatch(r"[0-9a-f]{64}", parts[-1], re.ASCII) is None: + raise AcceptanceError("runtime formal identity manifest omitted a pinned row") + selected[identity_name] = parts[-1] + selected["evaluator_sha256"] = selected["producer_sha256"] + return _validated_formal_identities(selected) + + def runtime_acceptance_environment( runtime_root: Path | str, caller_environment: Mapping[str, str] | None = None, @@ -1908,14 +2625,29 @@ def direct_backend_call( return value +def effective_runtime_pins() -> dict[str, object]: + try: + pins = provisioner.effective_release_pins() + except (KeyError, TypeError, provisioner.ProvisionError) as error: + raise AcceptanceError("host-effective runtime pins are unavailable") from error + if not isinstance(pins, dict) or any( + not isinstance(pins.get(key), str) + or re.fullmatch(r"[0-9a-f]{64}", pins[key], re.ASCII) is None + for key in ("package_sha256", "sha256sums_sha256") + ): + raise AcceptanceError("host-effective runtime digest pin is invalid") + return dict(pins) + + def verify_runtime(runtime_root: Path | str) -> None: try: + release_pins = effective_runtime_pins() provisioner.validate_runtime( Path(runtime_root), timeout=provisioner.SELFTEST_TIMEOUT, output_limit=provisioner.SELFTEST_OUTPUT_LIMIT, - expected_tree_sha256=provisioner.SHA256SUMS_SHA256, + expected_tree_sha256=release_pins["sha256sums_sha256"], ) - except provisioner.ProvisionError as error: + except (KeyError, TypeError, provisioner.ProvisionError) as error: raise AcceptanceError("pinned runtime validation refused") from error @@ -1935,6 +2667,9 @@ def dry_run_document( "mcp_tools": [ "jackal_exact", "jackal_integrate_bound_cert", "jackal_claim", "jackal_verify_bundle", "jackal_verify_receipt", + *MEASUREMENT_TOOLS, + *ADVANCED_TOOLS, + *STEM_TOOLS, ], "caller_pins": { "claim_release_epoch": CLAIM_RELEASE_EPOCH, @@ -1984,6 +2719,7 @@ def _live(runtime_root: Path, codex_binary: Path) -> dict[str, Any]: source_aggregate = verify_wrapper(PLUGIN_ROOT) verify_runtime(runtime_root) runtime_document = load_runtime_document(runtime_root) + formal_identities = load_runtime_formal_identities(runtime_root) with tempfile.TemporaryDirectory( prefix="jackel-codex-live-", dir=_isolated_codex_temp_parent() ) as directory: @@ -2000,15 +2736,17 @@ def _live(runtime_root: Path, codex_binary: Path) -> dict[str, Any]: with installed_mcp_client(installed, environment) as client: report = run_acceptance( client=client, runtime_document=runtime_document, + formal_identities=formal_identities, direct_call=lambda tool, arguments: direct_backend_call( runtime_root, tool, arguments, environment=environment ), ) + runtime_pins = effective_runtime_pins() return { "status": "accepted", "wrapper_aggregate_sha256": source_aggregate, - "runtime_package_sha256": provisioner.PACKAGE_SHA256, - "runtime_tree_sha256": provisioner.SHA256SUMS_SHA256, + "runtime_package_sha256": runtime_pins["package_sha256"], + "runtime_tree_sha256": runtime_pins["sha256sums_sha256"], **report, } diff --git a/tests/codex_plugin/test_advanced.py b/tests/codex_plugin/test_advanced.py new file mode 100644 index 0000000..ab849a6 --- /dev/null +++ b/tests/codex_plugin/test_advanced.py @@ -0,0 +1,250 @@ +import base64 +import copy +import struct +import unittest +from fractions import Fraction + +from plugins.jackel.mcp import advanced +from plugins.jackel.mcp import server as adapter + + +FIXTURE_IDENTITY = "a" * 64 + + +class AdvancedSurfaceTests(unittest.TestCase): + def test_definitions_form_one_strict_identity_pinned_surface(self): + definitions = adapter.build_advanced_tool_definitions(advanced) + + self.assertEqual( + {definition["name"] for definition in definitions}, + adapter.ADVANCED_TOOL_NAMES, + ) + self.assertEqual(len(definitions), adapter.EXPECTED_ADVANCED_TOOL_COUNT) + for definition in definitions: + with self.subTest(tool=definition["name"]): + self.assertIs(definition["inputSchema"]["additionalProperties"], False) + self.assertEqual( + definition["annotations"], + { + "readOnlyHint": True, + "destructiveHint": False, + "idempotentHint": True, + "openWorldHint": False, + }, + ) + + def test_definition_tampering_refuses_before_merge(self): + original = advanced.tool_definitions + definitions = original() + definitions[0] = copy.deepcopy(definitions[0]) + definitions[0]["name"] = "jackal_forged" + advanced.tool_definitions = lambda: definitions + try: + with self.assertRaises(adapter.CatalogError): + adapter.build_advanced_tool_definitions(advanced) + finally: + advanced.tool_definitions = original + + def test_cas_preserves_the_delegated_status_and_body(self): + delegated = { + "status": "exact", + "formal": False, + "fields": {"parsed": "1/3+1/3", "exact": "2/3"}, + "non_claims": ["fixture residual"], + } + calls = [] + + def kernel_call(name, arguments): + calls.append((name, copy.deepcopy(arguments))) + return copy.deepcopy(delegated) + + body = advanced.dispatch_integrated( + "jackal_cas", + {"operation": "exact", "arguments": {"expression": "1/3+1/3"}}, + kernel_call, + FIXTURE_IDENTITY, + ) + + self.assertEqual(body["status"], "exact") + self.assertEqual(body["result"], delegated) + self.assertEqual( + calls, + [("jackal_exact", {"expression": "1/3+1/3"})], + ) + self.assertIn("adds no assurance", body["non_claims"][0]) + + def test_cas_refusal_is_not_routed_to_a_weaker_lane(self): + def kernel_call(name, arguments): + return { + "status": "refused", + "reason": "fixture-refusal", + "detail": "unsupported fixture", + } + + body = advanced.dispatch_integrated( + "jackal_cas", + {"operation": "exact", "arguments": {"expression": "sqrt(2)"}}, + kernel_call, + FIXTURE_IDENTITY, + ) + + self.assertEqual(body["status"], "refused") + self.assertEqual(body["reason"], "kernel-refused:fixture-refusal") + self.assertIn("no weaker lane", body["non_claims"][0].lower()) + + def test_graph_delegates_coordinates_and_values_and_emits_png(self): + coordinate_index = 0 + calls = [] + + def kernel_call(name, arguments): + nonlocal coordinate_index + calls.append((name, copy.deepcopy(arguments))) + if name == "jackal_exact": + coordinate = Fraction(-1) + Fraction(coordinate_index, 8) + coordinate_index += 1 + return { + "status": "exact", + "fields": { + "parsed": arguments["expression"], + "exact": str(coordinate), + }, + } + if name == "jackal_evaluate": + return {"status": "estimated", "engine_output": "0"} + self.fail(f"unexpected kernel call: {name}") + + body = advanced.dispatch_integrated( + "jackal_graph", + {"expression": "x^2", "x_min": "-1", "x_max": "1", "samples": "17"}, + kernel_call, + FIXTURE_IDENTITY, + ) + + self.assertEqual(body["status"], "estimated") + self.assertIs(body["formal"], False) + self.assertEqual(body["fields"]["finite_sample_count"], 17) + self.assertEqual(len([name for name, unused in calls if name == "jackal_exact"]), 17) + self.assertEqual(len([name for name, unused in calls if name == "jackal_evaluate"]), 17) + image = body["_mcp_content"][1] + self.assertEqual(image["mimeType"], "image/png") + png = base64.b64decode(image["data"], validate=True) + self.assertTrue(png.startswith(b"\x89PNG\r\n\x1a\n")) + self.assertEqual( + struct.unpack(">II", png[16:24]), + (advanced.GRAPH_WIDTH, advanced.GRAPH_HEIGHT), + ) + self.assertTrue(any("visualization only" in item for item in body["non_claims"])) + + def test_graph_breaks_at_a_refused_sample(self): + coordinate_index = 0 + evaluation_index = 0 + + def kernel_call(name, arguments): + nonlocal coordinate_index, evaluation_index + if name == "jackal_exact": + coordinate = Fraction(-1) + Fraction(coordinate_index, 8) + coordinate_index += 1 + return {"status": "exact", "fields": {"exact": str(coordinate)}} + evaluation_index += 1 + if evaluation_index == 9: + return { + "status": "refused", + "reason": "domain", + "detail": "fixture gap", + } + return {"status": "estimated", "engine_output": str(evaluation_index)} + + body = advanced.dispatch_integrated( + "jackal_graph", + {"expression": "1/x", "x_min": "-1", "x_max": "1", "samples": "17"}, + kernel_call, + FIXTURE_IDENTITY, + ) + + refused = [point for point in body["fields"]["points"] if point["status"] == "refused"] + self.assertEqual(len(refused), 1) + self.assertTrue(any("break" in item for item in body["non_claims"])) + + def test_hellgate_result_requires_startup_configuration_and_exact_problem_id(self): + result = { + "status": "bounded", + "checker_verdict": "ACCEPT", + "formal": False, + "fields": { + "eigenvalue_decimal_interval": ["-5", "-4"], + "trial_diagnostics": { + "schema": "jackal-hellgate-trial-diagnostics-v1", + "status": "bounded", + "subject": "normalized-certificate-trial-phi", + "non_claims": ["not the exact ground state u0"], + }, + "ground_state_transfer": { + "schema": "jackal-hellgate-ground-transfer-v1", + "status": "bounded", + "subject": "positive-normalized-ground-state-u0", + "method": "lambda-strong-convexity-density-transfer-v1", + "non_claims": ["does not enclose polynomial moments"], + }, + }, + } + advanced.configure_hellgate( + result, + advanced_sha256="a" * 64, + checker_sha256="b" * 64, + certificate_sha256="c" * 64, + ) + body = advanced.dispatch_integrated( + "jackal_hellgate_ground_state", + {"problem_id": "hellgate-v1"}, + lambda unused_name, unused_arguments: self.fail("certificate replay delegates nothing"), + FIXTURE_IDENTITY, + ) + self.assertEqual(body["status"], "bounded") + self.assertIs(body["formal"], False) + self.assertEqual(body["identities"]["hellgate_checker_sha256"], "b" * 64) + + refusal = advanced.dispatch_integrated( + "jackal_hellgate_ground_state", + {"problem_id": "different-problem"}, + lambda unused_name, unused_arguments: {}, + FIXTURE_IDENTITY, + ) + self.assertEqual(refusal["status"], "refused") + self.assertEqual(refusal["reason"], "unsupported-problem") + + +class AdvancedMCPContentTests(unittest.TestCase): + def test_reserved_content_is_validated_and_removed_from_structured_result(self): + png = b"\x89PNG\r\n\x1a\nfixture" + backend = { + "status": "estimated", + "_mcp_content": [ + {"type": "text", "text": "fixture graph"}, + { + "type": "image", + "data": base64.b64encode(png).decode("ascii"), + "mimeType": "image/png", + }, + ], + } + + result = adapter.backend_result(backend) + + self.assertNotIn("_mcp_content", result["structuredContent"]) + self.assertEqual(result["content"][0]["text"], "fixture graph") + self.assertEqual(result["content"][1]["mimeType"], "image/png") + self.assertIn("_mcp_content", backend) + + def test_malformed_content_injection_fails_closed(self): + cases = ( + [{"type": "image", "data": "not-base64", "mimeType": "image/png"}], + [{"type": "image", "data": base64.b64encode(b"GIF89a").decode("ascii"), "mimeType": "image/png"}], + [{"type": "resource", "uri": "file:///tmp/forbidden"}], + ) + for content in cases: + with self.subTest(content=content), self.assertRaises(adapter.BackendFailure): + adapter.backend_result({"status": "estimated", "_mcp_content": content}) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/codex_plugin/test_hellgate.py b/tests/codex_plugin/test_hellgate.py new file mode 100644 index 0000000..1a74337 --- /dev/null +++ b/tests/codex_plugin/test_hellgate.py @@ -0,0 +1,237 @@ +import ast +import copy +import hashlib +import json +import unittest +import zlib +from fractions import Fraction +from pathlib import Path + +from plugins.jackel.mcp import hellgate_verify +from plugins.jackel.mcp import server as adapter +from tools import hellgate_trial_oracle + + +REPO_ROOT = Path(__file__).resolve().parents[2] +CERTIFICATE_PATH = ( + REPO_ROOT / "plugins/jackel/mcp/certificates/hellgate_v1.json.zlib" +) +CHECKER_PATH = REPO_ROOT / "plugins/jackel/mcp/hellgate_verify.py" + + +def canonical_bytes(value): + return json.dumps( + value, sort_keys=True, separators=(",", ":"), ensure_ascii=False + ).encode("utf-8") + + +def repin(document): + result = copy.deepcopy(document) + result.pop("certificate_sha256", None) + result["certificate_sha256"] = hashlib.sha256(canonical_bytes(result)).hexdigest() + return canonical_bytes(result) + b"\n" + + +class HellgateCertificateTests(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.compressed = CERTIFICATE_PATH.read_bytes() + cls.raw = adapter._decompress_certificate(cls.compressed) + cls.document = json.loads(cls.raw) + cls.result = hellgate_verify.verify_bytes(cls.raw) + cls.oracle = hellgate_trial_oracle.compute_oracle(cls.document) + + def test_static_certificate_is_accepted_at_the_declared_assurance_boundary(self): + self.assertEqual(self.result["status"], "bounded") + self.assertEqual(self.result["checker_verdict"], "ACCEPT") + self.assertIs(self.result["formal"], False) + self.assertEqual( + self.result["fields"]["eigenvalue_decimal_interval"], + ["-4.615978698574496508", "-4.615978698574496507"], + ) + width = Fraction(self.result["fields"]["interval_width"]) + self.assertLess(width, hellgate_verify.MAX_EIGENVALUE_WIDTH) + self.assertTrue(any("not formal-bounded" in item for item in self.result["non_claims"])) + + def test_trial_diagnostics_are_bounded_and_subject_scoped(self): + trial = self.result["fields"]["trial_diagnostics"] + self.assertEqual(trial["schema"], "jackal-hellgate-trial-diagnostics-v1") + self.assertEqual(trial["status"], "bounded") + self.assertEqual(trial["subject"], "normalized-certificate-trial-phi") + for interval in ( + trial["quartic_norm_interval"], + trial["kinetic_energy_interval"], + trial["energy_functional_interval"], + *trial["moment_intervals"].values(), + ): + self.assertLessEqual(Fraction(interval[0]), Fraction(interval[1])) + for key in ( + "energy_eigenvalue_identity_residual_interval", + "virial_residual_interval", + ): + lower, upper = map(Fraction, trial[key]) + self.assertLessEqual(lower, 0) + self.assertGreaterEqual(upper, 0) + self.assertTrue( + any("not the exact ground state u0" in item for item in trial["non_claims"]) + ) + + def test_untrusted_high_precision_oracle_lands_inside_bounded_replay(self): + self.assertEqual(self.oracle["status"], "unverified-numerical-oracle") + oracle = self.oracle["fields"] + fields = self.result["fields"] + trial = fields["trial_diagnostics"] + + def assert_inside(interval, point): + lower, upper = map(Fraction, interval) + value = Fraction(point) + self.assertLessEqual(lower, value) + self.assertGreaterEqual(upper, value) + + assert_inside(fields["normalization_interval"], oracle["normalization"]) + assert_inside(trial["quartic_norm_interval"], oracle["quartic_norm"]) + for key in ("x2", "x4", "x6"): + assert_inside(trial["moment_intervals"][key], oracle["moments"][key]) + assert_inside(trial["kinetic_energy_interval"], oracle["kinetic_energy"]) + assert_inside( + trial["energy_functional_interval"], oracle["energy_functional"] + ) + assert_inside( + fields["eigenvalue_interval"], oracle["eigenvalue_from_energy"] + ) + assert_inside( + trial["virial_residual_interval"], oracle["virial_residual"] + ) + self.assertTrue( + any( + "not certificate evidence" in item + for item in self.oracle["non_claims"] + ) + ) + + def test_ground_transfer_is_narrow_bounded_and_does_not_launder_moments(self): + fields = self.result["fields"] + trial = fields["trial_diagnostics"] + ground = fields["ground_state_transfer"] + self.assertEqual(ground["schema"], "jackal-hellgate-ground-transfer-v1") + self.assertEqual(ground["status"], "bounded") + self.assertEqual(ground["subject"], "positive-normalized-ground-state-u0") + self.assertEqual(ground["method"], "lambda-strong-convexity-density-transfer-v1") + self.assertLess( + Fraction(ground["density_l2_distance_upper"]), + hellgate_verify.MAX_DENSITY_L2_DISTANCE, + ) + trial_lower, trial_upper = map(Fraction, trial["quartic_norm_interval"]) + ground_lower, ground_upper = map(Fraction, ground["quartic_norm_interval"]) + self.assertLessEqual(ground_lower, trial_lower) + self.assertGreaterEqual(ground_upper, trial_upper) + self.assertNotIn("moment_intervals", ground) + self.assertTrue( + any("does not enclose polynomial moments" in item for item in ground["non_claims"]) + ) + + def test_startup_gate_requires_the_scoped_additive_envelopes(self): + self.assertTrue(adapter._hellgate_result_satisfies_startup_gate(self.result)) + weakened = copy.deepcopy(self.result) + del weakened["fields"]["trial_diagnostics"] + self.assertFalse(adapter._hellgate_result_satisfies_startup_gate(weakened)) + laundered = copy.deepcopy(self.result) + laundered["fields"]["trial_diagnostics"]["subject"] = ( + "positive-normalized-ground-state-u0" + ) + self.assertFalse(adapter._hellgate_result_satisfies_startup_gate(laundered)) + + def test_certificate_asset_remains_byte_pinned(self): + self.assertEqual( + hashlib.sha256(self.compressed).hexdigest(), + "e41ef05cb7ea6aae121a8a60330f52faf58e5827ee39adea3ef298ec4a873a88", + ) + + def test_checker_has_no_numerical_producer_dependency(self): + tree = ast.parse(CHECKER_PATH.read_text(encoding="utf-8")) + imported = { + alias.name.split(".")[0] + for node in ast.walk(tree) + if isinstance(node, (ast.Import, ast.ImportFrom)) + for alias in node.names + } + self.assertTrue({"numpy", "scipy", "mpmath"}.isdisjoint(imported)) + + def test_common_denominator_polynomial_arithmetic_matches_exact_vectors(self): + left = [Fraction(1, 2), Fraction(-2, 3), Fraction(5, 7)] + right = [Fraction(-3, 5), Fraction(4, 9)] + # JACKAL exact vectors, outside the formal certificate chain: + # parsed terms yield -3/10, 28/45, -137/189, 20/63 and + # parsed=-3/10+28/45/2+-137/189/3+20/63/4 yields -857/5670. + self.assertEqual( + hellgate_verify.poly_mul(left, right), + [ + Fraction(-3, 10), + Fraction(28, 45), + Fraction(-137, 189), + Fraction(20, 63), + ], + ) + self.assertEqual( + hellgate_verify.poly_product_integral_unit(left, right), + Fraction(-857, 5670), + ) + + def test_internal_digest_tampering_refuses(self): + document = copy.deepcopy(self.document) + document["center_eigenvalue"] = "0" + raw = canonical_bytes(document) + b"\n" + with self.assertRaises(hellgate_verify.VerificationRefusal) as raised: + hellgate_verify.verify_bytes(raw) + self.assertEqual(raised.exception.reason, "certificate-digest") + + def test_coherently_repinned_problem_tampering_refuses(self): + document = copy.deepcopy(self.document) + document["problem"]["lambda"] = "3/4" + with self.assertRaises(hellgate_verify.VerificationRefusal): + hellgate_verify.verify_bytes(repin(document)) + + def test_coherently_repinned_piece_tampering_refuses(self): + document = copy.deepcopy(self.document) + piece = document["forward_pieces"][1] + piece["coefficients"][0] = str(Fraction(piece["coefficients"][0]) + 1) + with self.assertRaises(hellgate_verify.VerificationRefusal): + hellgate_verify.verify_bytes(repin(document)) + + def test_coherently_repinned_tail_tampering_refuses(self): + document = copy.deepcopy(self.document) + document["tail_coefficients"][-1] = str( + Fraction(document["tail_coefficients"][-1]) + 1 + ) + with self.assertRaises(hellgate_verify.VerificationRefusal): + hellgate_verify.verify_bytes(repin(document)) + + def test_coherently_repinned_nonclaim_weakening_refuses(self): + document = copy.deepcopy(self.document) + document["nonclaims"].pop() + with self.assertRaises(hellgate_verify.VerificationRefusal) as raised: + hellgate_verify.verify_bytes(repin(document)) + self.assertEqual(raised.exception.reason, "certificate-nonclaims") + + def test_coherently_repinned_density_tampering_refuses(self): + document = copy.deepcopy(self.document) + document["forward_pieces"][0]["density_coefficients"][0] = "-1" + with self.assertRaises(hellgate_verify.VerificationRefusal): + hellgate_verify.verify_bytes(repin(document)) + + def test_duplicate_json_key_refuses(self): + raw = b'{"schema":"first","schema":"second"}\n' + with self.assertRaises(hellgate_verify.VerificationRefusal) as raised: + hellgate_verify.verify_bytes(raw) + self.assertEqual(raised.exception.reason, "duplicate-json-key") + + def test_compression_trailing_bytes_refuse(self): + with self.assertRaises(adapter.StartupError): + adapter._decompress_certificate(self.compressed + b"trailing") + + def test_compression_round_trip_is_byte_exact(self): + self.assertEqual(zlib.decompress(self.compressed), self.raw) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/codex_plugin/test_live_acceptance.py b/tests/codex_plugin/test_live_acceptance.py index 4ac043b..92aac08 100644 --- a/tests/codex_plugin/test_live_acceptance.py +++ b/tests/codex_plugin/test_live_acceptance.py @@ -22,6 +22,12 @@ REPOSITORY_ROOT = Path(__file__).resolve().parents[2] RUNTIME_TOOLS = REPOSITORY_ROOT / "plugin" / "hermes" / "tools.json" +TEST_FORMAL_IDENTITIES = { + "evaluator_sha256": "b4240fdac3c77b2abd751595303b2b3a0e4bebd492b2ae57fa5ccf052cd50af4", + "producer_sha256": "b4240fdac3c77b2abd751595303b2b3a0e4bebd492b2ae57fa5ccf052cd50af4", + "checker_sha256": "f2e26f506f921b577fd8609a095b69789b3b76cce65d8c293d1a11f3007a8078", + "plugin_sha256": "6943891086bde13e48dbc9bbde9c8c9fed90d0e78a7d8c29b8be32a92502711a", +} def mcp_response(request_id, payload): @@ -64,10 +70,7 @@ def formal_payload(emitted_at): "sha256": hashlib.sha256(certificate).hexdigest(), }, "identities": { - "evaluator_sha256": live.INT_CERT_PRODUCER_SHA256, - "producer_sha256": live.INT_CERT_PRODUCER_SHA256, - "checker_sha256": live.INT_CERT_CHECKER_SHA256, - "plugin_sha256": live.HERMES_BUNDLE_SHA256, + **TEST_FORMAL_IDENTITIES, }, "theorem": {"id": "int_cert_sound"}, "checker": {"verdict": "ACCEPT"}, @@ -77,19 +80,89 @@ def formal_payload(emitted_at): class IdentityAndInstallPlanTests(unittest.TestCase): - def test_formal_receipt_oracle_matches_current_hermes_bundle_pin(self): - row = next( - ( - line.split() - for line in (REPOSITORY_ROOT / "release/MANIFEST.sha256") - .read_text(encoding="utf-8") - .splitlines() - if line.startswith("plugin_hermes ") - ), - None, + def test_runtime_formal_identities_come_from_package_bound_manifest(self): + manifest = ( + "# fixture runtime manifest\n" + f"plugin_hermes {TEST_FORMAL_IDENTITIES['plugin_sha256']}\n" + "int_cert_producer producer.py " + f"{TEST_FORMAL_IDENTITIES['producer_sha256']}\n" + "int_cert_checker checker " + f"{TEST_FORMAL_IDENTITIES['checker_sha256']}\n" + ).encode("utf-8") + with tempfile.TemporaryDirectory() as directory: + root = Path(directory) + (root / "MANIFEST.sha256").write_bytes(manifest) + with ( + mock.patch.object( + live.provisioner, "effective_release_pins", + return_value={ + "package_sha256": "d" * 64, + "sha256sums_sha256": "a" * 64, + }, + ), + mock.patch.object( + live.provisioner, "verify_sha256sums", + return_value={ + "MANIFEST.sha256": hashlib.sha256(manifest).hexdigest(), + }, + ) as verify, + ): + actual = live.load_runtime_formal_identities(root) + self.assertEqual(actual, TEST_FORMAL_IDENTITIES) + verify.assert_called_once_with( + root, expected_manifest_sha256="a" * 64, ) - self.assertIsNotNone(row, "release manifest has no plugin_hermes row") - self.assertEqual(live.HERMES_BUNDLE_SHA256, row[-1]) + + def test_runtime_formal_identity_manifest_rejects_duplicate_rows(self): + manifest = ( + f"plugin_hermes {TEST_FORMAL_IDENTITIES['plugin_sha256']}\n" + f"plugin_hermes {TEST_FORMAL_IDENTITIES['plugin_sha256']}\n" + "int_cert_producer producer.py " + f"{TEST_FORMAL_IDENTITIES['producer_sha256']}\n" + "int_cert_checker checker " + f"{TEST_FORMAL_IDENTITIES['checker_sha256']}\n" + ).encode("utf-8") + with tempfile.TemporaryDirectory() as directory: + root = Path(directory) + (root / "MANIFEST.sha256").write_bytes(manifest) + with ( + mock.patch.object( + live.provisioner, "effective_release_pins", + return_value={ + "package_sha256": "d" * 64, + "sha256sums_sha256": "a" * 64, + }, + ), + mock.patch.object( + live.provisioner, "verify_sha256sums", + return_value={ + "MANIFEST.sha256": hashlib.sha256(manifest).hexdigest(), + }, + ), + ): + with self.assertRaisesRegex(live.AcceptanceError, "duplicate key"): + live.load_runtime_formal_identities(root) + + def test_runtime_formal_identity_manifest_rejects_post_validation_change(self): + manifest = b"plugin_hermes " + b"a" * 64 + b"\n" + with tempfile.TemporaryDirectory() as directory: + root = Path(directory) + (root / "MANIFEST.sha256").write_bytes(manifest) + with ( + mock.patch.object( + live.provisioner, "effective_release_pins", + return_value={ + "package_sha256": "d" * 64, + "sha256sums_sha256": "b" * 64, + }, + ), + mock.patch.object( + live.provisioner, "verify_sha256sums", + return_value={"MANIFEST.sha256": "c" * 64}, + ), + ): + with self.assertRaisesRegex(live.AcceptanceError, "changed after validation"): + live.load_runtime_formal_identities(root) def test_dry_run_lists_each_mcp_tool_once(self): document = live.dry_run_document( @@ -427,7 +500,9 @@ def test_exact_result_requires_strict_direct_parity(self): def test_formal_result_verifies_identities_digests_and_only_normalizes_time(self): mcp = formal_payload(10) direct = formal_payload(11) - live.validate_formal_int_cert(mcp_response("formal", mcp), direct) + live.validate_formal_int_cert( + mcp_response("formal", mcp), direct, TEST_FORMAL_IDENTITIES, + ) tampered = formal_payload(11) tampered["receipt"]["certificate"]["sha256"] = "0" * 64 @@ -435,7 +510,19 @@ def test_formal_result_verifies_identities_digests_and_only_normalizes_time(self tampered["receipt"] ) with self.assertRaisesRegex(live.AcceptanceError, "certificate digest"): - live.validate_formal_int_cert(mcp_response("formal", mcp), tampered) + live.validate_formal_int_cert( + mcp_response("formal", mcp), tampered, TEST_FORMAL_IDENTITIES, + ) + + self_signed = formal_payload(11) + self_signed["receipt"]["identities"]["checker_sha256"] = "d" * 64 + self_signed["receipt"]["receipt_digest_sha256"] = live.receipt_digest( + self_signed["receipt"] + ) + with self.assertRaisesRegex(live.AcceptanceError, "identity binding"): + live.validate_formal_int_cert( + mcp_response("formal", mcp), self_signed, TEST_FORMAL_IDENTITIES, + ) def test_named_formal_refusal_has_no_downgrade_shape(self): refused = { @@ -1756,16 +1843,24 @@ def request(self, request_id, method, params): "result": { "protocolVersion": live.MCP_PROTOCOL_VERSION, "serverInfo": {"name": "jackel-codex", "version": "0.1.0"}, - "capabilities": {"tools": {"listChanged": False}}, + "capabilities": { + "tools": {"listChanged": False}, + "resources": {"subscribe": False, "listChanged": False}, + }, }, } if method == "tools/list": return { "jsonrpc": "2.0", "id": request_id, - "result": {"tools": [ - {"name": record["name"]} - for record in self.runtime_document["tools"] - ]}, + "result": { + "tools": [ + {"name": record["name"]} + for record in self.runtime_document["tools"] + ] + + [{"name": name} for name in live.MEASUREMENT_TOOLS] + + [{"name": name} for name in live.ADVANCED_TOOLS] + + [{"name": name} for name in live.STEM_TOOLS] + }, } self.assert_tools_call(method) name = params["name"] @@ -1783,6 +1878,211 @@ def request(self, request_id, method, params): "status": "refused", "reason": "producer-refused", "detail": "outside fragment", } + elif name in live.MEASUREMENT_TOOLS: + measurement_statuses = { + "jackal_convert": "exact", + "jackal_rate_apply": "exact-given", + "jackal_percent": "exact", + "jackal_date_delta": "exact-given", + "jackal_stat": "exact", + "jackal_compare": "exact", + "jackal_scan": "checked", + } + if name == "jackal_rate_apply" and "rate_source" not in params["arguments"]: + payload = { + "status": "refused", + "reason": "undeclared-datum", + "detail": "fixture missing provenance", + "consequence_ceiling": "informational", + "non_claims": ["fixture refusal"], + } + else: + status = measurement_statuses[name] + fields = {"fixture": name} + trace = [{"tool": "jackal_exact", "status": "exact"}] + if name == "jackal_stat": + fields = { + "population_variance": "5", + "field_status": { + "population_stddev_enclosure": "formal-bounded", + }, + } + trace.append({ + "tool": "jackal_sqrt_rat_bound", + "status": "formal-bounded", + "parsed": "sqrt(x) on [5,5]", + }) + elif name == "jackal_scan": + fields = { + "numerals": [ + {"text": "10^-12"}, + {"text": "2e-12"}, + {"text": "1×10⁻¹²"}, + ], + } + trace = [] + payload = { + "status": status, + "lane": "fixture-measurement", + "parsed": name, + "fields": fields, + "delegated_to": trace, + "consequence_ceiling": "informational", + "non_claims": ["fixture non-claim"], + "identities": {"jackal_measurement_sha256": "c" * 64}, + } + if status == "exact-given": + payload["given"] = { + "source": "fixture source", + "as_of": "fixture as-of", + } + elif name == "jackal_cas": + delegated = { + "status": "exact", + "lane": "rat", + "formal": False, + "fields": {"exact": "3/10"}, + } + payload = { + "status": "exact", + "lane": "cas-route", + "formal": False, + "parsed": { + "operation": "exact", + "delegated_tool": "jackal_exact", + }, + "result": delegated, + "delegated_to": [ + {"tool": "jackal_exact", "status": "exact"} + ], + "identities": {"jackal_advanced_sha256": "d" * 64}, + "non_claims": ["fixture router adds no assurance"], + } + elif name == "jackal_graph": + payload = { + "status": "estimated", + "lane": "graph-delegated-f64-v1", + "formal": False, + "consequence_ceiling": "informational", + "fields": {"finite_sample_count": 17}, + "delegated_to": [ + {"tool": "jackal_exact", "status": "exact"}, + {"tool": "jackal_evaluate", "status": "estimated"}, + ], + "identities": {"jackal_advanced_sha256": "d" * 64}, + "non_claims": ["fixture graph visualization only"], + } + png = b"\x89PNG\r\n\x1a\nfixture" + return { + "jsonrpc": "2.0", + "id": request_id, + "result": { + "content": [ + {"type": "text", "text": "fixture graph"}, + { + "type": "image", + "data": base64.b64encode(png).decode("ascii"), + "mimeType": "image/png", + }, + ], + "structuredContent": copy.deepcopy(payload), + }, + } + elif name == "jackal_hellgate_ground_state": + payload = { + "status": "bounded", + "lane": "nonlinear-barta-exact-rational-v1", + "formal": False, + "checker_verdict": "ACCEPT", + "fields": { + "eigenvalue_interval": ["-5", "-4"], + "eigenvalue_decimal_interval": ["-5", "-4"], + "interval_width": "1", + "trial_diagnostics": { + "schema": "jackal-hellgate-trial-diagnostics-v1", + "status": "bounded", + "subject": "normalized-certificate-trial-phi", + "non_claims": ["not the exact ground state u0"], + }, + "ground_state_transfer": { + "schema": "jackal-hellgate-ground-transfer-v1", + "status": "bounded", + "subject": "positive-normalized-ground-state-u0", + "method": "lambda-strong-convexity-density-transfer-v1", + "non_claims": ["does not enclose polynomial moments"], + }, + }, + "identities": { + "jackal_advanced_sha256": "d" * 64, + "hellgate_checker_sha256": "e" * 64, + "hellgate_certificate_file_sha256": "f" * 64, + }, + "theorem": {"name": "fixture comparison"}, + "assumptions": ["fixture assumption"], + "non_claims": ["bounded is not formal-bounded"], + } + elif name in live.STEM_TOOLS: + statuses = { + "jackal_matrix": "exact", + "jackal_regression": "model-based", + "jackal_probability": "model-based", + "jackal_hypothesis": "model-based", + "jackal_sensor": "exact-given", + "jackal_aerospace": "model-based", + "jackal_linked_workspace": "checked", + } + field_statuses = { + "jackal_matrix": {"determinant": "exact"}, + "jackal_regression": {"coefficients_ascending": "exact"}, + "jackal_probability": {"probability": "exact"}, + "jackal_hypothesis": {"p_value": "exact"}, + "jackal_sensor": {"population_stddev_enclosure": "formal-bounded"}, + "jackal_aerospace": {"speed_enclosure": "formal-bounded"}, + "jackal_linked_workspace": {"points.y": "estimated"}, + } + payload = { + "status": statuses[name], + "lane": "fixture-stem", + "formal": False, + "consequence_ceiling": ( + "advisory" + if name in {"jackal_hypothesis", "jackal_aerospace"} + else "informational" + ), + "parsed": {"fixture": name}, + "fields": {"fixture": name}, + "field_status": field_statuses[name], + "delegated_to": [{"tool": "jackal_exact", "status": "exact"}], + "identities": {"jackal_stem_sha256": "1" * 64}, + "non_claims": ["fixture STEM non-claim"], + } + if name == "jackal_sensor": + payload["given"] = {"input_provenance": "supplied"} + if name == "jackal_linked_workspace": + resource_text = "Pixels are not proof" + resource_uri = ( + "ui://jackal/linked-workspace/" + + hashlib.sha256(resource_text.encode("utf-8")).hexdigest() + ) + payload["fields"]["resource_uri"] = resource_uri + return { + "jsonrpc": "2.0", + "id": request_id, + "result": { + "content": [ + {"type": "text", "text": "fixture workspace"}, + { + "type": "resource", + "resource": { + "uri": resource_uri, + "mimeType": "text/html", + "text": resource_text, + }, + }, + ], + "structuredContent": copy.deepcopy(payload), + }, + } elif name == "jackal_claim": payload = { "status": "ok", "root": "root-node", @@ -1805,9 +2105,9 @@ def request(self, request_id, method, params): "status": "verified", "verdict": "ACCEPT", "receipt_digest_sha256": receipt["receipt_digest_sha256"], "certificate_sha256": receipt["certificate"]["sha256"], - "checker_sha256": live.INT_CERT_CHECKER_SHA256, - "evaluator_sha256": live.INT_CERT_PRODUCER_SHA256, - "plugin_sha256": live.HERMES_BUNDLE_SHA256, + "checker_sha256": TEST_FORMAL_IDENTITIES["checker_sha256"], + "evaluator_sha256": TEST_FORMAL_IDENTITIES["evaluator_sha256"], + "plugin_sha256": TEST_FORMAL_IDENTITIES["plugin_sha256"], "enclosure": ["0", "1"], } else: @@ -1830,6 +2130,10 @@ def test_live_mcp_and_direct_comparator_share_one_sanitized_environment(self): "PATH": "/fixed/python:/usr/bin:/bin:/usr/sbin:/sbin", "JACKAL_HOME": str(runtime), } + runtime_pins = { + "package_sha256": "e" * 64, + "sha256sums_sha256": "f" * 64, + } client = mock.Mock() client_context = mock.Mock() client_context.__enter__ = mock.Mock(return_value=client) @@ -1841,8 +2145,9 @@ def test_live_mcp_and_direct_comparator_share_one_sanitized_environment(self): ) temporary.__exit__ = mock.Mock(return_value=False) - def acceptance(*, client, runtime_document, direct_call): + def acceptance(*, client, runtime_document, direct_call, formal_identities): self.assertEqual(runtime_document, {"tools": []}) + self.assertEqual(formal_identities, TEST_FORMAL_IDENTITIES) direct_call("jackal_exact", {"expression": "1+1"}) return {"sequence": "accepted"} @@ -1850,6 +2155,13 @@ def acceptance(*, client, runtime_document, direct_call): mock.patch.object(live, "verify_wrapper", return_value="a" * 64), mock.patch.object(live, "verify_runtime"), mock.patch.object(live, "load_runtime_document", return_value={"tools": []}), + mock.patch.object( + live, "load_runtime_formal_identities", + return_value=TEST_FORMAL_IDENTITIES, + ), + mock.patch.object( + live, "effective_runtime_pins", return_value=runtime_pins, + ), mock.patch.object( live.tempfile, "TemporaryDirectory", return_value=temporary ) as temporary_directory, @@ -1880,6 +2192,8 @@ def acceptance(*, client, runtime_document, direct_call): environment=environment, ) self.assertEqual(report["sequence"], "accepted") + self.assertEqual(report["runtime_package_sha256"], runtime_pins["package_sha256"]) + self.assertEqual(report["runtime_tree_sha256"], runtime_pins["sha256sums_sha256"]) def test_full_strict_sequence_has_no_weaker_fallback(self): runtime_document = json.loads(RUNTIME_TOOLS.read_text(encoding="utf-8")) @@ -1889,9 +2203,15 @@ def test_full_strict_sequence_has_no_weaker_fallback(self): def direct(tool, arguments): direct_calls.append((tool, copy.deepcopy(arguments))) if tool == "jackal_exact": + exact_value = ( + "5" + if arguments["expression"] + == "((0-3)^2+(4-3)^2+(6-3)^2+(2-3)^2)/4" + else "3/10" + ) return { "status": "exact", "lane": "rat", "formal": False, - "fields": {"exact": "3/10"}, + "fields": {"exact": exact_value}, } if arguments["expression"] == "sin(x)": return formal_payload(11) @@ -1903,30 +2223,77 @@ def direct(tool, arguments): report = live.run_acceptance( client=client, runtime_document=runtime_document, direct_call=direct, + formal_identities=TEST_FORMAL_IDENTITIES, ) tool_calls = [name for name, _ in client.calls if not name.startswith("notifications/")] self.assertEqual( tool_calls, [ "jackal_exact", "jackal_integrate_bound_cert", - "jackal_integrate_bound_cert", "jackal_claim", + "jackal_integrate_bound_cert", + "jackal_convert", "jackal_rate_apply", "jackal_percent", + "jackal_date_delta", "jackal_compare", "jackal_stat", + "jackal_scan", "jackal_rate_apply", "jackal_cas", + "jackal_graph", "jackal_hellgate_ground_state", + "jackal_matrix", "jackal_matrix", "jackal_matrix", + "jackal_matrix", "jackal_matrix", "jackal_matrix", + "jackal_matrix", "jackal_regression", + "jackal_probability", "jackal_probability", + "jackal_probability", "jackal_hypothesis", + "jackal_hypothesis", "jackal_hypothesis", + "jackal_hypothesis", "jackal_sensor", "jackal_sensor", + "jackal_aerospace", "jackal_aerospace", "jackal_aerospace", + "jackal_aerospace", "jackal_aerospace", + "jackal_linked_workspace", "jackal_claim", "jackal_verify_bundle", "jackal_verify_receipt", ], ) self.assertNotIn("jackal_integrate_bound", tool_calls) self.assertEqual( [name for name, _ in direct_calls], - ["jackal_exact", "jackal_integrate_bound_cert", "jackal_integrate_bound_cert"], + [ + "jackal_exact", "jackal_integrate_bound_cert", + "jackal_integrate_bound_cert", "jackal_exact", "jackal_exact", + ], ) # Exact against the catalog actually fed in — this test feeds the repo # `plugin/hermes/tools.json`, so retyping its size here would go stale # on every surface addition while checking nothing extra. self.assertEqual(report["discovered_tool_count"], - len(runtime_document["tools"])) - self.assertGreaterEqual(report["discovered_tool_count"], live.MIN_TOOL_COUNT) + len(runtime_document["tools"]) + + len(live.MEASUREMENT_TOOLS) + + len(live.ADVANCED_TOOLS) + + len(live.STEM_TOOLS)) + self.assertGreaterEqual( + len(runtime_document["tools"]), live.MIN_RUNTIME_TOOL_COUNT + ) self.assertEqual(report["gates"], { "exact": "exact", "formal": "formal-bounded", "unsupported_formal": "producer-refused", + "measurement": { + "jackal_convert": "exact", + "jackal_rate_apply": "exact-given", + "jackal_percent": "exact", + "jackal_date_delta": "exact-given", + "jackal_compare": "exact", + "jackal_stat": "exact", + "jackal_scan": "checked", + "refusal": "undeclared-datum", + }, + "advanced": { + "cas": "exact", + "graph": "estimated", + "hellgate": "bounded", + }, + "stem": { + "matrix": "exact", + "regression": "model-based", + "probability": "model-based", + "hypothesis": "model-based", + "sensor": "exact-given", + "aerospace": "model-based", + "linked_workspace": "checked", + }, "claim_bundle": "verified", "formal_receipt": "verified", }) diff --git a/tests/codex_plugin/test_mcp_adapter.py b/tests/codex_plugin/test_mcp_adapter.py index 849448f..92da6f7 100644 --- a/tests/codex_plugin/test_mcp_adapter.py +++ b/tests/codex_plugin/test_mcp_adapter.py @@ -22,6 +22,9 @@ sys.dont_write_bytecode = True from plugins.jackel.mcp import server as adapter +from plugins.jackel.mcp import advanced +from plugins.jackel.mcp import measurement +from plugins.jackel.mcp import stem from plugins.jackel.scripts import provision_runtime as real_provisioner @@ -259,21 +262,42 @@ def setUp(self): import sys import time - if len(sys.argv) != 4 or sys.argv[1] != "call": + stdio_mode = len(sys.argv) == 2 and sys.argv[1] == "stdio" + request_id = None + if stdio_mode: + raw = sys.stdin.buffer.readline() + trailing = sys.stdin.buffer.read() + if not raw or trailing: + raise SystemExit(64) + request = json.loads(raw) + request_id = request.get("id") + name = request.get("method") + arguments = request.get("params") + elif len(sys.argv) == 4 and sys.argv[1] == "call": + name = sys.argv[2] + arguments = json.loads(sys.argv[3]) + else: raise SystemExit(64) - name = sys.argv[2] - arguments = json.loads(sys.argv[3]) allowed = {{"payload", "mode", "pid_file", "release_file"}} if ( + not isinstance(arguments, dict) + or "payload" not in arguments or not isinstance(arguments.get("payload"), dict) or any(key not in allowed for key in arguments) ): - print(json.dumps({{ + refusal = {{ "status": "refused", "reason": "plugin-args-schema", "arguments": arguments, - }}, sort_keys=True), flush=True) + }} + if stdio_mode: + refusal = {{ + "jsonrpc": "2.0", "id": request_id, "result": refusal, + }} + print(json.dumps(refusal, sort_keys=True), flush=True) + raise SystemExit(0) + print(json.dumps(refusal, sort_keys=True), flush=True) raise SystemExit(1) mode = arguments.get("mode", "echo") payload = arguments.get("payload", {{}}) @@ -403,14 +427,20 @@ def exit_on_term(unused_signum, unused_frame): print(json.dumps({{"status": "checked", "blob": "x" * 8192}}), flush=True) raise SystemExit(0) - if mode == "refused": + if mode == "accept-large": + result = {{"status": "checked", "accepted": True}} + elif mode == "refused": result = {{"status": "refused", "reason": "fixture-refusal", "input": payload}} elif mode == "indeterminate": result = {{"status": "indeterminate", "reason": "fixture-indeterminate", "input": payload}} else: result = payload + if stdio_mode: + result = {{"jsonrpc": "2.0", "id": request_id, "result": result}} print(json.dumps(result, ensure_ascii=False, sort_keys=False), flush=True) - if mode in ("refused", "indeterminate", "ok-rc1", "unknown-rc1"): + if stdio_mode and mode == "unknown-rc1": + raise SystemExit(1) + if not stdio_mode and mode in ("refused", "indeterminate", "ok-rc1", "unknown-rc1"): raise SystemExit(1) """ ), @@ -487,8 +517,10 @@ async def test_backend_call_ignores_hostile_caller_path_python3(self): fake_python.chmod(0o755) entry = Path(self.temporary.name) / "legitimate-backend.py" entry.write_text( - "import json\n" - "print(json.dumps({'status': 'checked', 'origin': 'selected-python'}))\n", + "import json, sys\n" + "request = json.loads(sys.stdin.buffer.read())\n" + "print(json.dumps({'jsonrpc': '2.0', 'id': request['id'], " + "'result': {'status': 'checked', 'origin': 'selected-python'}}))\n", encoding="utf-8", ) launcher = Path(self.temporary.name) / "bare-python-launcher" @@ -520,6 +552,35 @@ async def test_backend_call_ignores_hostile_caller_path_python3(self): ) self.assertFalse(attacked.exists()) + async def test_one_request_can_launch_multiple_serial_backend_processes(self): + state = adapter._CallState(request_id="multi-delegation") + first = self.server._invoke_backend_sync( + state, "jackal_echo", {"payload": {"delegation": "first"}}, + ) + second = self.server._invoke_backend_sync( + state, "jackal_echo", {"payload": {"delegation": "second"}}, + ) + + self.assertEqual(first, {"delegation": "first"}) + self.assertEqual(second, {"delegation": "second"}) + self.assertTrue(state.reaped) + self.assertIsNone(state.process) + self.assertIsNone(state.runner) + + async def test_replay_sized_backend_arguments_are_streamed_over_stdin(self): + response = await self.server.handle_message( + self._call( + "large-backend-input", + payload={"receipt": "x" * adapter.MAX_CATALOG_BYTES}, + mode="accept-large", + ) + ) + + self.assertEqual( + response["result"]["structuredContent"], + {"status": "checked", "accepted": True}, + ) + async def test_active_call_flood_refuses_ordinary_busy_and_recovers(self): limited = adapter.MCPServer( runtime_root=self.runtime, @@ -850,7 +911,13 @@ async def test_initialize_ping_notification_and_full_tools_list(self): self.assertEqual(initialized["jsonrpc"], "2.0") self.assertEqual(initialized["id"], "init-1") self.assertEqual(initialized["result"]["protocolVersion"], adapter.LATEST_PROTOCOL_VERSION) - self.assertEqual(initialized["result"]["capabilities"], {"tools": {"listChanged": False}}) + self.assertEqual( + initialized["result"]["capabilities"], + { + "tools": {"listChanged": False}, + "resources": {"subscribe": False, "listChanged": False}, + }, + ) self.assertEqual(initialized["result"]["serverInfo"]["name"], "jackel-codex") self.assertIsNone( @@ -928,8 +995,11 @@ async def test_backend_owns_known_tool_argument_schema_refusals_with_exact_parit arguments, ensure_ascii=False, allow_nan=False, sort_keys=True, separators=(",", ":"), ) - direct_process = await asyncio.to_thread( - subprocess.run, + # Keep this tiny fixture invocation synchronous. The host's + # current asyncio global executor does not reliably shut down, + # and the production adapter intentionally owns its worker + # threads instead of depending on that global executor. + direct_process = subprocess.run( [str(self.launcher), "call", "jackal_echo", compact], cwd=self.runtime, capture_output=True, text=True, check=False, ) @@ -1037,6 +1107,22 @@ async def test_malformed_requests_and_adapter_owned_argument_shape_fail_closed(s self.assertEqual(unterminated["error"]["code"], -32600) self.assertIsNone(unterminated["id"]) + replay_sized = ( + json.dumps( + { + "jsonrpc": "2.0", + "id": 10, + "method": "ping", + "params": {"_meta": {"receipt_fixture": "x" * adapter.MAX_CATALOG_BYTES}}, + }, + separators=(",", ":"), + ).encode("utf-8") + + b"\n" + ) + self.assertLess(len(replay_sized), adapter.MAX_REQUEST_LINE_BYTES) + replay_response = await self.server.handle_line(replay_sized) + self.assertEqual(replay_response["result"], {}) + async def test_deep_json_and_recursion_failure_are_bounded_parse_errors(self): expected_depth_limit = getattr(adapter, "MAX_JSON_DEPTH", 64) nested = ( @@ -1617,7 +1703,7 @@ def mark_reaped(unused_process): with ( mock.patch.object(adapter.subprocess, "Popen", return_value=setup_process), - mock.patch.object(adapter.socket, "socketpair", side_effect=OSError("fixture")), + mock.patch.object(adapter.os, "pipe", side_effect=OSError("fixture")), mock.patch.object( setup_runner, "_terminate_and_reap", @@ -1897,6 +1983,7 @@ def setUp(self): }, default_locator_path=lambda: self.root / "locator.json", validate_host=mock.Mock(return_value=None), + reap_orphaned_runtime_snapshots=mock.Mock(return_value=()), runtime_subprocess_environment=mock.Mock( return_value=real_provisioner.runtime_subprocess_environment({}) ), @@ -1985,6 +2072,7 @@ def test_production_builder_verifies_plugin_and_runtime_with_wrapper_pins(self): plugin_root, plugin_root / "PLUGIN_IDENTITY.sha256" ) self.provisioner.validate_host.assert_called_once_with() + self.provisioner.reap_orphaned_runtime_snapshots.assert_called_once_with() self.provisioner.runtime_subprocess_environment.assert_called_once_with( {"JACKAL_HOME": str(self.runtime)} ) @@ -2010,6 +2098,130 @@ def test_production_builder_verifies_plugin_and_runtime_with_wrapper_pins(self): asyncio.run(server.close()) self.snapshot_owners[0].close.assert_called_once_with() + def test_production_builder_passes_only_an_explicit_private_snapshot_parent(self): + plugin_root = self.root / "private-parent-plugin" + plugin_root.mkdir() + (plugin_root / "PLUGIN_IDENTITY.sha256").write_text("fixture\n") + private_parent = self.root / "private-tmpfs" + + server = adapter.build_production_server( + plugin_root=plugin_root, + environ={"JACKAL_HOME": str(self.runtime)}, + snapshot_parent=private_parent, + provisioner=self.provisioner, + identity_verifier=mock.Mock(return_value=()), + runtime_validator=mock.Mock(return_value={}), + ) + + self.provisioner.create_runtime_snapshot.assert_called_once_with( + self.runtime, + timeout=self.provisioner.SELFTEST_TIMEOUT, + output_limit=self.provisioner.SELFTEST_OUTPUT_LIMIT, + expected_tree_sha256=self.provisioner.SHA256SUMS_SHA256, + temporary_parent=os.fspath(private_parent), + ) + asyncio.run(server.close()) + + def test_production_builder_refuses_orphan_cleanup_failure_before_runtime_copy(self): + plugin_root = self.root / "reaper-failure-plugin" + plugin_root.mkdir() + (plugin_root / "PLUGIN_IDENTITY.sha256").write_text("fixture\n") + self.provisioner.reap_orphaned_runtime_snapshots.side_effect = OSError( + "fixture cleanup failure" + ) + runtime_validator = mock.Mock(return_value={}) + + with self.assertRaisesRegex(adapter.StartupError, "orphaned runtime snapshot"): + adapter.build_production_server( + plugin_root=plugin_root, + environ={"JACKAL_HOME": str(self.runtime)}, + provisioner=self.provisioner, + identity_verifier=mock.Mock(return_value=()), + runtime_validator=runtime_validator, + ) + + runtime_validator.assert_not_called() + self.provisioner.create_runtime_snapshot.assert_not_called() + + def test_linux_namespace_wrapper_execs_mount_and_pid_isolation_after_probe(self): + probe = mock.Mock(returncode=0) + with ( + mock.patch.object(adapter.sys, "platform", "linux"), + mock.patch.object( + adapter, + "_fixed_executable", + side_effect=("/usr/bin/unshare", "/usr/bin/true"), + ), + mock.patch.object( + adapter, "_mount_namespace_identity", return_value="mnt:[123]" + ), + mock.patch.object(adapter.subprocess, "run", return_value=probe) as run, + mock.patch.object(adapter.os, "execv", side_effect=OSError("fixture")) as execv, + ): + self.assertFalse(adapter._exec_in_private_snapshot_namespace()) + + probe_command = run.call_args.args[0] + command = execv.call_args.args[1] + self.assertEqual(probe_command[-1], "/usr/bin/true") + self.assertIn("--mount", command) + self.assertIn("--pid", command) + self.assertIn("--fork", command) + self.assertIn("--kill-child=SIGKILL", command) + self.assertIn("--forward-signals", command) + self.assertIn(adapter.PRIVATE_NAMESPACE_FLAG, command) + + def test_linux_namespace_probe_or_private_mount_failure_uses_exact_reaper_fallback(self): + with ( + mock.patch.object(adapter.sys, "platform", "linux"), + mock.patch.object( + adapter, + "_fixed_executable", + side_effect=("/usr/bin/unshare", "/usr/bin/true"), + ), + mock.patch.object( + adapter, "_mount_namespace_identity", return_value="mnt:[123]" + ), + mock.patch.object( + adapter.subprocess, "run", return_value=mock.Mock(returncode=1) + ), + mock.patch.object(adapter.os, "execv") as execv, + ): + self.assertFalse(adapter._exec_in_private_snapshot_namespace()) + execv.assert_not_called() + + with ( + mock.patch.object( + adapter.sys, + "argv", + [adapter.__file__, adapter.PRIVATE_NAMESPACE_FLAG, "mnt:[123]"], + ), + mock.patch.object( + adapter, + "_prepare_private_snapshot_parent", + side_effect=adapter.StartupError("fixture mount refusal"), + ), + mock.patch.object(adapter, "_run_production_server", return_value=17) as run, + mock.patch.object(adapter, "_exec_in_private_snapshot_namespace") as enter, + ): + self.assertEqual(adapter.main(), 17) + run.assert_called_once_with(None) + enter.assert_not_called() + + def test_private_namespace_child_arguments_are_exact(self): + self.assertEqual( + adapter._parse_namespace_child( + [adapter.PRIVATE_NAMESPACE_FLAG, "mnt:[123]"] + ), + "mnt:[123]", + ) + for arguments in ( + ["--other", "mnt:[123]"], + [adapter.PRIVATE_NAMESPACE_FLAG, "forged"], + [adapter.PRIVATE_NAMESPACE_FLAG, "mnt:[123]", "extra"], + ): + with self.subTest(arguments=arguments), self.assertRaises(adapter.StartupError): + adapter._parse_namespace_child(arguments) + def test_production_builder_refuses_unsupported_host_before_any_runtime_access(self): plugin_root = self.root / "host-guard-plugin" plugin_root.mkdir() @@ -2035,11 +2247,16 @@ def test_production_builder_refuses_unsupported_host_before_any_runtime_access(s catalog.assert_not_called() validator.assert_not_called() - def test_production_bootstraps_both_wrapper_modules_from_pinned_bytes(self): + def test_production_bootstraps_all_wrapper_modules_from_pinned_bytes(self): plugin_root = self.root / "verified-wrapper-plugin" plugin_root.mkdir() (plugin_root / "PLUGIN_IDENTITY.sha256").write_text("fixture\n") inventory = { + "mcp/advanced.py": "d" * 64, + "mcp/certificates/hellgate_v1.json.zlib": "f" * 64, + "mcp/hellgate_verify.py": "e" * 64, + "mcp/measurement.py": "c" * 64, + "mcp/stem.py": "1" * 64, "scripts/provision_runtime.py": "a" * 64, "scripts/verify_plugin.py": "b" * 64, } @@ -2051,13 +2268,53 @@ def test_production_bootstraps_both_wrapper_modules_from_pinned_bytes(self): verify_manifest=mock.Mock(return_value=records) ) runtime_validator = mock.Mock(return_value={}) + checker_module = types.SimpleNamespace( + VerificationRefusal=type("FixtureRefusal", (Exception,), {}), + verify_bytes=mock.Mock( + return_value={ + "status": "bounded", + "checker_verdict": "ACCEPT", + "formal": False, + "fields": { + "trial_diagnostics": { + "schema": "jackal-hellgate-trial-diagnostics-v1", + "status": "bounded", + "subject": "normalized-certificate-trial-phi", + "non_claims": ["not the exact ground state u0"], + }, + "ground_state_transfer": { + "schema": "jackal-hellgate-ground-transfer-v1", + "status": "bounded", + "subject": "positive-normalized-ground-state-u0", + "method": "lambda-strong-convexity-density-transfer-v1", + "non_claims": ["does not enclose polynomial moments"], + }, + }, + } + ), + ) with ( mock.patch.object(adapter, "_read_identity_inventory", return_value=inventory), mock.patch.object( adapter, "_load_verified_module", - side_effect=(verifier_module, self.provisioner), + side_effect=( + verifier_module, + measurement, + advanced, + checker_module, + stem, + self.provisioner, + ), ) as loader, + mock.patch.object( + adapter, + "_read_verified_plugin_blob", + return_value=(b"compressed-fixture", "f" * 64), + ), + mock.patch.object( + adapter, "_decompress_certificate", return_value=b"certificate-fixture" + ), ): server = adapter.build_production_server( plugin_root=plugin_root, @@ -2072,6 +2329,22 @@ def test_production_bootstraps_both_wrapper_modules_from_pinned_bytes(self): plugin_root, "scripts/verify_plugin.py", "jackel_codex_verify_plugin", inventory, ), + mock.call( + plugin_root, "mcp/measurement.py", + "jackel_codex_measurement", inventory, + ), + mock.call( + plugin_root, "mcp/advanced.py", + "jackel_codex_advanced", inventory, + ), + mock.call( + plugin_root, "mcp/hellgate_verify.py", + "jackel_codex_hellgate_verify", inventory, + ), + mock.call( + plugin_root, "mcp/stem.py", + "jackel_codex_stem", inventory, + ), mock.call( plugin_root, "scripts/provision_runtime.py", "jackel_codex_provision_runtime", inventory, @@ -2081,7 +2354,13 @@ def test_production_bootstraps_both_wrapper_modules_from_pinned_bytes(self): verifier_module.verify_manifest.assert_called_once_with( plugin_root, plugin_root / "PLUGIN_IDENTITY.sha256" ) - self.assertEqual(len(server.tool_definitions), RUNTIME_TOOL_COUNT) + self.assertEqual( + len(server.tool_definitions), + RUNTIME_TOOL_COUNT + + adapter.EXPECTED_MEASUREMENT_TOOL_COUNT + + adapter.EXPECTED_ADVANCED_TOOL_COUNT + + adapter.EXPECTED_STEM_TOOL_COUNT, + ) asyncio.run(server.close()) def test_snapshot_is_cleaned_when_post_copy_startup_refuses(self): @@ -2140,7 +2419,9 @@ def test_calls_remain_bound_to_snapshot_after_original_launcher_backend_and_aba_ ) backend_bytes = ( b"#!/bin/sh\n" - b"echo '{\"status\":\"checked\",\"origin\":\"snapshot\"}'\n" + b"IFS= read -r request\n" + b"echo '{\"jsonrpc\":\"2.0\",\"id\":\"jackal-adapter-backend\"," + b"\"result\":{\"status\":\"checked\",\"origin\":\"snapshot\"}}'\n" ) files = { "MANIFEST.sha256": b"fixture manifest\n", @@ -2183,6 +2464,7 @@ def test_calls_remain_bound_to_snapshot_after_original_launcher_backend_and_aba_ }, SELFTEST_TIMEOUT=2.0, SELFTEST_OUTPUT_LIMIT=65536, validate_host=mock.Mock(return_value=None), + reap_orphaned_runtime_snapshots=real_provisioner.reap_orphaned_runtime_snapshots, validate_runtime=real_provisioner.validate_runtime, create_runtime_snapshot=real_provisioner.create_runtime_snapshot, runtime_subprocess_environment=real_provisioner.runtime_subprocess_environment, diff --git a/tests/codex_plugin/test_measurement.py b/tests/codex_plugin/test_measurement.py new file mode 100644 index 0000000..5eece75 --- /dev/null +++ b/tests/codex_plugin/test_measurement.py @@ -0,0 +1,159 @@ +import copy +import unittest + +from plugins.jackel.mcp import measurement +from plugins.jackel.mcp import server as adapter + + +FIXTURE_IDENTITY = "a" * 64 + + +class MeasurementSurfaceTests(unittest.TestCase): + def test_identity_pinned_definitions_are_one_closed_surface(self): + definitions = adapter.build_measurement_tool_definitions(measurement) + + self.assertEqual( + {definition["name"] for definition in definitions}, + adapter.MEASUREMENT_TOOL_NAMES, + ) + self.assertEqual(len(definitions), adapter.EXPECTED_MEASUREMENT_TOOL_COUNT) + for definition in definitions: + with self.subTest(tool=definition["name"]): + self.assertIs(definition["inputSchema"]["additionalProperties"], False) + self.assertEqual( + definition["annotations"], + { + "readOnlyHint": True, + "destructiveHint": False, + "idempotentHint": True, + "openWorldHint": False, + }, + ) + + def test_definition_tampering_refuses_before_merge(self): + original = measurement.tool_definitions + definitions = original() + definitions[0] = copy.deepcopy(definitions[0]) + definitions[0]["name"] = "jackal_forged" + measurement.tool_definitions = lambda: definitions + try: + with self.assertRaises(adapter.CatalogError): + adapter.build_measurement_tool_definitions(measurement) + finally: + measurement.tool_definitions = original + + def test_scientific_notation_is_not_split(self): + text = ( + "Bounds: 10^-12, 10**-12, 10^{-12}, 10⁻¹², 2e-12, " + "and 1×10⁻¹²." + ) + + def no_kernel_call(unused_name, unused_arguments): + self.fail("the lexical scan must not call the arithmetic runtime") + + body = measurement.dispatch_integrated( + "jackal_scan", + {"text": text, "context_window": 60}, + no_kernel_call, + FIXTURE_IDENTITY, + ) + + self.assertEqual(body["status"], "checked") + self.assertEqual( + [item["text"] for item in body["fields"]["numerals"]], + ["10^-12", "10**-12", "10^{-12}", "10⁻¹²", "2e-12", "1×10⁻¹²"], + ) + self.assertEqual( + body["identities"]["jackal_measurement_sha256"], FIXTURE_IDENTITY + ) + + def test_integer_variance_uses_canonical_point_interval(self): + exact_values = { + "(0) + (4) + (6) + (2)": "12", + "(12) / 4": "3", + "((2) + (4)) / 2": "3", + "((0) - (3))^2 + ((4) - (3))^2 + ((6) - (3))^2 + ((2) - (3))^2": "20", + "(20) / 4": "5", + "(6) - (0)": "6", + "(20) / 3": "20/3", + "2": "2", + "3": "3", + } + calls = [] + + def kernel_call(name, arguments): + calls.append((name, copy.deepcopy(arguments))) + if name == "jackal_exact": + expression = arguments["expression"] + value = exact_values[expression] + return { + "status": "exact", + "fields": {"parsed": expression, "exact": value, "approx": value}, + "identities": {"evaluator_sha256": "b" * 64}, + } + if name == "jackal_sqrt_rat_bound": + self.assertEqual(arguments["input_lo"], "5") + self.assertEqual(arguments["input_hi"], "5") + return { + "status": "formal-bounded", + "checker_rerun": "ACCEPT", + "checker_output": "output 2 3", + } + self.fail(f"unexpected delegated tool {name}") + + body = measurement.dispatch_integrated( + "jackal_stat", + {"sample": [0, 4, 6, 2], "include_stddev": True}, + kernel_call, + FIXTURE_IDENTITY, + ) + + self.assertEqual(body["status"], "exact") + self.assertEqual(body["fields"]["population_variance"], "5") + self.assertEqual( + body["fields"]["field_status"]["population_stddev_enclosure"], + "formal-bounded", + ) + sqrt_calls = [arguments for name, arguments in calls if name == "jackal_sqrt_rat_bound"] + self.assertEqual(sqrt_calls, [{"expression": "sqrt(x)", "input_lo": "5", "input_hi": "5"}]) + self.assertNotIn("5/1", repr(calls)) + + def test_kernel_refusal_propagates_without_fallback(self): + calls = [] + + def kernel_call(name, arguments): + calls.append((name, arguments)) + return { + "status": "refused", + "reason": "fixture-refusal", + "detail": "fixture detail", + } + + body = measurement.dispatch_integrated( + "jackal_percent", + {"op": "of", "a": "10", "b": "20"}, + kernel_call, + FIXTURE_IDENTITY, + ) + + self.assertEqual(body["status"], "refused") + self.assertEqual(body["reason"], "kernel-refused:fixture-refusal") + self.assertEqual(len(calls), 1) + self.assertNotIn("fields", body) + + def test_json_float_sample_refuses_before_kernel_call(self): + calls = [] + body = measurement.dispatch_integrated( + "jackal_stat", + {"sample": [0.1]}, + lambda name, arguments: calls.append((name, arguments)), + FIXTURE_IDENTITY, + ) + + self.assertEqual(body["status"], "refused") + self.assertEqual(body["reason"], "args") + self.assertEqual(calls, []) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/codex_plugin/test_plugin_metadata.py b/tests/codex_plugin/test_plugin_metadata.py index 569ef2a..923d4a7 100644 --- a/tests/codex_plugin/test_plugin_metadata.py +++ b/tests/codex_plugin/test_plugin_metadata.py @@ -35,8 +35,10 @@ / "2026-08-17-jackel-codex-plugin.md" ) APPROVED_SKILL_DESCRIPTION = ( - "Route claim-aware computation, domain-pack, and Anubis program evidence " - "through JACKAL without overstating assurance." + "Route evidence-aware CAS, graphing, THOTH measurement, exact-field " + "matrices, statistical models, sensors, aerospace workflows, linked views, " + "claim bundles, nonlinear certificates, and Anubis program evidence through " + "JACKAL without overstating assurance." ) @@ -106,7 +108,7 @@ def test_legacy_ids_remain_jackel_but_public_product_is_jackal(self): ) self.assertEqual(manifest["name"], "jackel") - self.assertEqual(manifest["interface"]["displayName"], "JACKAL") + self.assertEqual(manifest["interface"]["displayName"], "JACKAL + THOTH") self.assertIn("JACKAL", manifest["description"]) self.assertIn("JACKAL", manifest["interface"]["longDescription"]) self.assertIn("JACKAL", manifest["interface"]["defaultPrompt"][0]) @@ -127,7 +129,7 @@ def test_legacy_ids_remain_jackel_but_public_product_is_jackal(self): ) self.assertEqual(set(mcp["mcpServers"]), {"jackel"}) self.assertEqual(self.parse_skill_frontmatter(skill)["name"], "jackel") - self.assertIn("# JACKAL numerical-trust operator", skill) + self.assertIn("# JACKAL + THOTH numerical-trust operator", skill) self.assertNotIn("JACKEL", skill) server = SERVER_PATH.read_text(encoding="utf-8") self.assertIn("Preserve JACKAL status", server) @@ -217,46 +219,85 @@ def test_jackel_plugin_metadata_contract(self): self.assertEqual(marketplace["interface"]["displayName"], "Anubis Quantum Cipher") interface = manifest["interface"] - self.assertEqual(interface["displayName"], "JACKAL") - self.assertEqual(interface["shortDescription"], "Claim-aware computation with explicit evidence classes") + self.assertEqual(interface["displayName"], "JACKAL + THOTH") + self.assertEqual( + interface["shortDescription"], + "Evidence-aware CAS, linked STEM views, and THOTH measurement", + ) self.assertEqual(interface["developerName"], "Anubis Quantum Cipher") self.assertEqual(interface["category"], "Productivity") self.assertEqual(interface["capabilities"], ["Interactive"]) self.assertEqual(interface["websiteURL"], "https://github.com/AnubisQuantumCipher/jackal") + self.assertEqual(interface["brandColor"], "#00E0B8") + self.assertEqual( + interface["screenshots"], + [ + "./assets/jackal-thoth-hellgate-graph.png", + "./assets/jackal-linked-evidence-workspace.png", + ], + ) self.assertEqual( interface["defaultPrompt"], [ - "Classify and verify this numerical claim with JACKAL.", - "Find the strongest supported bound and refuse any silent downgrade.", - "Verify this receipt or claim bundle against my pinned expectations.", - "Verify this Anubis Safe program-evidence package without executing its artifact.", + "Use JACKAL + THOTH to solve and classify this calculation.", + "Graph this expression and separate visualization from evidence.", + "Open a linked symbolic, numeric, graph, table, and evidence workspace for this expression.", + "Solve this matrix or regression workflow while preserving exact fields and model assumptions.", + "Analyze this supplied sensor batch or aerospace model without upgrading its provenance or physical assumptions.", + "Replay the HELLGATE nonlinear ground-state certificate without promoting its assurance.", ], ) expected_long_description = ( - "Expose JACKAL's 41-tool v1.7.3 release runtime through Codex. " - "The MCP adapter copies the parsed runtime result object into " - "structuredContent unchanged; its only adapter-local tool result is " - "status=refused reason=plugin-busy. Runtime result and assurance " - "vocabulary: ok, exact, structural-exact, formal-bounded, bounded, " - "checked, estimated, model-based, verified, " + "Expose one unified 58-tool JACKAL surface through Codex: the sealed " + "41-tool v1.7.3 release runtime, seven identity-pinned THOTH " + "measurement/provenance tools, three identity-pinned CAS, graph, and " + "nonlinear-certificate tools, and seven identity-pinned STEM workflows " + "for matrices, regression, probability, hypothesis testing, supplied " + "sensor batches, aerospace models, and a professional linked evidence " + "workspace. THOTH is a named JACKAL subsystem, never a separate server " + "or arithmetic authority. Every reported numeric field in the additive " + "workflows delegates to an admitted JACKAL lane; wrapper orchestration " + "and UI rendering add no mathematical assurance. The adapter copies each " + "parsed sealed-runtime result object into structuredContent unchanged. " + "For additive results it deep-copies the result and removes only the " + "identity-validated _mcp_content transport envelope before returning " + "structuredContent; its only transport-local refusal is status=refused " + "reason=plugin-busy. Graph coordinates are exact rational JACKAL results, " + "sampled values and pixels remain estimated visualization, and refused " + "samples break the curve. The fixed HELLGATE lane replays an independent " + "exact-rational certificate as bounded, never formal-bounded. Result " + "vocabulary: ok, exact, exact-given, structural-exact, formal-bounded, " + "bounded, checked, estimated, model-based, verified, " "verified-program-evidence, verified-program-receipt, indeterminate, " - "and refused. Formal-bounded is limited to checker-admitted fragments; " - "program evidence leaves construct-totality, source, and runtime " - "residuals open. Requires Apple Silicon macOS and Python >=3.10 at " - "/opt/homebrew/bin/python3 (install with brew install python)." + "refused. Field statuses, assumptions, identities, route traces, refusal " + "reasons, consequence ceilings, and non-claims remain first-class. " + "Requires a host-admitted pinned runtime and Python >=3.10 at a fixed " + "launcher-approved path." ) self.assertEqual(interface["longDescription"], expected_long_description) - self.assertIn(f"- `interface.longDescription`: `{expected_long_description}`", DESIGN_PATH.read_text(encoding="utf-8")) + design = DESIGN_PATH.read_text(encoding="utf-8") + self.assertIn("unified 58-tool surface", design) + self.assertIn("graph visualization", design) self.assertRegex(manifest["version"], r"^0\.1\.0\+codex\.\d{14}$") - self.assertEqual(manifest["description"], "Expose JACKAL's claim-aware computation, domain-pack, and program-evidence kernel to Codex.") + self.assertEqual( + manifest["description"], + "Expose JACKAL's evidence-aware CAS, professional linked graphing, " + "integrated THOTH measurement, matrices, statistical models, sensors, " + "aerospace workflows, nonlinear certificates, and program evidence to Codex.", + ) self.assertEqual(manifest["author"], {"name": "Anubis Quantum Cipher", "url": "https://github.com/AnubisQuantumCipher"}) self.assertEqual(manifest["homepage"], "https://github.com/AnubisQuantumCipher/jackal") self.assertEqual(manifest["repository"], "https://github.com/AnubisQuantumCipher/jackal") self.assertEqual(manifest["license"], "MIT") self.assertEqual( manifest["keywords"], - ["jackel", "mathematics", "numerical-trust", "formal-verification", "evidence", "mcp"], + [ + "jackel", "thoth", "mathematics", "computer-algebra", + "graphing", "linked-views", "matrices", "regression", + "probability", "sensors", "aerospace", "symbolic-algebra", + "numerical-trust", "formal-verification", "evidence", "mcp", + ], ) self.assertEqual(manifest["skills"], "./skills/") self.assertEqual(manifest["mcpServers"], "./.mcp.json") @@ -269,11 +310,9 @@ def test_jackel_plugin_metadata_contract(self): for forbidden in ( "privacyPolicyURL", "termsOfServiceURL", - "brandColor", "composerIcon", "logo", "logoDark", - "screenshots", ): self.assertNotIn(forbidden, interface) @@ -318,9 +357,10 @@ def test_jackel_plugin_metadata_contract(self): "error estimate is not a bound", "Source-to-native refinement remains open and unclaimed", "Run a weaker lane only when the caller explicitly requests one", - "Darwin/arm64 and Linux/aarch64", + "Darwin/arm64, Linux/aarch64, and Linux/x86_64", "Do not bypass the host guard", - "no published release asset for host linux-aarch64", + "Linux/aarch64 has an exact host-specific pin", + "Linux/x86_64 has no", "Python >=3.10", "brew install python", ): @@ -337,9 +377,17 @@ def test_every_shipped_plugin_path_exists_and_is_identity_governed(self): mcp = self.load_json(MCP_PATH)["mcpServers"]["jackel"] referenced = { "README.md", + "assets/jackal-thoth-hellgate-graph.png", + "assets/jackal-linked-evidence-workspace.png", ".codex-plugin/plugin.json", manifest["mcpServers"].removeprefix("./"), "mcp/server.py", + "mcp/measurement.py", + "mcp/advanced.py", + "mcp/stem.py", + "mcp/hellgate_verify.py", + "mcp/certificates/README.md", + "mcp/certificates/hellgate_v1.json.zlib", "scripts/provision_runtime.py", "scripts/launch_mcp.sh", "scripts/launch_mcp.zsh", @@ -365,6 +413,16 @@ def test_readme_documents_release_install_discovery_and_boundaries(self): text = README_PATH.read_text(encoding="utf-8") for required in ( "41-tool", + "58-tool", + "THOTH", + "jackal_graph", + "jackal_hellgate_ground_state", + "jackal_matrix", + "jackal_regression", + "jackal_sensor", + "jackal_aerospace", + "jackal_linked_workspace", + "plugin-card screenshot", "v1.7.3 release", "release/capability_inventory_v1.json", "/bin/sh scripts/launch_mcp.sh provision", diff --git a/tests/codex_plugin/test_runtime_provisioner.py b/tests/codex_plugin/test_runtime_provisioner.py index 78c58c0..eb91ea6 100644 --- a/tests/codex_plugin/test_runtime_provisioner.py +++ b/tests/codex_plugin/test_runtime_provisioner.py @@ -1,3 +1,4 @@ +import ctypes import errno import hashlib import io @@ -43,6 +44,15 @@ class RuntimeProvisionerTests(unittest.TestCase): def sha(self, data): return hashlib.sha256(data).hexdigest() + def write_snapshot_owner(self, parent, name, identity): + root = parent / name + root.mkdir(mode=0o700) + provisioner._write_snapshot_owner(root, identity) + runtime = root / provisioner.SNAPSHOT_RUNTIME_DIRECTORY + runtime.mkdir(mode=0o700) + (runtime / "payload").write_bytes(b"fixture\n") + return root + def add_bytes(self, archive, name, data=b"", mode=0o644, kind=tarfile.REGTYPE, linkname=""): info = tarfile.TarInfo(name) info.type = kind @@ -836,6 +846,13 @@ def test_private_runtime_snapshot_is_exact_independent_and_owned(self): snapshot_root = snapshot.root self.assertNotEqual(snapshot_root, source) + self.assertEqual(snapshot_root.parent, snapshot.owner_root) + self.assertEqual(snapshot_root.name, provisioner.SNAPSHOT_RUNTIME_DIRECTORY) + self.assertTrue(snapshot.owner_root.name.startswith(provisioner.SNAPSHOT_PREFIX)) + self.assertEqual( + provisioner._load_snapshot_owner(snapshot.owner_root), + provisioner._current_snapshot_owner(), + ) self.assertEqual(snapshot_root.stat().st_mode & 0o777, 0o700) self.assertEqual( (snapshot_root / "payload.txt").read_bytes(), b"payload\n" @@ -863,6 +880,7 @@ def test_private_runtime_snapshot_is_exact_independent_and_owned(self): snapshot.close() self.assertFalse(snapshot_root.exists()) + self.assertFalse(snapshot.owner_root.exists()) def test_runtime_snapshot_cleanup_failure_remains_retryable(self): with tempfile.TemporaryDirectory() as directory: @@ -878,6 +896,170 @@ def test_runtime_snapshot_cleanup_failure_remains_retryable(self): self.assertTrue(snapshot._closed) self.assertEqual(cleanup.call_count, 2) + def test_linux_process_stat_parser_handles_spaces_and_closing_parentheses(self): + fields = [b"S"] + ([b"0"] * 18) + [b"9876"] + self.assertEqual( + provisioner._parse_linux_process_stat( + b"123 (worker ) with spaces) " + b" ".join(fields) + b"\n", + expected_pid=123, + ), + (123, "9876"), + ) + + def test_darwin_process_identity_uses_kernel_start_timeval_and_detects_gone(self): + class FakeProcPIDInfo: + argtypes = None + restype = None + + def __init__(self, *, present): + self.present = present + + def __call__(self, pid, flavor, unused_argument, buffer, size): + self.assertions = (pid, flavor, unused_argument) + if not self.present: + return 0 + info = ctypes.cast( + buffer, ctypes.POINTER(provisioner._DarwinBSDInfo) + ).contents + info.pbi_pid = pid + info.pbi_start_tvsec = 1_700_000_000 + info.pbi_start_tvusec = 123_456 + return size + + available = FakeProcPIDInfo(present=True) + with mock.patch.object( + provisioner.ctypes, + "CDLL", + return_value=types.SimpleNamespace(proc_pidinfo=available), + ): + self.assertEqual( + provisioner._darwin_process_identity(321), + (321, "1700000000:123456"), + ) + self.assertEqual( + available.assertions, (321, provisioner.DARWIN_PROC_PIDTBSDINFO, 0) + ) + + gone = FakeProcPIDInfo(present=False) + with ( + mock.patch.object( + provisioner.ctypes, + "CDLL", + return_value=types.SimpleNamespace(proc_pidinfo=gone), + ), + mock.patch.object(provisioner.os, "kill", side_effect=ProcessLookupError), + self.assertRaises(provisioner._ProcessGone), + ): + provisioner._darwin_process_identity(322) + + def test_snapshot_reaper_is_exact_for_live_gone_reused_and_ambiguous_owners(self): + with tempfile.TemporaryDirectory() as directory: + parent = Path(directory) + boot_id = "linux:test-boot" + live = self.write_snapshot_owner( + parent, + f"{provisioner.SNAPSHOT_PREFIX}live", + provisioner.SnapshotOwnerIdentity(101, "live-start", boot_id), + ) + reused = self.write_snapshot_owner( + parent, + f"{provisioner.SNAPSHOT_PREFIX}reused", + provisioner.SnapshotOwnerIdentity(102, "old-start", boot_id), + ) + gone = self.write_snapshot_owner( + parent, + f"{provisioner.SNAPSHOT_PREFIX}gone", + provisioner.SnapshotOwnerIdentity(103, "gone-start", boot_id), + ) + foreign_boot = self.write_snapshot_owner( + parent, + f"{provisioner.SNAPSHOT_PREFIX}foreign", + provisioner.SnapshotOwnerIdentity(104, "foreign-start", "linux:other"), + ) + missing_stamp = parent / f"{provisioner.SNAPSHOT_PREFIX}missing" + missing_stamp.mkdir(mode=0o700) + malformed = parent / f"{provisioner.SNAPSHOT_PREFIX}malformed" + malformed.mkdir(mode=0o700) + (malformed / provisioner.SNAPSHOT_OWNER_FILE).write_text("not-json\n") + unstamped_identity = provisioner.SnapshotOwnerIdentity( + 105, "unstamped-start", boot_id + ) + unstamped = parent / ( + provisioner._snapshot_owner_directory_prefix(unstamped_identity) + + "fixture" + ) + unstamped.mkdir(mode=0o700) + partial_identity = provisioner.SnapshotOwnerIdentity( + 106, "partial-start", boot_id + ) + partial = parent / ( + provisioner._snapshot_owner_directory_prefix(partial_identity) + + "fixture" + ) + partial.mkdir(mode=0o700) + (partial / provisioner.SNAPSHOT_OWNER_FILE).write_text("partial") + named_identity = provisioner.SnapshotOwnerIdentity( + 107, "named-start", boot_id + ) + mismatch = self.write_snapshot_owner( + parent, + provisioner._snapshot_owner_directory_prefix(named_identity) + + "fixture", + provisioner.SnapshotOwnerIdentity(108, "other-start", boot_id), + ) + + observed = [] + + def process_start(pid): + observed.append(pid) + if pid == 101: + return "live-start" + if pid == 102: + return "new-start" + if pid == 103: + raise provisioner._ProcessGone("fixture gone") + if pid == 105: + raise provisioner._ProcessGone("fixture gone before stamp") + if pid == 106: + raise provisioner._ProcessGone("fixture gone during stamp") + raise AssertionError(f"ambiguous owner was inspected: {pid}") + + removed = provisioner.reap_orphaned_runtime_snapshots( + parent, + current_boot_id=boot_id, + process_start_reader=process_start, + ) + + self.assertEqual(set(removed), {reused, gone, unstamped, partial}) + self.assertEqual(set(observed), {101, 102, 103, 105, 106}) + self.assertTrue(live.exists()) + self.assertFalse(reused.exists()) + self.assertFalse(gone.exists()) + self.assertTrue(foreign_boot.exists()) + self.assertTrue(missing_stamp.exists()) + self.assertTrue(malformed.exists()) + self.assertFalse(unstamped.exists()) + self.assertFalse(partial.exists()) + self.assertTrue(mismatch.exists()) + + def test_default_snapshot_parent_canonicalizes_the_platform_tmp_symlink(self): + with tempfile.TemporaryDirectory() as directory: + physical = Path(directory) / "private-tmp" + physical.mkdir() + lexical = Path(directory) / "tmp" + lexical.symlink_to(physical, target_is_directory=True) + with mock.patch.object( + provisioner.tempfile, "gettempdir", return_value=str(lexical) + ): + self.assertEqual(provisioner._snapshot_parent_path(None), physical) + self.assertEqual( + provisioner.reap_orphaned_runtime_snapshots( + current_boot_id="fixture-boot", + process_start_reader=mock.Mock(), + ), + (), + ) + def test_runtime_snapshot_preflights_file_size_against_remaining_budget(self): with tempfile.TemporaryDirectory() as directory: base = Path(directory) diff --git a/tests/codex_plugin/test_stem.py b/tests/codex_plugin/test_stem.py new file mode 100644 index 0000000..5acd110 --- /dev/null +++ b/tests/codex_plugin/test_stem.py @@ -0,0 +1,520 @@ +import ast +import copy +import hashlib +import unittest +from fractions import Fraction + +from plugins.jackel.mcp import server as adapter +from plugins.jackel.mcp import stem + + +FIXTURE_IDENTITY = "d" * 64 + + +class ExactFixtureKernel: + """Small test double: product code still has to delegate every numeric field.""" + + def __init__(self): + self.calls = [] + + def __call__(self, name, arguments): + self.calls.append((name, copy.deepcopy(arguments))) + if name == "jackal_exact": + expression = arguments["expression"] + value = self._fraction(ast.parse(expression.replace("^", "**"), mode="eval").body) + rendered = str(value.numerator) + if value.denominator != 1: + rendered += f"/{value.denominator}" + return { + "status": "exact", + "fields": {"parsed": expression, "exact": rendered}, + "formal": False, + } + if name == "jackal_evaluate": + return {"status": "estimated", "engine_output": "0", "formal": False} + if name == "jackal_integrate_adaptive": + return { + "status": "estimated", + "fields": {"integral": "1/4", "parsed": arguments["expression"]}, + "formal": False, + } + if name in {"jackal_sqrt_rat_bound", "jackal_ln_rat_bound"}: + return { + "status": "formal-bounded", + "checker_rerun": "ACCEPT", + "fields": { + "parsed": arguments["expression"], + "input_lo": arguments["input_lo"], + "input_hi": arguments["input_hi"], + }, + "formal": True, + } + if name == "jackal_canon": + return {"status": "exact", "engine_output": "(pow x 2)", "formal": False} + if name == "jackal_diff": + return {"status": "checked", "engine_output": "2*x", "formal": False} + raise AssertionError(f"unexpected delegated tool: {name}") + + def _fraction(self, node): + if isinstance(node, ast.Constant) and isinstance(node.value, int): + return Fraction(node.value) + if isinstance(node, ast.UnaryOp): + value = self._fraction(node.operand) + if isinstance(node.op, ast.USub): + return -value + if isinstance(node.op, ast.UAdd): + return value + if isinstance(node, ast.BinOp): + left = self._fraction(node.left) + right = self._fraction(node.right) + if isinstance(node.op, ast.Add): + return left + right + if isinstance(node.op, ast.Sub): + return left - right + if isinstance(node.op, ast.Mult): + return left * right + if isinstance(node.op, ast.Div): + return left / right + if isinstance(node.op, ast.Pow) and right.denominator == 1: + return left ** right.numerator + raise AssertionError(f"unsupported fixture expression: {ast.dump(node)}") + + +class StemSurfaceTests(unittest.TestCase): + def test_definitions_form_one_closed_identity_pinned_surface(self): + definitions = adapter.build_stem_tool_definitions(stem) + + self.assertEqual( + {definition["name"] for definition in definitions}, adapter.STEM_TOOL_NAMES + ) + self.assertEqual(len(definitions), adapter.EXPECTED_STEM_TOOL_COUNT) + for definition in definitions: + with self.subTest(tool=definition["name"]): + self.assertIs(definition["inputSchema"]["additionalProperties"], False) + self.assertEqual( + definition["annotations"], + { + "readOnlyHint": True, + "destructiveHint": False, + "idempotentHint": True, + "openWorldHint": False, + }, + ) + + def test_definition_tampering_refuses_before_merge(self): + original = stem.tool_definitions + definitions = original() + definitions[0] = copy.deepcopy(definitions[0]) + definitions[0]["name"] = "jackal_forged" + stem.tool_definitions = lambda: definitions + try: + with self.assertRaises(adapter.CatalogError): + adapter.build_stem_tool_definitions(stem) + finally: + stem.tool_definitions = original + + def test_matrix_inverse_and_all_numeric_cells_delegate(self): + kernel = ExactFixtureKernel() + body = stem.dispatch_integrated( + "jackal_matrix", + {"operation": "inverse", "matrix": [["1", "2"], ["3", "5"]]}, + kernel, + FIXTURE_IDENTITY, + ) + + self.assertEqual(body["status"], "exact") + self.assertEqual(body["fields"]["matrix"], [["-5", "2"], ["3", "-1"]]) + self.assertTrue(kernel.calls) + self.assertEqual({name for name, unused in kernel.calls}, {"jackal_exact"}) + self.assertTrue(any("NOT formal-bounded" in item for item in body["non_claims"])) + + def test_every_matrix_route_and_singular_refusal(self): + kernel = ExactFixtureKernel() + cases = ( + ( + {"operation": "add", "matrix": [["1", "2"], ["3", "4"]], "second_matrix": [["5", "6"], ["7", "8"]]}, + "matrix", + [["6", "8"], ["10", "12"]], + ), + ( + {"operation": "multiply", "matrix": [["1", "2"], ["3", "4"]], "second_matrix": [["5", "6"], ["7", "8"]]}, + "matrix", + [["19", "22"], ["43", "50"]], + ), + ( + {"operation": "transpose", "matrix": [["1", "2", "3"], ["4", "5", "6"]]}, + "matrix", + [["1", "4"], ["2", "5"], ["3", "6"]], + ), + ( + {"operation": "determinant", "matrix": [["1", "2"], ["3", "4"]]}, + "determinant", + "-2", + ), + ( + {"operation": "rref", "matrix": [["1", "2"], ["2", "4"]]}, + "matrix", + [["1", "2"], ["0", "0"]], + ), + ( + {"operation": "solve", "matrix": [["1", "0"], ["0", "1"]], "vector": ["7", "9"]}, + "solution", + ["7", "9"], + ), + ) + for arguments, field, expected in cases: + with self.subTest(operation=arguments["operation"]): + body = stem.dispatch_integrated( + "jackal_matrix", arguments, kernel, FIXTURE_IDENTITY + ) + self.assertEqual(body["status"], "exact") + self.assertEqual(body["fields"][field], expected) + + singular = stem.dispatch_integrated( + "jackal_matrix", + {"operation": "inverse", "matrix": [["1", "2"], ["2", "4"]]}, + kernel, + FIXTURE_IDENTITY, + ) + self.assertEqual(singular["status"], "refused") + self.assertEqual(singular["reason"], "matrix-singular") + + def test_polynomial_regression_keeps_model_status_separate_from_exact_fields(self): + kernel = ExactFixtureKernel() + body = stem.dispatch_integrated( + "jackal_regression", + { + "model": "polynomial_ols", + "degree": "1", + "x": ["0", "1", "2"], + "y": ["1", "3", "5"], + }, + kernel, + FIXTURE_IDENTITY, + ) + + self.assertEqual(body["status"], "model-based") + self.assertEqual(body["fields"]["coefficients_ascending"], ["1", "2"]) + self.assertEqual(body["fields"]["sse"], "0") + self.assertEqual(body["field_status"]["coefficients_ascending"], "exact") + self.assertTrue(any("do not establish" in item for item in body["non_claims"])) + + def test_probability_and_hypothesis_preserve_model_assumptions(self): + kernel = ExactFixtureKernel() + probability = stem.dispatch_integrated( + "jackal_probability", + {"operation": "binomial_cdf", "n": "3", "k": "1", "p": "1/2"}, + kernel, + FIXTURE_IDENTITY, + ) + hypothesis = stem.dispatch_integrated( + "jackal_hypothesis", + { + "operation": "exact_binomial_tail", + "alternative": "greater", + "n": "3", + "k": "2", + "p0": "1/2", + }, + kernel, + FIXTURE_IDENTITY, + ) + + self.assertEqual(probability["status"], "model-based") + self.assertEqual(probability["fields"]["probability"], "1/2") + self.assertEqual(hypothesis["status"], "model-based") + self.assertEqual(hypothesis["fields"]["p_value"], "1/2") + self.assertEqual(hypothesis["consequence_ceiling"], "advisory") + + def test_binomial_endpoint_probabilities_do_not_divide_by_zero(self): + kernel = ExactFixtureKernel() + cases = ( + ({"operation": "binomial_cdf", "n": "3", "k": "1", "p": "1"}, "0"), + ({"operation": "binomial_pmf", "n": "3", "k": "3", "p": "1"}, "1"), + ({"operation": "binomial_cdf", "n": "3", "k": "0", "p": "0"}, "1"), + ) + for arguments, expected in cases: + with self.subTest(arguments=arguments): + body = stem.dispatch_integrated( + "jackal_probability", arguments, kernel, FIXTURE_IDENTITY + ) + self.assertEqual(body["status"], "model-based") + self.assertEqual(body["fields"]["probability"], expected) + + def test_normal_probability_and_all_z_alternatives_use_estimated_finite_tails(self): + kernel = ExactFixtureKernel() + normal = stem.dispatch_integrated( + "jackal_probability", + { + "operation": "normal_cdf", + "z": "0", + "tail_cutoff": "6", + "tolerance": "1/10", + }, + kernel, + FIXTURE_IDENTITY, + ) + self.assertEqual(normal["status"], "model-based") + self.assertEqual(normal["field_status"]["finite_cutoff_cdf_estimate"], "estimated") + + for alternative in ("less", "greater", "two_sided"): + with self.subTest(alternative=alternative): + body = stem.dispatch_integrated( + "jackal_hypothesis", + { + "operation": "one_sample_z", + "alternative": alternative, + "sample_mean": "1", + "null_mean": "1", + "population_sd": "2", + "n": "4", + "tail_cutoff": "6", + "tolerance": "1/10", + }, + kernel, + FIXTURE_IDENTITY, + ) + self.assertEqual(body["status"], "model-based") + self.assertEqual(body["field_status"]["p_value_estimate"], "estimated") + + def test_sensor_provenance_stays_supplied_and_stddev_stays_formal_bounded(self): + kernel = ExactFixtureKernel() + body = stem.dispatch_integrated( + "jackal_sensor", + { + "operation": "linear_calibration", + "sensor_id": "imu-1", + "channel": "accel-x", + "quantity": "acceleration", + "unit": "m/s2", + "samples": ["1", "2", "3"], + "source": "fixture-export.csv", + "observed_at": "fixture-time", + "scale": "2", + "offset": "1", + "calibration_source": "fixture-sheet", + "calibration_as_of": "fixture-date", + }, + kernel, + FIXTURE_IDENTITY, + ) + + self.assertEqual(body["status"], "exact-given") + self.assertEqual(body["given"]["input_provenance"], "supplied") + self.assertIs(body["given"]["calibration"]["verified"], False) + self.assertEqual( + body["field_status"]["population_stddev_enclosure"], "formal-bounded" + ) + self.assertTrue(any("does not claim it opened" in item for item in body["non_claims"])) + + def test_aerospace_formal_scalar_does_not_upgrade_physical_model(self): + kernel = ExactFixtureKernel() + body = stem.dispatch_integrated( + "jackal_aerospace", + {"operation": "vis_viva", "parameters": {"mu": "10", "radius": "2", "semi_major_axis": "3"}}, + kernel, + FIXTURE_IDENTITY, + ) + + self.assertEqual(body["status"], "model-based") + self.assertEqual(body["field_status"]["speed_enclosure"], "formal-bounded") + self.assertEqual(body["consequence_ceiling"], "advisory") + self.assertTrue(any("physical model" in item for item in body["non_claims"])) + + def test_every_aerospace_model_route_preserves_advisory_model_status(self): + kernel = ExactFixtureKernel() + cases = ( + {"operation": "circular_orbit", "parameters": {"mu": "10", "radius": "2"}}, + {"operation": "rocket_equation", "parameters": {"exhaust_velocity": "3", "initial_mass": "5", "final_mass": "2"}}, + {"operation": "hohmann_transfer", "parameters": {"mu": "10", "r1": "2", "r2": "3"}}, + {"operation": "plane_change", "parameters": {"velocity": "7", "angle_degrees": "30"}}, + ) + for arguments in cases: + with self.subTest(operation=arguments["operation"]): + body = stem.dispatch_integrated( + "jackal_aerospace", arguments, kernel, FIXTURE_IDENTITY + ) + self.assertEqual(body["status"], "model-based") + self.assertEqual(body["consequence_ceiling"], "advisory") + self.assertTrue(body["assumptions"]) + + invalid_angle = stem.dispatch_integrated( + "jackal_aerospace", + {"operation": "plane_change", "parameters": {"velocity": "7", "angle_degrees": "181"}}, + kernel, + FIXTURE_IDENTITY, + ) + self.assertEqual(invalid_angle["status"], "refused") + self.assertEqual(invalid_angle["reason"], "domain") + + def test_linked_workspace_embeds_digest_bound_html_without_upgrading_results(self): + kernel = ExactFixtureKernel() + body = stem.dispatch_integrated( + "jackal_linked_workspace", + {"expression": "x^2", "x_min": "-1", "x_max": "1", "samples": "17"}, + kernel, + FIXTURE_IDENTITY, + ) + + self.assertEqual(body["status"], "checked") + resource = body["_mcp_content"][1]["resource"] + digest = hashlib.sha256(resource["text"].encode("utf-8")).hexdigest() + self.assertEqual(resource["uri"], f"ui://jackal/linked-workspace/{digest}") + self.assertIn("Pixels are not proof", resource["text"]) + wrapped = adapter.backend_result(body) + self.assertEqual(wrapped["content"][1]["type"], "resource") + self.assertNotIn("_mcp_content", wrapped["structuredContent"]) + + def test_malformed_numeric_token_and_kernel_refusal_fail_closed(self): + calls = [] + malformed = stem.dispatch_integrated( + "jackal_matrix", + {"operation": "transpose", "matrix": [["1junk"]]}, + lambda name, arguments: calls.append((name, arguments)), + FIXTURE_IDENTITY, + ) + refused = stem.dispatch_integrated( + "jackal_matrix", + {"operation": "determinant", "matrix": [["1"]]}, + lambda unused_name, unused_arguments: { + "status": "refused", + "reason": "fixture-refusal", + "detail": "fixture detail", + }, + FIXTURE_IDENTITY, + ) + + self.assertEqual(malformed["status"], "refused") + self.assertEqual(malformed["reason"], "args") + self.assertEqual(calls, []) + self.assertEqual(refused["status"], "refused") + self.assertEqual(refused["reason"], "kernel-refused:fixture-refusal") + + def test_delegated_status_tampering_cannot_upgrade_a_field(self): + kernel = ExactFixtureKernel() + + def tampered(name, arguments): + if name == "jackal_sqrt_rat_bound": + return { + "status": "estimated", + "checker_rerun": "ACCEPT", + "formal": False, + } + return kernel(name, arguments) + + body = stem.dispatch_integrated( + "jackal_sensor", + { + "operation": "ingest_batch", + "sensor_id": "fixture", + "channel": "x", + "quantity": "q", + "unit": "u", + "samples": ["1", "2"], + "source": "fixture", + "observed_at": "fixture", + }, + tampered, + FIXTURE_IDENTITY, + ) + + self.assertEqual(body["status"], "refused") + self.assertEqual(body["reason"], "kernel-error") + self.assertNotIn("field_status", body) + + def test_adaptive_integration_status_tampering_refuses(self): + kernel = ExactFixtureKernel() + + def tampered(name, arguments): + if name == "jackal_integrate_adaptive": + return { + "status": "checked", + "fields": {"integral": "1/2"}, + "formal": False, + } + return kernel(name, arguments) + + body = stem.dispatch_integrated( + "jackal_probability", + { + "operation": "normal_cdf", + "z": "0", + "tail_cutoff": "6", + "tolerance": "1/10", + }, + tampered, + FIXTURE_IDENTITY, + ) + + self.assertEqual(body["status"], "refused") + self.assertEqual(body["reason"], "kernel-error") + + +class StemResourceValidationTests(unittest.TestCase): + def test_resource_digest_or_uri_tampering_fails_closed(self): + content = [ + {"type": "text", "text": "fixture"}, + { + "type": "resource", + "resource": { + "uri": "ui://jackal/linked-workspace/" + ("0" * 64), + "mimeType": "text/html", + "text": "tampered", + }, + }, + ] + with self.assertRaises(adapter.BackendFailure): + adapter.backend_result({"status": "checked", "_mcp_content": content}) + + +class StemResourceProtocolTests(unittest.IsolatedAsyncioTestCase): + async def asyncSetUp(self): + self.server = adapter.MCPServer( + runtime_root="/tmp", + launcher="/bin/false", + tool_definitions=adapter.build_stem_tool_definitions(stem), + runtime_environment={"PATH": "/usr/bin:/bin"}, + stem_module=stem, + stem_identity=FIXTURE_IDENTITY, + ) + + async def asyncTearDown(self): + await self.server.close() + + async def test_resource_listing_and_shell_read_are_closed_to_one_uri(self): + listed = await self.server.handle_message( + { + "jsonrpc": "2.0", + "id": "list", + "method": "resources/list", + "params": {}, + } + ) + resource = listed["result"]["resources"][0] + self.assertEqual(resource["uri"], adapter.LINKED_WORKSPACE_SHELL_URI) + + read = await self.server.handle_message( + { + "jsonrpc": "2.0", + "id": "read", + "method": "resources/read", + "params": {"uri": adapter.LINKED_WORKSPACE_SHELL_URI}, + } + ) + contents = read["result"]["contents"][0] + self.assertEqual(contents["mimeType"], "text/html") + self.assertIn("Call jackal_linked_workspace", contents["text"]) + + refused = await self.server.handle_message( + { + "jsonrpc": "2.0", + "id": "refuse", + "method": "resources/read", + "params": {"uri": "file:///tmp/forbidden"}, + } + ) + self.assertEqual(refused["error"]["code"], adapter.INVALID_PARAMS) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/codex_plugin/ui_stem_acceptance.py b/tests/codex_plugin/ui_stem_acceptance.py new file mode 100644 index 0000000..d72a197 --- /dev/null +++ b/tests/codex_plugin/ui_stem_acceptance.py @@ -0,0 +1,157 @@ +#!/usr/bin/env python3 +"""Rendered acceptance for JACKAL's static linked evidence workspace.""" + +from __future__ import annotations + +import argparse +from pathlib import Path +import sys + +from playwright.sync_api import sync_playwright + +REPOSITORY_ROOT = Path(__file__).resolve().parents[2] +if str(REPOSITORY_ROOT) not in sys.path: + sys.path.insert(0, str(REPOSITORY_ROOT)) + +from plugins.jackel.mcp import stem + + +def fixture_document() -> str: + points = [ + {"x": "-4", "y": "12", "status": "estimated"}, + {"x": "-3", "y": "5", "status": "estimated"}, + {"x": "-2", "y": "0", "status": "estimated"}, + {"x": "-1", "y": "-3", "status": "estimated"}, + {"x": "0", "y": "-4", "status": "estimated"}, + {"x": "1", "y": "-3", "status": "estimated"}, + {"x": "2", "y": "0", "status": "estimated"}, + {"x": "3", "y": "5", "status": "estimated"}, + {"x": "4", "y": "12", "status": "estimated"}, + ] + return stem._workspace_document( + { + "status": "checked", + "expression": "x^2 - 4", + "points": points, + "finite_sample_count": "9", + "canonical_text": "(sub (pow (var x) (num 2)) (num 4))", + "derivative_text": "d/dx[x^2-4] = 2*x · status=checked", + "route": [ + {"tool": "jackal_canon", "status": "exact", "parsed": "canonical expression"}, + {"tool": "jackal_diff", "status": "checked", "parsed": "sampled symbolic derivative check"}, + {"tool": "jackal_exact", "status": "exact", "parsed": "rational x coordinates"}, + {"tool": "jackal_evaluate", "status": "estimated", "parsed": "sampled y values"}, + ], + } + ) + + +def run(output: Path, mobile_output: Path | None = None) -> None: + output.parent.mkdir(parents=True, exist_ok=True) + if mobile_output is not None: + mobile_output.parent.mkdir(parents=True, exist_ok=True) + console_errors: list[str] = [] + page_errors: list[str] = [] + with sync_playwright() as playwright: + browser = playwright.chromium.launch(headless=True) + page = browser.new_page( + viewport={"width": 1440, "height": 980}, + device_scale_factor=1, + ) + page.on( + "console", + lambda message: console_errors.append(message.text) + if message.type == "error" + else None, + ) + page.on("pageerror", lambda error: page_errors.append(str(error))) + page.set_content(fixture_document(), wait_until="networkidle") + + page.locator("#plot").wait_for(state="visible") + if page.locator("#rows tr").count() != 9: + raise RuntimeError("workspace table did not render every supplied fixture point") + if page.locator(".route").count() != 4: + raise RuntimeError("workspace evidence route did not render every fixture stage") + if page.locator("#rows tr.active").count() != 1: + raise RuntimeError("workspace did not establish one synchronized cursor") + if page.locator('#status[data-status="checked"]').count() != 1: + raise RuntimeError("workspace did not expose the result status visually") + if page.locator(".trace-path").count() != 1: + raise RuntimeError("workspace did not render the continuous delegated trace") + if page.locator('path[fill="url(#trace-fill)"]').count() != 1: + raise RuntimeError("workspace did not render the graph depth layer") + route_statuses = page.locator(".route").evaluate_all( + "nodes => nodes.map(node => node.dataset.status)" + ) + if route_statuses != ["exact", "checked", "exact", "estimated"]: + raise RuntimeError("workspace did not preserve route status classes") + + page.locator("#rows tr").nth(2).focus() + if page.locator("#cursor-x").inner_text() != "-2": + raise RuntimeError("keyboard table focus did not synchronize the inspector") + + plot = page.locator("#plot").bounding_box() + if plot is None: + raise RuntimeError("workspace plot has no rendered bounds") + page.mouse.move(plot["x"] + plot["width"] - 8, plot["y"] + plot["height"] / 2) + page.wait_for_timeout(100) + if page.locator("#cursor-x").inner_text() != "4": + raise RuntimeError("plot hover did not synchronize the table and inspector") + page.evaluate("document.activeElement.blur()") + + page.screenshot(path=str(output), full_page=True) + + page.locator("#connect").click() + page.wait_for_timeout(100) + sensor_log = page.locator("#sensor-log").inner_text() + if "unavailable" not in sensor_log and "stopped" not in sensor_log: + raise RuntimeError("sensor dock did not expose its browser/device refusal") + + page.emulate_media(reduced_motion="reduce") + trace_animation = page.locator(".trace-path").evaluate( + "element => getComputedStyle(element).animationName" + ) + if trace_animation != "none": + raise RuntimeError("workspace did not honor reduced-motion preference") + + for width, height in ((760, 1100), (390, 844)): + page.set_viewport_size({"width": width, "height": height}) + page.wait_for_timeout(100) + horizontal_overflow = page.evaluate( + "document.documentElement.scrollWidth > document.documentElement.clientWidth" + ) + if horizontal_overflow: + raise RuntimeError( + f"responsive workspace introduces horizontal overflow at {width}px" + ) + if not page.locator("#status").is_visible() or not page.locator("#expr").is_visible(): + raise RuntimeError( + f"responsive workspace hides primary evidence context at {width}px" + ) + mobile_plot = page.locator("#plot").bounding_box() + if mobile_plot is None or mobile_plot["width"] <= 0 or mobile_plot["height"] <= 0: + raise RuntimeError(f"responsive workspace collapsed the graph at {width}px") + if width == 760 and mobile_output is not None: + page.screenshot(path=str(mobile_output), full_page=True) + browser.close() + + if console_errors or page_errors: + raise RuntimeError( + f"workspace emitted browser errors: console={console_errors!r} page={page_errors!r}" + ) + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument("--output", type=Path, required=True) + parser.add_argument("--mobile-output", type=Path) + arguments = parser.parse_args() + run(arguments.output, arguments.mobile_output) + print(arguments.output) + if arguments.mobile_output is not None: + print(arguments.mobile_output) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tests/jackal_skill_contract_test.py b/tests/jackal_skill_contract_test.py index 813cf84..8e59355 100644 --- a/tests/jackal_skill_contract_test.py +++ b/tests/jackal_skill_contract_test.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Check JACKAL routing skills against the canonical capability inventory.""" +"""Check JACKAL routing skills against sealed and additive capabilities.""" from __future__ import annotations @@ -8,6 +8,8 @@ import unittest from pathlib import Path +from plugins.jackel.mcp import server as codex_adapter + ROOT = Path(__file__).resolve().parents[1] INVENTORY = ROOT / "release/capability_inventory_v1.json" @@ -52,6 +54,14 @@ def inventory_names() -> set[str]: return {row["name"] for row in document["tools"]} +def codex_additive_names() -> set[str]: + return set( + codex_adapter.MEASUREMENT_TOOL_NAMES + | codex_adapter.ADVANCED_TOOL_NAMES + | codex_adapter.STEM_TOOL_NAMES + ) + + def profile_counts() -> dict[str, int]: document = json.loads(INVENTORY.read_text(encoding="utf-8")) counts = {"core": 0, "formal": 0, "full": 0} @@ -72,11 +82,17 @@ def current_block(text: str) -> str: def assert_router_contract( - case: unittest.TestCase, path: Path, *, require_marker: bool = True + case: unittest.TestCase, + path: Path, + *, + require_marker: bool = True, + allow_codex_additions: bool = False, ) -> None: text = path.read_text(encoding="utf-8") lower = text.lower() names = inventory_names() + if allow_codex_additions: + names |= codex_additive_names() references = set(TOOL_REFERENCE.findall(text)) case.assertTrue(REQUIRED_ROUTING <= references, (path, references)) case.assertEqual(references - names, set(), (path, references - names)) @@ -87,13 +103,21 @@ def assert_router_contract( block = current_block(text) case.assertIn("41-tool", block) case.assertIn("release/capability_inventory_v1.json", block) + if allow_codex_additions: + case.assertIn("58-tool", block) for stale in STALE_CURRENT: case.assertNotIn(stale, lower, (path, stale)) class JackalSkillContractTest(unittest.TestCase): - def test_repository_codex_router_uses_only_inventory_tools(self) -> None: - assert_router_contract(self, REPO_ROUTER) + def test_repository_codex_router_uses_only_unified_tools(self) -> None: + runtime = inventory_names() + additive = codex_additive_names() + self.assertFalse(runtime & additive) + self.assertEqual( + len(runtime | additive), codex_adapter.EXPECTED_UNIFIED_TOOL_COUNT + ) + assert_router_contract(self, REPO_ROUTER, allow_codex_additions=True) def test_personal_codex_oracle_names_current_replay_front_doors(self) -> None: if not PERSONAL_CODEX_ORACLE.is_file(): diff --git a/tools/capability_drift_gate.py b/tools/capability_drift_gate.py index cb7c20e..5819f55 100644 --- a/tools/capability_drift_gate.py +++ b/tools/capability_drift_gate.py @@ -33,7 +33,15 @@ ".codex-plugin/plugin.json", ".mcp.json", "README.md", + "assets/jackal-linked-evidence-workspace.png", + "assets/jackal-thoth-hellgate-graph.png", + "mcp/advanced.py", + "mcp/certificates/README.md", + "mcp/certificates/hellgate_v1.json.zlib", + "mcp/hellgate_verify.py", + "mcp/measurement.py", "mcp/server.py", + "mcp/stem.py", "scripts/launch_mcp.sh", "scripts/launch_mcp.zsh", "scripts/provision_runtime.py", @@ -46,13 +54,16 @@ CURRENT_SURFACE_BEGIN = "" CURRENT_SURFACE_END = "" TOOL_REFERENCE = re.compile(r"`(jackal_[a-z0-9_]+)`") +TOOL_NAME = re.compile(r"jackal_[a-z0-9_]+\Z") STATUS_ASSIGNMENT = re.compile(r"\bstatus\s*(?:=|:)\s*`?([a-z][a-z0-9-]*)") HEX64 = re.compile(r"[0-9a-f]{64}\Z") NEUTRAL_METADATA_CLAUSES = ( - "copies the parsed runtime result object into structuredContent unchanged", - "only adapter-local tool result is status=refused reason=plugin-busy", + "copies each parsed sealed-runtime result object into structuredContent unchanged", + "removes only the identity-validated _mcp_content transport envelope", + "only transport-local refusal is status=refused reason=plugin-busy", ) +WRAPPER_ONLY_STATUSES = frozenset({"exact-given"}) FORBIDDEN_PROMOTIONAL_CLAIMS = ( "statuses pass through verbatim", "statuses pass through unchanged and never inflate", @@ -200,6 +211,142 @@ def _python_constants(path: Path, required: set[str]) -> dict[str, object]: return values +def _python_frozenset_constants( + path: Path, required: set[str] +) -> dict[str, frozenset[str]]: + try: + tree = ast.parse(_read_text(path), filename=str(path)) + except SyntaxError as error: + refuse("python-parse", f"{path}: {error}") + values: dict[str, frozenset[str]] = {} + for node in tree.body: + if not isinstance(node, (ast.Assign, ast.AnnAssign)): + continue + targets = node.targets if isinstance(node, ast.Assign) else [node.target] + for target in targets: + if not isinstance(target, ast.Name) or target.id not in required: + continue + if target.id in values: + refuse("python-constant", f"{path} repeats {target.id}") + call = node.value + if ( + not isinstance(call, ast.Call) + or not isinstance(call.func, ast.Name) + or call.func.id != "frozenset" + or len(call.args) != 1 + or call.keywords + or not isinstance(call.args[0], (ast.Set, ast.List, ast.Tuple)) + ): + refuse( + "python-constant", + f"{path} {target.id} is not a literal frozenset", + ) + items = call.args[0].elts + strings = [ + item.value + for item in items + if isinstance(item, ast.Constant) and isinstance(item.value, str) + ] + if len(strings) != len(items) or len(strings) != len(set(strings)): + refuse( + "python-constant", + f"{path} {target.id} has non-string or duplicate members", + ) + invalid = sorted(value for value in strings if TOOL_NAME.fullmatch(value) is None) + if invalid: + refuse( + "python-constant", + f"{path} {target.id} has invalid tool names {invalid}", + ) + values[target.id] = frozenset(strings) + missing = sorted(required - set(values)) + if missing: + refuse("python-constant", f"{path} lacks constants {missing}") + return values + + +def _verify_backend_result_mechanism(path: Path, source: str) -> None: + try: + tree = ast.parse(source, filename=str(path)) + except SyntaxError as error: + refuse("python-parse", f"{path}: {error}") + functions = [ + node + for node in tree.body + if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)) + and node.name == "backend_result" + ] + if len(functions) != 1: + refuse("adapter-mechanism", "Codex adapter must define backend_result once") + function = functions[0] + + def assigned_name(node: ast.stmt, name: str) -> ast.expr | None: + if not isinstance(node, ast.Assign) or len(node.targets) != 1: + return None + target = node.targets[0] + return node.value if isinstance(target, ast.Name) and target.id == name else None + + deep_copy_indices: list[int] = [] + pop_indices: list[int] = [] + return_indices: list[int] = [] + for index, node in enumerate(function.body): + structured_value = assigned_name(node, "structured") + if ( + isinstance(structured_value, ast.Call) + and isinstance(structured_value.func, ast.Attribute) + and isinstance(structured_value.func.value, ast.Name) + and structured_value.func.value.id == "copy" + and structured_value.func.attr == "deepcopy" + and len(structured_value.args) == 1 + and isinstance(structured_value.args[0], ast.Name) + and structured_value.args[0].id == "value" + and not structured_value.keywords + ): + deep_copy_indices.append(index) + + content_value = assigned_name(node, "raw_content") + if ( + isinstance(content_value, ast.Call) + and isinstance(content_value.func, ast.Attribute) + and isinstance(content_value.func.value, ast.Name) + and content_value.func.value.id == "structured" + and content_value.func.attr == "pop" + and len(content_value.args) == 2 + and isinstance(content_value.args[0], ast.Constant) + and content_value.args[0].value == "_mcp_content" + and isinstance(content_value.args[1], ast.Constant) + and content_value.args[1].value is None + and not content_value.keywords + ): + pop_indices.append(index) + + if isinstance(node, ast.Return) and isinstance(node.value, ast.Dict): + pairs = { + key.value: value + for key, value in zip(node.value.keys, node.value.values) + if isinstance(key, ast.Constant) and isinstance(key.value, str) + } + if ( + set(pairs) == {"content", "structuredContent"} + and isinstance(pairs["content"], ast.Name) + and pairs["content"].id == "content" + and isinstance(pairs["structuredContent"], ast.Name) + and pairs["structuredContent"].id == "structured" + ): + return_indices.append(index) + if ( + len(deep_copy_indices) != 1 + or len(pop_indices) != 1 + or len(return_indices) != 1 + or not deep_copy_indices[0] < pop_indices[0] < return_indices[0] + ): + refuse( + "adapter-mechanism", + "backend_result must deep-copy the result, extract only _mcp_content, " + "and return the remaining object as structuredContent", + ) + + def _current_surface_block(path: Path) -> str: text = _read_text(path) if text.count(CURRENT_SURFACE_BEGIN) != 1 or text.count(CURRENT_SURFACE_END) != 1: @@ -256,27 +403,72 @@ def _verify_package_pin(root: Path, version: str) -> dict[str, object]: return constants -def _verify_codex_adapter(root: Path, expected_count: int) -> int: +def _verify_codex_adapter( + root: Path, expected_count: int, runtime_names: set[str] +) -> tuple[int, set[str]]: server_path = root / CODEX_SERVER_PATH - constants = _python_constants(server_path, {"EXPECTED_TOOL_COUNT"}) + constants = _python_constants( + server_path, + { + "EXPECTED_TOOL_COUNT", + "EXPECTED_MEASUREMENT_TOOL_COUNT", + "EXPECTED_ADVANCED_TOOL_COUNT", + "EXPECTED_STEM_TOOL_COUNT", + "EXPECTED_UNIFIED_TOOL_COUNT", + }, + ) observed = constants["EXPECTED_TOOL_COUNT"] if observed != expected_count: refuse( "codex-tool-count", f"wrapper EXPECTED_TOOL_COUNT={observed!r} inventory={expected_count}", ) + groups = _python_frozenset_constants( + server_path, + {"MEASUREMENT_TOOL_NAMES", "ADVANCED_TOOL_NAMES", "STEM_TOOL_NAMES"}, + ) + count_bindings = { + "MEASUREMENT_TOOL_NAMES": "EXPECTED_MEASUREMENT_TOOL_COUNT", + "ADVANCED_TOOL_NAMES": "EXPECTED_ADVANCED_TOOL_COUNT", + "STEM_TOOL_NAMES": "EXPECTED_STEM_TOOL_COUNT", + } + additive_names: set[str] = set() + for group_name, count_name in count_bindings.items(): + names = groups[group_name] + if len(names) != constants[count_name]: + refuse( + "codex-tool-count", + f"{group_name} has {len(names)} names but {count_name}=" + f"{constants[count_name]!r}", + ) + overlap = sorted(additive_names & names) + if overlap: + refuse("codex-tool-count", f"additive tool groups overlap at {overlap}") + additive_names.update(names) + runtime_overlap = sorted(runtime_names & additive_names) + if runtime_overlap: + refuse("codex-tool-count", f"runtime and additive tools overlap at {runtime_overlap}") + unified_names = runtime_names | additive_names + unified_count = constants["EXPECTED_UNIFIED_TOOL_COUNT"] + if len(unified_names) != unified_count: + refuse( + "codex-tool-count", + f"wrapper EXPECTED_UNIFIED_TOOL_COUNT={unified_count!r} " + f"but the disjoint roster has {len(unified_names)} names", + ) source = _read_text(server_path) - for required in ( - '"structuredContent": copy.deepcopy(value)', - 'return backend_result({"status": "refused", "reason": "plugin-busy"})', - ): - if required not in source: - refuse("adapter-mechanism", f"Codex adapter lacks {required!r}") - return int(observed) + _verify_backend_result_mechanism(server_path, source) + busy_refusal = 'return backend_result({"status": "refused", "reason": "plugin-busy"})' + if busy_refusal not in source: + refuse("adapter-mechanism", f"Codex adapter lacks {busy_refusal!r}") + return int(unified_count), additive_names def _verify_plugin_metadata( - root: Path, expected_count: int, status_vocabulary: set[str] + root: Path, + expected_count: int, + unified_count: int, + status_vocabulary: set[str], ) -> str: manifest = _load_json(root / PLUGIN_MANIFEST_PATH) interface = manifest.get("interface") @@ -285,10 +477,15 @@ def _verify_plugin_metadata( description = interface.get("longDescription") if not isinstance(description, str): refuse("plugin-metadata", "plugin longDescription is not a string") - if f"{expected_count}-tool" not in description: + if f"sealed {expected_count}-tool" not in description: refuse( "current-tool-count", - f"plugin longDescription does not state {expected_count}-tool", + f"plugin longDescription does not state sealed {expected_count}-tool", + ) + if f"unified {unified_count}-tool" not in description: + refuse( + "current-tool-count", + f"plugin longDescription does not state unified {unified_count}-tool", ) if "v1.7.3 release runtime" not in description: refuse("current-release-state", "plugin metadata does not identify release state") @@ -330,10 +527,10 @@ def _verify_current_surfaces(root: Path, expected_count: int) -> list[tuple[Path "current-tool-count", f"{relative} current block does not state {expected_count}-tool", ) - if "v1.7.3 release" not in block: + if "v1.7.3" not in block or "release" not in block: refuse( "current-release-state", - f"{relative} current block does not state v1.7.3 release", + f"{relative} current block does not state the v1.7.3 release", ) if "release/capability_inventory_v1.json" not in block: refuse( @@ -369,13 +566,18 @@ def verify_surface(root: Path | str) -> dict[str, object]: names = [row.get("name") for row in records if isinstance(row, dict)] if len(names) != expected_count or len(set(names)) != expected_count: refuse("inventory-contract", "inventory tool names are missing or duplicated") - known_names = set(names) - status_vocabulary = set(vocabulary) + runtime_names = set(names) + status_vocabulary = set(vocabulary) | set(WRAPPER_ONLY_STATUSES) package = _verify_package_pin(root_path, str(release["version"])) - codex_count = _verify_codex_adapter(root_path, expected_count) + codex_count, additive_names = _verify_codex_adapter( + root_path, expected_count, runtime_names + ) + known_names = runtime_names | additive_names blocks = _verify_current_surfaces(root_path, expected_count) - description = _verify_plugin_metadata(root_path, expected_count, status_vocabulary) + description = _verify_plugin_metadata( + root_path, expected_count, codex_count, status_vocabulary + ) skill_text = _read_text(root_path / SKILL_PATH) unknown_skill_names = sorted(skill_tool_names(skill_text) - known_names) diff --git a/tools/hellgate_generate.py b/tools/hellgate_generate.py new file mode 100644 index 0000000..5172cff --- /dev/null +++ b/tools/hellgate_generate.py @@ -0,0 +1,453 @@ +#!/usr/bin/env python3 +"""Generate the fixed HELLGATE nonlinear-ground-state trial certificate. + +This is an untrusted numerical producer. It uses high-precision Taylor +multiple shooting to construct a positive even trial density. The emitted +decimal coefficients are only candidate data; ``mcp/hellgate_verify.py`` +independently reparses them as exact rationals and decides whether they prove +anything. +""" + +from __future__ import annotations + +import argparse +import hashlib +import json +import zlib +import sys +from fractions import Fraction +from pathlib import Path + +import mpmath as mp + + +if hasattr(sys, "set_int_max_str_digits"): + # Exact-rational continuity propagation can legitimately create long + # denominators. This is an offline producer; the verifier has independent + # byte and integer-digit budgets and does not inherit this setting. + sys.set_int_max_str_digits(0) + +mp.mp.dps = 110 + +EPSILON = mp.mpf(1) / 20 +LAMBDA = mp.mpf(7) / 10 +RIGHT = mp.mpf("2.5") +MATCH = mp.mpf("1.7") +SHOOT_STEP = mp.mpf("0.005") +CERT_STEP = mp.mpf("0.01") +SHOOT_DEGREE = 50 +CERT_DEGREE = 38 +TAIL_TERMS = 80 +PARAMETERS = 3 + + +def canonical_bytes(value: object) -> bytes: + return json.dumps( + value, sort_keys=True, separators=(",", ":"), ensure_ascii=False + ).encode("utf-8") + + +def rational_text(value: mp.mpf, digits: int = 60) -> str: + """Round producer data to a decimal that the checker treats as rational.""" + text = mp.nstr(value, digits, strip_zeros=False) + return str(Fraction(text)) + + +def potential_series(origin: mp.mpf, degree: int) -> mp.mpf: + value = mp.mpf(0) + if degree <= 6: + value += mp.binomial(6, degree) * origin ** (6 - degree) + if degree <= 4: + value -= 5 * mp.binomial(4, degree) * origin ** (4 - degree) + if degree <= 2: + value += 4 * mp.binomial(2, degree) * origin ** (2 - degree) + return value + + +def convolution(left: list[mp.mpf], right: list[mp.mpf], degree: int) -> mp.mpf: + return mp.fsum(left[index] * right[degree - index] for index in range(degree + 1)) + + +def taylor_coefficients( + state: tuple[mp.mpf, ...], origin: mp.mpf, eigenvalue: mp.mpf, degree: int +) -> tuple[list[mp.mpf], list[mp.mpf], list[mp.mpf], list[list[mp.mpf]], list[list[mp.mpf]], list[list[mp.mpf]]]: + q = [state[0]] + [mp.mpf(0)] * degree + w = [state[1]] + [mp.mpf(0)] * degree + mass = [state[2]] + [mp.mpf(0)] * degree + q_sens: list[list[mp.mpf]] = [] + w_sens: list[list[mp.mpf]] = [] + mass_sens: list[list[mp.mpf]] = [] + for parameter in range(PARAMETERS): + offset = 3 + 3 * parameter + q_sens.append([state[offset]] + [mp.mpf(0)] * degree) + w_sens.append([state[offset + 1]] + [mp.mpf(0)] * degree) + mass_sens.append([state[offset + 2]] + [mp.mpf(0)] * degree) + density = [mp.exp(q[0])] + [mp.mpf(0)] * degree + + for order in range(degree): + divisor = order + 1 + q[divisor] = 2 * w[order] / divisor + w[divisor] = ( + ( + potential_series(origin, order) + + LAMBDA * density[order] + - (eigenvalue if order == 0 else 0) + ) + / (EPSILON * EPSILON) + - convolution(w, w, order) + ) / divisor + mass[divisor] = density[order] / divisor + + for parameter in range(PARAMETERS): + q_sens[parameter][divisor] = 2 * w_sens[parameter][order] / divisor + eigen_source = -1 if parameter == 2 and order == 0 else 0 + w_sens[parameter][divisor] = ( + ( + LAMBDA + * convolution(density, q_sens[parameter], order) + + eigen_source + ) + / (EPSILON * EPSILON) + - 2 * convolution(w, w_sens[parameter], order) + ) / divisor + mass_sens[parameter][divisor] = convolution( + density, q_sens[parameter], order + ) / divisor + + density[divisor] = mp.fsum( + index * q[index] * density[divisor - index] + for index in range(1, divisor + 1) + ) / divisor + + return q, w, mass, q_sens, w_sens, mass_sens + + +def evaluate(coefficients: list[mp.mpf], step: mp.mpf) -> mp.mpf: + value = mp.mpf(0) + for coefficient in reversed(coefficients): + value = value * step + coefficient + return value + + +def advance( + state: tuple[mp.mpf, ...], origin: mp.mpf, step: mp.mpf, eigenvalue: mp.mpf, degree: int +) -> tuple[mp.mpf, ...]: + q, w, mass, q_sens, w_sens, mass_sens = taylor_coefficients( + state, origin, eigenvalue, degree + ) + result = [evaluate(q, step), evaluate(w, step), evaluate(mass, step)] + for parameter in range(PARAMETERS): + result.extend( + [ + evaluate(q_sens[parameter], step), + evaluate(w_sens[parameter], step), + evaluate(mass_sens[parameter], step), + ] + ) + return tuple(result) + + +def integrate( + start: mp.mpf, + stop: mp.mpf, + state: tuple[mp.mpf, ...], + eigenvalue: mp.mpf, + *, + step: mp.mpf = SHOOT_STEP, + degree: int = SHOOT_DEGREE, +) -> tuple[mp.mpf, ...]: + direction = 1 if stop >= start else -1 + signed_step = direction * abs(step) + position = start + while direction * (stop - position) > 0: + current = signed_step + if direction * (position + current - stop) > 0: + current = stop - position + state = advance(state, position, current, eigenvalue, degree) + position += current + return state + + +def potential(x: mp.mpf) -> mp.mpf: + return x**6 - 5 * x**4 + 4 * x**2 + + +def potential_derivative(x: mp.mpf) -> mp.mpf: + return 6 * x**5 - 20 * x**3 + 8 * x + + +def tail_coefficients(eigenvalue: mp.mpf, count: int) -> list[mp.mpf]: + """Formal decaying Riccati coefficients w=sum a_k*x^(3-2k).""" + epsilon = EPSILON + coefficients: list[mp.mpf] = [] + for index in range(count): + potential_coefficient = mp.mpf(0) + if index == 0: + potential_coefficient = 1 + elif index == 1: + potential_coefficient = -5 + elif index == 2: + potential_coefficient = 4 + elif index == 3: + potential_coefficient = -eigenvalue + derivative = mp.mpf(0) + prior = index - 2 + if prior >= 0: + derivative = -epsilon * epsilon * coefficients[prior] * (3 - 2 * prior) + known_square = mp.fsum( + coefficients[left] * coefficients[index - left] + for left in range(1, index) + ) + if index == 0: + coefficient = mp.mpf(-20) + else: + coefficient = ( + potential_coefficient + + derivative + - epsilon * epsilon * known_square + ) / (2 * epsilon * epsilon * coefficients[0]) + coefficients.append(coefficient) + return coefficients + + +def tail_value(eigenvalue: mp.mpf) -> mp.mpf: + coefficients = tail_coefficients(eigenvalue, TAIL_TERMS) + return mp.fsum( + coefficient * RIGHT ** (3 - 2 * index) + for index, coefficient in enumerate(coefficients) + ) + + +def tail_value_derivative(eigenvalue: mp.mpf) -> mp.mpf: + return mp.diff(tail_value, eigenvalue) + + +def solve_parameters() -> tuple[mp.mpf, mp.mpf, mp.mpf]: + left_q = mp.mpf("-120.048245944203569382657017663048096374") + right_q = mp.mpf("-116.633507058547647528503576301885412018") + eigenvalue = mp.mpf("-4.615978698574496507441387083141344198") + + for _ in range(9): + forward = ( + left_q, + mp.mpf(0), + mp.mpf(0), + mp.mpf(1), 0, 0, + 0, 0, 0, + 0, 0, 0, + ) + backward = ( + right_q, + tail_value(eigenvalue), + mp.mpf(0), + 0, 0, 0, + mp.mpf(1), 0, 0, + 0, tail_value_derivative(eigenvalue), 0, + ) + left = integrate(mp.mpf(0), MATCH, forward, eigenvalue) + right = integrate(RIGHT, MATCH, backward, eigenvalue) + residual = mp.matrix( + [left[0] - right[0], left[1] - right[1], left[2] - right[2] - mp.mpf("0.5")] + ) + jacobian = mp.matrix(PARAMETERS, PARAMETERS) + for parameter in range(PARAMETERS): + jacobian[0, parameter] = left[3 + 3 * parameter] - right[3 + 3 * parameter] + jacobian[1, parameter] = left[4 + 3 * parameter] - right[4 + 3 * parameter] + jacobian[2, parameter] = left[5 + 3 * parameter] - right[5 + 3 * parameter] + correction = mp.lu_solve(jacobian, -residual) + left_q += correction[0] + right_q += correction[1] + eigenvalue += correction[2] + if max(abs(value) for value in residual) < mp.mpf("1e-90"): + break + return left_q, right_q, eigenvalue + + +def q_piece( + state: tuple[mp.mpf, ...], origin: mp.mpf, step: mp.mpf, eigenvalue: mp.mpf +) -> tuple[list[mp.mpf], list[mp.mpf], tuple[mp.mpf, ...]]: + q, *_ = taylor_coefficients(state, origin, eigenvalue, CERT_DEGREE) + density = [mp.exp(q[0])] + [mp.mpf(0)] * CERT_DEGREE + for order in range(1, CERT_DEGREE + 1): + density[order] = mp.fsum( + index * q[index] * density[order - index] + for index in range(1, order + 1) + ) / order + scaled_q = [coefficient * step**index for index, coefficient in enumerate(q)] + scaled_density = [ + coefficient * step**index for index, coefficient in enumerate(density) + ] + return ( + scaled_q, + scaled_density, + advance(state, origin, step, eigenvalue, CERT_DEGREE), + ) + + +def polynomial_value(coefficients: list[Fraction]) -> Fraction: + return sum(coefficients, Fraction(0)) + + +def polynomial_derivative_at_one(coefficients: list[Fraction]) -> Fraction: + return sum( + Fraction(index) * coefficient + for index, coefficient in enumerate(coefficients) + if index + ) + + +def quantize_piece(coefficients: list[mp.mpf]) -> list[Fraction]: + return [Fraction(rational_text(value)) for value in coefficients] + + +def build_chain( + start: mp.mpf, + stop: mp.mpf, + q_value: mp.mpf, + w_value: mp.mpf, + eigenvalue: mp.mpf, +) -> list[dict[str, object]]: + direction = 1 if stop >= start else -1 + count = int(mp.nint(abs((stop - start) / CERT_STEP))) + if count < 1: + raise RuntimeError("certificate chain must contain at least one piece") + step = (stop - start) / count + state: tuple[mp.mpf, ...] = ( + q_value, w_value, mp.mpf(0), + 0, 0, 0, 0, 0, 0, 0, 0, 0, + ) + pieces: list[dict[str, object]] = [] + prior_value: Fraction | None = None + prior_derivative: Fraction | None = None + for index in range(count): + position = start + index * step + current = step + raw, raw_density, state = q_piece(state, position, current, eigenvalue) + coefficients = quantize_piece(raw) + density_coefficients = quantize_piece(raw_density) + if prior_value is not None and prior_derivative is not None: + coefficients[0] = prior_value + coefficients[1] = Fraction(rational_text(current)) * prior_derivative + elif position == 0: + coefficients[1] = Fraction(0) + value_at_end = polynomial_value(coefficients) + derivative_at_end = polynomial_derivative_at_one(coefficients) / Fraction( + rational_text(current) + ) + pieces.append( + { + "origin": rational_text(position), + "step": rational_text(current), + "coefficients": [str(value) for value in coefficients], + "density_coefficients": [ + str(value) for value in density_coefficients + ], + } + ) + prior_value = value_at_end + prior_derivative = derivative_at_end + return pieces + + +def join_chains(forward: list[dict[str, object]], backward: list[dict[str, object]]) -> None: + left = forward[-1] + right = backward[-1] + left_coefficients = [Fraction(value) for value in left["coefficients"]] # type: ignore[index] + right_coefficients = [Fraction(value) for value in right["coefficients"]] # type: ignore[index] + left_step = Fraction(left["step"]) # type: ignore[arg-type] + right_step = Fraction(right["step"]) # type: ignore[arg-type] + left_value = polynomial_value(left_coefficients) + left_slope_s = polynomial_derivative_at_one(left_coefficients) + right_value = polynomial_value(right_coefficients) + right_slope_x = polynomial_derivative_at_one(right_coefficients) / right_step + value_delta = right_value - left_value + slope_delta = left_step * right_slope_x - left_slope_s + left_coefficients[2] += 3 * value_delta - slope_delta + left_coefficients[3] += slope_delta - 2 * value_delta + left["coefficients"] = [str(value) for value in left_coefficients] + + +def bind_backward_tail_and_continuity( + backward: list[dict[str, object]], tail: list[Fraction] +) -> None: + right = Fraction(5, 2) + tail_w = sum( + ( + coefficient * right ** (3 - 2 * index) + for index, coefficient in enumerate(tail) + ), + Fraction(0), + ) + prior_value: Fraction | None = None + prior_derivative: Fraction | None = None + for index, piece in enumerate(backward): + coefficients = [Fraction(value) for value in piece["coefficients"]] # type: ignore[index] + step = Fraction(piece["step"]) # type: ignore[arg-type] + if index == 0: + coefficients[1] = step * 2 * tail_w + else: + assert prior_value is not None and prior_derivative is not None + coefficients[0] = prior_value + coefficients[1] = step * prior_derivative + prior_value = polynomial_value(coefficients) + prior_derivative = polynomial_derivative_at_one(coefficients) / step + piece["coefficients"] = [str(value) for value in coefficients] + + +def generate() -> dict[str, object]: + left_q, right_q, eigenvalue = solve_parameters() + eigenvalue_fraction = Fraction(rational_text(eigenvalue)) + tail_fraction = [ + Fraction(rational_text(value)) + for value in tail_coefficients(eigenvalue, TAIL_TERMS) + ] + tail_fraction[:3] = [Fraction(-20), Fraction(50), Fraction(21)] + forward = build_chain(mp.mpf(0), MATCH, left_q, mp.mpf(0), eigenvalue) + backward = build_chain( + RIGHT, MATCH, right_q, tail_value(eigenvalue), eigenvalue + ) + bind_backward_tail_and_continuity(backward, tail_fraction) + join_chains(forward, backward) + document: dict[str, object] = { + "schema": "jackal-hellgate-barta-certificate-v1", + "problem": { + "epsilon": "1/20", + "lambda": "7/10", + "potential": "x^6-5*x^4+4*x^2", + "mass": "1", + "parity": "even", + "positivity": "strict", + }, + "representation": "piecewise-log-density-power-v1", + "center_eigenvalue": str(eigenvalue_fraction), + "right_endpoint": rational_text(RIGHT), + "match_point": rational_text(MATCH), + "tail_terms": TAIL_TERMS, + "tail_coefficients": [str(value) for value in tail_fraction], + "forward_pieces": forward, + "backward_pieces": backward, + "nonclaims": [ + "producer arithmetic is untrusted until independent exact-rational replay accepts", + "certificate is specific to the declared HELLGATE parameters", + "bounded is not formal-bounded; no Lean theorem checks this certificate", + ], + } + document["certificate_sha256"] = hashlib.sha256(canonical_bytes(document)).hexdigest() + return document + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument("output", type=Path) + arguments = parser.parse_args() + document = generate() + payload = canonical_bytes(document) + b"\n" + if arguments.output.suffix == ".zlib": + payload = zlib.compress(payload, 9) + arguments.output.write_bytes(payload) + print(document["certificate_sha256"]) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tools/hellgate_trial_oracle.py b/tools/hellgate_trial_oracle.py new file mode 100644 index 0000000..422b2ca --- /dev/null +++ b/tools/hellgate_trial_oracle.py @@ -0,0 +1,166 @@ +#!/usr/bin/env python3 -B +"""Untrusted high-precision differential oracle for the HELLGATE trial. + +This module is intentionally outside the certificate decision path. It +numerically integrates the encoded piecewise log density with mpmath so tests +can detect disagreement between an independent floating-point path and the +exact-rational verifier. Its output is never evidence and never upgrades a +JACKAL status. +""" + +from __future__ import annotations + +import argparse +import json +import zlib +from pathlib import Path + +import mpmath as mp + + +def _mp_rational(token: str) -> mp.mpf: + numerator, separator, denominator = token.partition("/") + if separator: + return mp.mpf(numerator) / mp.mpf(denominator) + return mp.mpf(numerator) + + +def _evaluate(coefficients: list[mp.mpf], point: mp.mpf) -> mp.mpf: + value = mp.mpf(0) + for coefficient in reversed(coefficients): + value = value * point + coefficient + return value + + +def compute_oracle( + document: dict[str, object], *, decimal_places: int = 80, quadrature_order: int = 24 +) -> dict[str, object]: + """Return an unverified numerical differential oracle for one certificate.""" + mp.mp.dps = decimal_places + nodes, weights = mp.gauss_quadrature(quadrature_order, "legendre") + raw = { + key: mp.mpf(0) + for key in ("mass", "quartic", "x2", "x4", "x6", "q_derivative_squared") + } + pieces = document["forward_pieces"] + document["backward_pieces"] + for piece in pieces: + origin = _mp_rational(piece["origin"]) + step = _mp_rational(piece["step"]) + coefficients = [_mp_rational(item) for item in piece["coefficients"]] + derivative = [ + (index + 1) * coefficients[index + 1] / step + for index in range(len(coefficients) - 1) + ] + for node, weight in zip(nodes, weights, strict=True): + unit_point = (node + 1) / 2 + physical_weight = weight * abs(step) / 2 + x_value = origin + step * unit_point + q_value = _evaluate(coefficients, unit_point) + density = mp.exp(q_value) + q_derivative = _evaluate(derivative, unit_point) + raw["mass"] += physical_weight * density + raw["quartic"] += physical_weight * density * density + raw["x2"] += physical_weight * x_value**2 * density + raw["x4"] += physical_weight * x_value**4 * density + raw["x6"] += physical_weight * x_value**6 * density + raw["q_derivative_squared"] += ( + physical_weight * q_derivative * q_derivative * density + ) + + right = _mp_rational(document["right_endpoint"]) + tail = [_mp_rational(item) for item in document["tail_coefficients"]] + tail_q = _mp_rational(document["backward_pieces"][0]["coefficients"][0]) + + def tail_w(x_value: mp.mpf) -> mp.mpf: + return mp.fsum( + coefficient * x_value ** (3 - 2 * index) + for index, coefficient in enumerate(tail) + ) + + def tail_log_density(x_value: mp.mpf) -> mp.mpf: + value = tail_q + for index, coefficient in enumerate(tail): + power = 3 - 2 * index + if power == -1: + value += 2 * coefficient * mp.log(x_value / right) + else: + value += ( + 2 + * coefficient + * (x_value ** (power + 1) - right ** (power + 1)) + / (power + 1) + ) + return value + + def tail_integral(quantity: str) -> mp.mpf: + def integrand(x_value: mp.mpf) -> mp.mpf: + density = mp.exp(tail_log_density(x_value)) + if quantity == "mass": + return density + if quantity == "quartic": + return density * density + if quantity == "q_derivative_squared": + return 4 * tail_w(x_value) ** 2 * density + return x_value ** int(quantity[1:]) * density + + return mp.quad( + integrand, + [right, right + mp.mpf("0.25"), right + 1, mp.inf], + ) + + for quantity in raw: + raw[quantity] = 2 * (raw[quantity] + tail_integral(quantity)) + + normalization = raw["mass"] + quartic = raw["quartic"] / normalization**2 + moments = { + key: raw[key] / normalization + for key in ("x2", "x4", "x6") + } + # JACKAL exact: parsed=(1/20)^2/4; exact=1/1600; status=exact (not formal). + kinetic = raw["q_derivative_squared"] / normalization / 1600 + potential = moments["x6"] - 5 * moments["x4"] + 4 * moments["x2"] + energy = kinetic + potential + mp.mpf(7) * quartic / 20 + eigenvalue_from_energy = energy + mp.mpf(7) * quartic / 20 + virial = ( + 2 * kinetic + - 6 * moments["x6"] + + 20 * moments["x4"] + - 8 * moments["x2"] + + mp.mpf(7) * quartic / 20 + ) + + def render(value: mp.mpf) -> str: + return mp.nstr(value, decimal_places - 20, strip_zeros=False) + + return { + "schema": "jackal-hellgate-untrusted-trial-oracle-v1", + "status": "unverified-numerical-oracle", + "fields": { + "normalization": render(normalization), + "quartic_norm": render(quartic), + "moments": {key: render(value) for key, value in moments.items()}, + "kinetic_energy": render(kinetic), + "energy_functional": render(energy), + "eigenvalue_from_energy": render(eigenvalue_from_energy), + "virial_residual": render(virial), + }, + "non_claims": [ + "mpmath floating-point quadrature is an untrusted test oracle, not certificate evidence", + "agreement with the exact-rational checker does not upgrade bounded to formal-bounded", + ], + } + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument("certificate", type=Path) + arguments = parser.parse_args() + raw = zlib.decompress(arguments.certificate.read_bytes()) + document = json.loads(raw) + print(json.dumps(compute_oracle(document), sort_keys=True, separators=(",", ":"))) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) From 9749a1985d54147f3ef36eb98694e12665749865 Mon Sep 17 00:00:00 2001 From: sicarii Date: Sat, 29 Aug 2026 01:19:56 -0400 Subject: [PATCH 17/22] Test unreleased Hermes bytes with a local package pin --- tests/anubis_program_verifier_test.py | 68 +++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 4 deletions(-) diff --git a/tests/anubis_program_verifier_test.py b/tests/anubis_program_verifier_test.py index 3bf4e8c..f45257d 100755 --- a/tests/anubis_program_verifier_test.py +++ b/tests/anubis_program_verifier_test.py @@ -4,6 +4,7 @@ import ast import hashlib import json +import shutil import subprocess import sys import tempfile @@ -14,6 +15,11 @@ ROOT = Path(__file__).resolve().parents[1] VERIFIER = ROOT / "tools/anubis_program_verify.py" POLICY_PATH = ROOT / "release/program/inventory_safe_v1.json" +PLUGIN_DIR = ROOT / "plugin/hermes" +sys.path.insert(0, str(PLUGIN_DIR)) + +from bundle_hash import compute_bundle_hash, resolve_runtime_files # noqa: E402 + VERIFY_TIME = "1787097600" APPROVED_CHECK_COMPILER_SHA256 = ( "0d6a8f89355eb9ec5971749daf943567c204ed9f2d3001edbd46599f4540d7d6" @@ -87,6 +93,59 @@ def compact(value: object) -> bytes: POLICY_SHA256 = sha(compact(POLICY_BODY)) +def materialize_current_hermes_test_repo(root: Path) -> Path: + """Build a self-consistent repository-layout package for plugin tests. + + Development changes intentionally do not rewrite the immutable published + ``release/MANIFEST.sha256`` in the source tree. A success-path plugin test + therefore has to exercise freshly assembled bytes with a package-local pin, + exactly as a release package builder does. This helper never weakens the + launcher's startup gate and never edits the published manifest. + """ + package_root = root / "current-hermes-test-package" + package_plugin = package_root / "plugin/hermes" + for source in resolve_runtime_files(PLUGIN_DIR).values(): + relative = source.resolve().relative_to(ROOT) + destination = package_root / relative + destination.parent.mkdir(parents=True, exist_ok=True) + shutil.copy2(source, destination) + + required_artifacts = ( + ROOT / "release/MANIFEST.sha256", + ROOT / "jackal-native", + ROOT / "jackal_calc.anb", + ROOT / "proofs/lean/.lake/build/bin/jackal_cert_check", + ROOT / "proofs/lean/.lake/build/bin/jackal_gaussian_check", + ROOT / "proofs/lean/.lake/build/bin/jackal_int_cert_check", + ROOT / "release/evidence/approved_z3.linux-aarch64", + ) + for source in required_artifacts: + if not source.is_file(): + raise RuntimeError(f"current Hermes test artifact missing: {source}") + relative = source.resolve().relative_to(ROOT) + destination = package_root / relative + destination.parent.mkdir(parents=True, exist_ok=True) + shutil.copy2(source, destination) + + package_hash = compute_bundle_hash(package_plugin) + package_manifest = package_root / "release/MANIFEST.sha256" + verifier_hash = sha( + (package_root / "tools/anubis_program_verify.py").read_bytes() + ) + pinned_lines = [] + for line in package_manifest.read_text(encoding="utf-8").splitlines(): + if line.startswith("plugin_hermes "): + line = f"plugin_hermes {package_hash}" + elif line.startswith("anubis_program_verifier "): + fields = line.split() + line = f"{fields[0]} {fields[1]} {verifier_hash}" + pinned_lines.append(line) + package_manifest.write_text( + "\n".join(pinned_lines) + "\n", encoding="utf-8" + ) + return package_plugin / "jackal_hermes" + + def dump(path: Path, value: object) -> None: path.parent.mkdir(parents=True, exist_ok=True) path.write_text( @@ -803,9 +862,11 @@ def test_v3_inventory_profile_verifies_replays_and_never_executes_artifact(self) def test_plugin_program_success_statuses_exit_zero(self) -> None: with tempfile.TemporaryDirectory(prefix="jackal-program-plugin-") as td: + test_root = Path(td) source, evidence, compiler_sha, artifact_sha, marker = make_v3_fixture( - Path(td) + test_root / "fixture" ) + launcher = materialize_current_hermes_test_repo(test_root) arguments = { "source_path": str(source), "evidence_dir": str(evidence), @@ -817,7 +878,6 @@ def test_plugin_program_success_statuses_exit_zero(self) -> None: "profile": "inventory-safe-v1", "nonce": "plugin-exit", } - launcher = ROOT / "plugin/hermes/jackal_hermes" verified = subprocess.run( [ str(launcher), @@ -827,7 +887,7 @@ def test_plugin_program_success_statuses_exit_zero(self) -> None: ], capture_output=True, text=True, - cwd=ROOT, + cwd=launcher.parents[2], timeout=30, ) self.assertEqual( @@ -844,7 +904,7 @@ def test_plugin_program_success_statuses_exit_zero(self) -> None: ], capture_output=True, text=True, - cwd=ROOT, + cwd=launcher.parents[2], timeout=30, ) self.assertEqual(replay.returncode, 0, replay.stdout + replay.stderr) From 369c291663713f564b86da9bbbc385a755e16729 Mon Sep 17 00:00:00 2001 From: sicarii Date: Sat, 29 Aug 2026 01:30:33 -0400 Subject: [PATCH 18/22] Pin the hosted HELLGATE oracle dependency --- .github/workflows/jackal-codex-plugin.yml | 37 +++++++++++++++++++ tests/codex_plugin/test_hellgate.py | 12 ++++++ .../codex_plugin/test_runtime_provisioner.py | 5 ++- 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/.github/workflows/jackal-codex-plugin.yml b/.github/workflows/jackal-codex-plugin.yml index 02f9727..8713fd7 100644 --- a/.github/workflows/jackal-codex-plugin.yml +++ b/.github/workflows/jackal-codex-plugin.yml @@ -10,6 +10,9 @@ permissions: env: PYTHONDONTWRITEBYTECODE: "1" + MPMATH_WHEEL_URL: https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl + MPMATH_WHEEL_SHA256: a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c + MPMATH_WHEEL_SIZE: "536198" jobs: linux-aarch64-plugin: @@ -45,7 +48,24 @@ jobs: tests.capability_inventory_test \ tests.capability_drift_gate_test -v + - name: Fetch exact untrusted HELLGATE oracle dependency + run: | + wheel="$RUNNER_TEMP/mpmath-1.3.0-py3-none-any.whl" + curl --proto '=https' --tlsv1.2 --fail --location --silent --show-error \ + --max-filesize "$MPMATH_WHEEL_SIZE" --output "$wheel" "$MPMATH_WHEEL_URL" + test "$(wc -c < "$wheel" | tr -d '[:space:]')" = "$MPMATH_WHEEL_SIZE" + /usr/bin/python3 - "$wheel" "$MPMATH_WHEEL_SHA256" <<'PY' + import hashlib + import pathlib + import sys + actual = hashlib.sha256(pathlib.Path(sys.argv[1]).read_bytes()).hexdigest() + if actual != sys.argv[2]: + raise SystemExit("mpmath wheel digest mismatch") + PY + - name: Run complete Codex plugin unit suite + env: + PYTHONPATH: ${{ runner.temp }}/mpmath-1.3.0-py3-none-any.whl run: /usr/bin/python3 -B -m unittest discover -s tests/codex_plugin -v - name: Verify exact plugin identity @@ -87,7 +107,24 @@ jobs: tests.capability_inventory_test \ tests.capability_drift_gate_test -v + - name: Fetch exact untrusted HELLGATE oracle dependency + run: | + wheel="$RUNNER_TEMP/mpmath-1.3.0-py3-none-any.whl" + curl --proto '=https' --tlsv1.2 --fail --location --silent --show-error \ + --max-filesize "$MPMATH_WHEEL_SIZE" --output "$wheel" "$MPMATH_WHEEL_URL" + test "$(wc -c < "$wheel" | tr -d '[:space:]')" = "$MPMATH_WHEEL_SIZE" + /opt/homebrew/bin/python3 - "$wheel" "$MPMATH_WHEEL_SHA256" <<'PY' + import hashlib + import pathlib + import sys + actual = hashlib.sha256(pathlib.Path(sys.argv[1]).read_bytes()).hexdigest() + if actual != sys.argv[2]: + raise SystemExit("mpmath wheel digest mismatch") + PY + - name: Run complete Codex plugin unit suite + env: + PYTHONPATH: ${{ runner.temp }}/mpmath-1.3.0-py3-none-any.whl run: /opt/homebrew/bin/python3 -B -m unittest discover -s tests/codex_plugin -v - name: Verify exact plugin identity diff --git a/tests/codex_plugin/test_hellgate.py b/tests/codex_plugin/test_hellgate.py index 1a74337..557beb7 100644 --- a/tests/codex_plugin/test_hellgate.py +++ b/tests/codex_plugin/test_hellgate.py @@ -17,6 +17,7 @@ REPO_ROOT / "plugins/jackel/mcp/certificates/hellgate_v1.json.zlib" ) CHECKER_PATH = REPO_ROOT / "plugins/jackel/mcp/hellgate_verify.py" +PLUGIN_WORKFLOW_PATH = REPO_ROOT / ".github/workflows/jackal-codex-plugin.yml" def canonical_bytes(value): @@ -109,6 +110,17 @@ def assert_inside(interval, point): ) ) + def test_hosted_oracle_dependency_is_content_pinned(self): + workflow = PLUGIN_WORKFLOW_PATH.read_text(encoding="utf-8") + for token in ( + "mpmath-1.3.0-py3-none-any.whl", + "a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", + 'MPMATH_WHEEL_SIZE: "536198"', + '--max-filesize "$MPMATH_WHEEL_SIZE"', + "mpmath wheel digest mismatch", + ): + self.assertIn(token, workflow) + def test_ground_transfer_is_narrow_bounded_and_does_not_launder_moments(self): fields = self.result["fields"] trial = fields["trial_diagnostics"] diff --git a/tests/codex_plugin/test_runtime_provisioner.py b/tests/codex_plugin/test_runtime_provisioner.py index eb91ea6..a8bc753 100644 --- a/tests/codex_plugin/test_runtime_provisioner.py +++ b/tests/codex_plugin/test_runtime_provisioner.py @@ -1051,7 +1051,10 @@ def test_default_snapshot_parent_canonicalizes_the_platform_tmp_symlink(self): with mock.patch.object( provisioner.tempfile, "gettempdir", return_value=str(lexical) ): - self.assertEqual(provisioner._snapshot_parent_path(None), physical) + self.assertEqual( + provisioner._snapshot_parent_path(None), + physical.resolve(strict=True), + ) self.assertEqual( provisioner.reap_orphaned_runtime_snapshots( current_boot_id="fixture-boot", From b0af93a31b7a94851fc1b46fe7fb7fe2158490b7 Mon Sep 17 00:00:00 2001 From: sicarii Date: Sat, 29 Aug 2026 01:33:14 -0400 Subject: [PATCH 19/22] Update the Linux clean-runner refusal contract --- .github/workflows/jackal-codex-plugin.yml | 2 +- tests/codex_plugin/test_plugin_metadata.py | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/jackal-codex-plugin.yml b/.github/workflows/jackal-codex-plugin.yml index 8713fd7..56c9820 100644 --- a/.github/workflows/jackal-codex-plugin.yml +++ b/.github/workflows/jackal-codex-plugin.yml @@ -80,7 +80,7 @@ jobs: set -e printf '%s\n' "$output" test "$status" -eq 1 - printf '%s\n' "$output" | grep -q "no published release asset for host linux-aarch64" + printf '%s\n' "$output" | grep -q "pinned runtime is not installed" macos-arm64-plugin: name: macOS arm64 plugin gates diff --git a/tests/codex_plugin/test_plugin_metadata.py b/tests/codex_plugin/test_plugin_metadata.py index 0437dfa..f9fec30 100644 --- a/tests/codex_plugin/test_plugin_metadata.py +++ b/tests/codex_plugin/test_plugin_metadata.py @@ -670,6 +670,15 @@ def test_hosted_macos_workflow_mechanically_runs_all_repo_local_plugin_gates(sel ): self.assertNotIn(forbidden, smoke_block) + def test_hosted_linux_smoke_requires_the_current_pinned_runtime_refusal(self): + source = WORKFLOW_PATH.read_text(encoding="utf-8") + linux_job = source.split("linux-aarch64-plugin:", 1)[1].split( + "macos-arm64-plugin:", 1 + )[0] + self.assertIn('test "$status" -eq 1', linux_job) + self.assertIn('grep -q "pinned runtime is not installed"', linux_job) + self.assertNotIn("no published release asset", linux_job) + def test_load_json_rejects_duplicate_keys(self): with tempfile.TemporaryDirectory() as temporary_directory: duplicate_json = Path(temporary_directory) / "duplicate.json" From 1e699e23c4d073572f45a548e8dce1a2d25953d0 Mon Sep 17 00:00:00 2001 From: sicarii Date: Sat, 29 Aug 2026 03:05:51 -0400 Subject: [PATCH 20/22] Make SPARK assumption guards syntax robust --- proofs/spark/claim_policy/prove.sh | 7 +--- proofs/spark/hellgate_interval/prove.sh | 7 +--- proofs/spark/reject_assumptions.sh | 21 ++++++++++ tests/claim_policy_conformance_test.py | 5 ++- tests/codex_plugin/test_spark_interval.py | 48 ++++++++++++++++++++++- 5 files changed, 74 insertions(+), 14 deletions(-) create mode 100755 proofs/spark/reject_assumptions.sh diff --git a/proofs/spark/claim_policy/prove.sh b/proofs/spark/claim_policy/prove.sh index 98d64ed..3f5305a 100755 --- a/proofs/spark/claim_policy/prove.sh +++ b/proofs/spark/claim_policy/prove.sh @@ -44,10 +44,7 @@ grep -q 'unit jackal_claim_policy' "$PROOF_REPORT" || { exit 1 } -if rg -n --glob '*.ad?' 'pragma[[:space:]]+(Assume|Annotate)' \ - "$SCRIPT_DIR/src" "$SCRIPT_DIR/tests"; then - echo "refused: proof assumptions or justifications are forbidden" >&2 - exit 1 -fi +"$SCRIPT_DIR/../reject_assumptions.sh" \ + "$SCRIPT_DIR/src" "$SCRIPT_DIR/tests" echo "SPARK_PLATINUM_CLAIM_POLICY_COMPONENT_PROOF_PASS" diff --git a/proofs/spark/hellgate_interval/prove.sh b/proofs/spark/hellgate_interval/prove.sh index d948839..2ef5b56 100755 --- a/proofs/spark/hellgate_interval/prove.sh +++ b/proofs/spark/hellgate_interval/prove.sh @@ -45,10 +45,7 @@ grep -q 'unit jackal_interval_envelope' "$PROOF_REPORT" || { exit 1 } -if rg -n --glob '*.ad?' 'pragma[[:space:]]+(Assume|Annotate)' \ - "$SCRIPT_DIR/src" "$SCRIPT_DIR/tests"; then - echo "refused: proof assumptions or justifications are forbidden" >&2 - exit 1 -fi +"$SCRIPT_DIR/../reject_assumptions.sh" \ + "$SCRIPT_DIR/src" "$SCRIPT_DIR/tests" echo "SPARK_PLATINUM_INTERVAL_COMPONENT_PROOF_PASS" diff --git a/proofs/spark/reject_assumptions.sh b/proofs/spark/reject_assumptions.sh new file mode 100755 index 0000000..e66b50d --- /dev/null +++ b/proofs/spark/reject_assumptions.sh @@ -0,0 +1,21 @@ +#!/bin/sh +set -eu + +if [ "$#" -eq 0 ]; then + echo "refused: no SPARK source roots were supplied" >&2 + exit 1 +fi + +command -v rg >/dev/null 2>&1 || { + echo "refused: rg is unavailable for the SPARK assumption scan" >&2 + exit 1 +} + +# Ada identifiers are case-insensitive and whitespace can span lines. Keep +# this scan multiline and case-insensitive so spelling or formatting cannot +# bypass the no-assumption/no-justification policy. +if rg -n -i -U --glob '*.ad?' \ + 'pragma[[:space:]]+(Assume|Annotate)\b' "$@"; then + echo "refused: proof assumptions or justifications are forbidden" >&2 + exit 1 +fi diff --git a/tests/claim_policy_conformance_test.py b/tests/claim_policy_conformance_test.py index eafa09a..e041a4a 100644 --- a/tests/claim_policy_conformance_test.py +++ b/tests/claim_policy_conformance_test.py @@ -71,8 +71,9 @@ def test_source_keeps_the_declared_formal_boundary(self) -> None: self.assertIn("function Apply_Rule_Caps", text) self.assertIn("function Meet_Artifact", text) self.assertIn("Post =>", text) - self.assertNotIn("pragma Assume", text) - self.assertNotIn("pragma Annotate", text) + lowered = text.lower() + self.assertNotIn("pragma assume", lowered) + self.assertNotIn("pragma annotate", lowered) @unittest.skipUnless( shutil.which("gprbuild") and shutil.which("gnatprove") and shutil.which("rg"), diff --git a/tests/codex_plugin/test_spark_interval.py b/tests/codex_plugin/test_spark_interval.py index d10dae5..247da11 100644 --- a/tests/codex_plugin/test_spark_interval.py +++ b/tests/codex_plugin/test_spark_interval.py @@ -1,11 +1,13 @@ import shutil import subprocess +import tempfile import unittest from pathlib import Path REPO_ROOT = Path(__file__).resolve().parents[2] SPARK_ROOT = REPO_ROOT / "proofs/spark/hellgate_interval" +ASSUMPTION_GUARD = REPO_ROOT / "proofs/spark/reject_assumptions.sh" class SparkIntervalEnvelopeTests(unittest.TestCase): @@ -24,8 +26,50 @@ def test_source_keeps_the_declared_formal_boundary(self): self.assertIn("function Evaluate_Untrusted_Envelope", text) self.assertIn("Required_Verdict", text) self.assertIn("Post =>", text) - self.assertNotIn("pragma Assume", text) - self.assertNotIn("pragma Annotate", text) + lowered = text.lower() + self.assertNotIn("pragma assume", lowered) + self.assertNotIn("pragma annotate", lowered) + + @unittest.skipUnless(shutil.which("rg"), "rg is not installed") + def test_assumption_guard_rejects_case_and_line_break_bypasses(self): + with tempfile.TemporaryDirectory() as raw_directory: + directory = Path(raw_directory) + source = directory / "guard_probe.adb" + source.write_text( + "procedure Guard_Probe is begin null; end Guard_Probe;\n", + encoding="utf-8", + ) + accepted = subprocess.run( + [str(ASSUMPTION_GUARD), str(directory)], + cwd=REPO_ROOT, + check=False, + capture_output=True, + text=True, + ) + self.assertEqual( + accepted.returncode, 0, accepted.stdout + accepted.stderr + ) + + forbidden_pragmas = ( + "pragma aSsUmE (True);", + "pragma\nAnNoTaTe (GNATprove, False_Positive, \"probe\");", + ) + for forbidden in forbidden_pragmas: + with self.subTest(forbidden=forbidden): + source.write_text(forbidden + "\n", encoding="utf-8") + refused = subprocess.run( + [str(ASSUMPTION_GUARD), str(directory)], + cwd=REPO_ROOT, + check=False, + capture_output=True, + text=True, + ) + transcript = refused.stdout + refused.stderr + self.assertNotEqual(refused.returncode, 0, transcript) + self.assertIn( + "proof assumptions or justifications are forbidden", + transcript, + ) @unittest.skipUnless( shutil.which("gprbuild") and shutil.which("gnatprove") and shutil.which("rg"), From fc54d12090637f56ce21c019f4d331fe36a963fc Mon Sep 17 00:00:00 2001 From: sicarii Date: Sat, 29 Aug 2026 03:08:02 -0400 Subject: [PATCH 21/22] Fail closed on GNATprove assumption counts --- proofs/spark/claim_policy/prove.sh | 2 +- proofs/spark/hellgate_interval/prove.sh | 2 +- proofs/spark/reject_assumptions.sh | 17 +++++++++++-- tests/codex_plugin/test_spark_interval.py | 31 +++++++++++++++++++++-- 4 files changed, 46 insertions(+), 6 deletions(-) diff --git a/proofs/spark/claim_policy/prove.sh b/proofs/spark/claim_policy/prove.sh index 3f5305a..17ef849 100755 --- a/proofs/spark/claim_policy/prove.sh +++ b/proofs/spark/claim_policy/prove.sh @@ -45,6 +45,6 @@ grep -q 'unit jackal_claim_policy' "$PROOF_REPORT" || { } "$SCRIPT_DIR/../reject_assumptions.sh" \ - "$SCRIPT_DIR/src" "$SCRIPT_DIR/tests" + "$PROOF_REPORT" "$SCRIPT_DIR/src" "$SCRIPT_DIR/tests" echo "SPARK_PLATINUM_CLAIM_POLICY_COMPONENT_PROOF_PASS" diff --git a/proofs/spark/hellgate_interval/prove.sh b/proofs/spark/hellgate_interval/prove.sh index 2ef5b56..cab8937 100755 --- a/proofs/spark/hellgate_interval/prove.sh +++ b/proofs/spark/hellgate_interval/prove.sh @@ -46,6 +46,6 @@ grep -q 'unit jackal_interval_envelope' "$PROOF_REPORT" || { } "$SCRIPT_DIR/../reject_assumptions.sh" \ - "$SCRIPT_DIR/src" "$SCRIPT_DIR/tests" + "$PROOF_REPORT" "$SCRIPT_DIR/src" "$SCRIPT_DIR/tests" echo "SPARK_PLATINUM_INTERVAL_COMPONENT_PROOF_PASS" diff --git a/proofs/spark/reject_assumptions.sh b/proofs/spark/reject_assumptions.sh index e66b50d..1fe476d 100755 --- a/proofs/spark/reject_assumptions.sh +++ b/proofs/spark/reject_assumptions.sh @@ -1,8 +1,21 @@ #!/bin/sh set -eu -if [ "$#" -eq 0 ]; then - echo "refused: no SPARK source roots were supplied" >&2 +if [ "$#" -lt 2 ]; then + echo "refused: a GNATprove report and SPARK source roots are required" >&2 + exit 1 +fi + +PROOF_REPORT=$1 +shift + +[ -f "$PROOF_REPORT" ] || { + echo "refused: the GNATprove report is not a regular file" >&2 + exit 1 +} + +if grep -Eq '\([1-9][0-9]* pragma Assume statements?\)' "$PROOF_REPORT"; then + echo "refused: GNATprove reports one or more proof assumptions" >&2 exit 1 fi diff --git a/tests/codex_plugin/test_spark_interval.py b/tests/codex_plugin/test_spark_interval.py index 247da11..ce52d0b 100644 --- a/tests/codex_plugin/test_spark_interval.py +++ b/tests/codex_plugin/test_spark_interval.py @@ -35,12 +35,17 @@ def test_assumption_guard_rejects_case_and_line_break_bypasses(self): with tempfile.TemporaryDirectory() as raw_directory: directory = Path(raw_directory) source = directory / "guard_probe.adb" + report = directory / "gnatprove.out" + report.write_text( + "Guard_Probe (0 pragma Assume statements)\n", + encoding="utf-8", + ) source.write_text( "procedure Guard_Probe is begin null; end Guard_Probe;\n", encoding="utf-8", ) accepted = subprocess.run( - [str(ASSUMPTION_GUARD), str(directory)], + [str(ASSUMPTION_GUARD), str(report), str(directory)], cwd=REPO_ROOT, check=False, capture_output=True, @@ -58,7 +63,7 @@ def test_assumption_guard_rejects_case_and_line_break_bypasses(self): with self.subTest(forbidden=forbidden): source.write_text(forbidden + "\n", encoding="utf-8") refused = subprocess.run( - [str(ASSUMPTION_GUARD), str(directory)], + [str(ASSUMPTION_GUARD), str(report), str(directory)], cwd=REPO_ROOT, check=False, capture_output=True, @@ -71,6 +76,28 @@ def test_assumption_guard_rejects_case_and_line_break_bypasses(self): transcript, ) + source.write_text( + "procedure Guard_Probe is begin null; end Guard_Probe;\n", + encoding="utf-8", + ) + report.write_text( + "Guard_Probe (1 pragma Assume statement)\n", + encoding="utf-8", + ) + refused_report = subprocess.run( + [str(ASSUMPTION_GUARD), str(report), str(directory)], + cwd=REPO_ROOT, + check=False, + capture_output=True, + text=True, + ) + report_transcript = refused_report.stdout + refused_report.stderr + self.assertNotEqual(refused_report.returncode, 0, report_transcript) + self.assertIn( + "GNATprove reports one or more proof assumptions", + report_transcript, + ) + @unittest.skipUnless( shutil.which("gprbuild") and shutil.which("gnatprove") and shutil.which("rg"), "GNATprove toolchain is not installed", From 6c733351d996aafdf2e60984376fb25a0a32c27a Mon Sep 17 00:00:00 2001 From: sicarii Date: Sat, 29 Aug 2026 03:11:16 -0400 Subject: [PATCH 22/22] Remove runner dependency from SPARK proof guard --- proofs/spark/reject_assumptions.py | 129 ++++++++++++++++++++++ proofs/spark/reject_assumptions.sh | 31 +----- tests/codex_plugin/test_spark_interval.py | 11 +- 3 files changed, 140 insertions(+), 31 deletions(-) create mode 100644 proofs/spark/reject_assumptions.py diff --git a/proofs/spark/reject_assumptions.py b/proofs/spark/reject_assumptions.py new file mode 100644 index 0000000..9874a78 --- /dev/null +++ b/proofs/spark/reject_assumptions.py @@ -0,0 +1,129 @@ +#!/usr/bin/python3 -I -B +"""Reject SPARK proof assumptions without runner-image tool dependencies.""" + +from __future__ import annotations + +import re +import sys +from collections.abc import Iterator +from pathlib import Path + + +REPORT_ASSUME = re.compile(r"\(([1-9][0-9]*) pragma Assume statements?\)") +ADA_SUFFIXES = {".adb", ".ads"} +FORBIDDEN_PRAGMAS = {"annotate", "assume"} + + +def refuse(message: str) -> None: + raise SystemExit(f"refused: {message}") + + +def identifiers(text: str) -> Iterator[tuple[str, int]]: + """Yield Ada identifiers outside line comments and string literals.""" + + index = 0 + line = 1 + while index < len(text): + if text.startswith("--", index): + newline = text.find("\n", index + 2) + if newline < 0: + return + index = newline + continue + + character = text[index] + if character == '"': + index += 1 + while index < len(text): + if text[index] == '"': + if index + 1 < len(text) and text[index + 1] == '"': + index += 2 + continue + index += 1 + break + if text[index] == "\n": + line += 1 + index += 1 + continue + + if character.isascii() and character.isalpha(): + start = index + start_line = line + index += 1 + while index < len(text): + character = text[index] + if not ( + character.isascii() + and (character.isalnum() or character == "_") + ): + break + index += 1 + yield text[start:index].lower(), start_line + continue + + if character == "\n": + line += 1 + index += 1 + + +def source_files(raw_roots: list[str]) -> list[Path]: + files: list[Path] = [] + seen: set[Path] = set() + for raw_root in raw_roots: + root = Path(raw_root) + if root.is_symlink() or not root.exists(): + refuse(f"SPARK source root is missing or symbolic: {root}") + candidates = [root] if root.is_file() else root.rglob("*") + for candidate in candidates: + if candidate.suffix.lower() not in ADA_SUFFIXES: + continue + if candidate.is_symlink() or not candidate.is_file(): + refuse(f"SPARK source is not a regular file: {candidate}") + resolved = candidate.resolve() + if resolved not in seen: + files.append(candidate) + seen.add(resolved) + if not files: + refuse("no SPARK source files were found") + return files + + +def check_source(path: Path) -> None: + try: + text = path.read_text(encoding="utf-8") + except (OSError, UnicodeError) as error: + refuse(f"cannot read SPARK source {path}: {error}") + + expect_pragma_name_at: int | None = None + for identifier, line in identifiers(text): + if expect_pragma_name_at is not None: + if identifier in FORBIDDEN_PRAGMAS: + refuse( + f"proof assumption or justification in {path}:" + f"{expect_pragma_name_at} ({identifier})" + ) + expect_pragma_name_at = None + if identifier == "pragma": + expect_pragma_name_at = line + + +def main(arguments: list[str]) -> None: + if len(arguments) < 2: + refuse("a GNATprove report and SPARK source roots are required") + + report = Path(arguments[0]) + if report.is_symlink() or not report.is_file(): + refuse("the GNATprove report is not a regular file") + try: + report_text = report.read_text(encoding="utf-8") + except (OSError, UnicodeError) as error: + refuse(f"cannot read the GNATprove report: {error}") + if REPORT_ASSUME.search(report_text): + refuse("GNATprove reports one or more proof assumptions") + + for path in source_files(arguments[1:]): + check_source(path) + + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/proofs/spark/reject_assumptions.sh b/proofs/spark/reject_assumptions.sh index 1fe476d..6753d73 100755 --- a/proofs/spark/reject_assumptions.sh +++ b/proofs/spark/reject_assumptions.sh @@ -1,34 +1,11 @@ #!/bin/sh set -eu -if [ "$#" -lt 2 ]; then - echo "refused: a GNATprove report and SPARK source roots are required" >&2 - exit 1 -fi - -PROOF_REPORT=$1 -shift - -[ -f "$PROOF_REPORT" ] || { - echo "refused: the GNATprove report is not a regular file" >&2 - exit 1 -} - -if grep -Eq '\([1-9][0-9]* pragma Assume statements?\)' "$PROOF_REPORT"; then - echo "refused: GNATprove reports one or more proof assumptions" >&2 - exit 1 -fi +SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd -P) -command -v rg >/dev/null 2>&1 || { - echo "refused: rg is unavailable for the SPARK assumption scan" >&2 +command -v python3 >/dev/null 2>&1 || { + echo "refused: python3 is unavailable for the SPARK assumption scan" >&2 exit 1 } -# Ada identifiers are case-insensitive and whitespace can span lines. Keep -# this scan multiline and case-insensitive so spelling or formatting cannot -# bypass the no-assumption/no-justification policy. -if rg -n -i -U --glob '*.ad?' \ - 'pragma[[:space:]]+(Assume|Annotate)\b' "$@"; then - echo "refused: proof assumptions or justifications are forbidden" >&2 - exit 1 -fi +exec python3 -I -B "$SCRIPT_DIR/reject_assumptions.py" "$@" diff --git a/tests/codex_plugin/test_spark_interval.py b/tests/codex_plugin/test_spark_interval.py index ce52d0b..d69b8a3 100644 --- a/tests/codex_plugin/test_spark_interval.py +++ b/tests/codex_plugin/test_spark_interval.py @@ -30,7 +30,6 @@ def test_source_keeps_the_declared_formal_boundary(self): self.assertNotIn("pragma assume", lowered) self.assertNotIn("pragma annotate", lowered) - @unittest.skipUnless(shutil.which("rg"), "rg is not installed") def test_assumption_guard_rejects_case_and_line_break_bypasses(self): with tempfile.TemporaryDirectory() as raw_directory: directory = Path(raw_directory) @@ -41,7 +40,10 @@ def test_assumption_guard_rejects_case_and_line_break_bypasses(self): encoding="utf-8", ) source.write_text( - "procedure Guard_Probe is begin null; end Guard_Probe;\n", + "-- pragma Assume (True);\n" + "procedure Guard_Probe is\n" + " Message : constant String := \"pragma Annotate\";\n" + "begin null; end Guard_Probe;\n", encoding="utf-8", ) accepted = subprocess.run( @@ -58,6 +60,7 @@ def test_assumption_guard_rejects_case_and_line_break_bypasses(self): forbidden_pragmas = ( "pragma aSsUmE (True);", "pragma\nAnNoTaTe (GNATprove, False_Positive, \"probe\");", + "pragma -- comment between Ada tokens\nAssume (True);", ) for forbidden in forbidden_pragmas: with self.subTest(forbidden=forbidden): @@ -72,7 +75,7 @@ def test_assumption_guard_rejects_case_and_line_break_bypasses(self): transcript = refused.stdout + refused.stderr self.assertNotEqual(refused.returncode, 0, transcript) self.assertIn( - "proof assumptions or justifications are forbidden", + "proof assumption or justification", transcript, ) @@ -99,7 +102,7 @@ def test_assumption_guard_rejects_case_and_line_break_bypasses(self): ) @unittest.skipUnless( - shutil.which("gprbuild") and shutil.which("gnatprove") and shutil.which("rg"), + shutil.which("gprbuild") and shutil.which("gnatprove"), "GNATprove toolchain is not installed", ) def test_build_runtime_boundary_and_gnatprove_gate(self):