sum-engine 0.4.1__tar.gz → 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sum_engine-0.4.1 → sum_engine-0.5.0}/PKG-INFO +5 -2
- {sum_engine-0.4.1 → sum_engine-0.5.0}/README.md +1 -1
- {sum_engine-0.4.1 → sum_engine-0.5.0}/pyproject.toml +11 -1
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine.egg-info/PKG-INFO +5 -2
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine.egg-info/SOURCES.txt +2 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine.egg-info/requires.txt +4 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/mcp_server/server.py +150 -1
- sum_engine-0.5.0/sum_engine_internal/research/__init__.py +21 -0
- sum_engine-0.5.0/sum_engine_internal/research/sheaf_laplacian.py +231 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/LICENSE +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/setup.cfg +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_cli/__init__.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_cli/main.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine.egg-info/dependency_links.txt +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine.egg-info/entry_points.txt +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine.egg-info/top_level.txt +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/__init__.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/adapters/__init__.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/adapters/format_pivot.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/algorithms/__init__.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/algorithms/causal_discovery.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/algorithms/chunked_corpus.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/algorithms/minhash.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/algorithms/predicate_canon.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/algorithms/semantic_arithmetic.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/algorithms/syntactic_sieve.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/algorithms/zk_semantics.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/ensemble/__init__.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/ensemble/automated_scientist.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/ensemble/autonomous_agent.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/ensemble/causal_triggers.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/ensemble/confidence_calibrator.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/ensemble/data/__init__.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/ensemble/data/common_english_2000.txt +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/ensemble/data/common_english_5000.txt +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/ensemble/epistemic_arbiter.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/ensemble/epistemic_loop.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/ensemble/extraction_validator.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/ensemble/gauge_orchestrator.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/ensemble/live_llm_adapter.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/ensemble/llm_dispatch.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/ensemble/llm_entailment.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/ensemble/mass_semantic_engine.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/ensemble/ouroboros.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/ensemble/s25_interventions.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/ensemble/semantic_dedup.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/ensemble/slider_renderer.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/ensemble/tome_generator.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/ensemble/tome_sliders.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/ensemble/vector_bridge.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/ensemble/venn_abers.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/infrastructure/__init__.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/infrastructure/akashic_ledger.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/infrastructure/canonical_codec.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/infrastructure/jcs.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/infrastructure/jose_envelope.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/infrastructure/key_manager.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/infrastructure/p2p_mesh.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/infrastructure/prov_o.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/infrastructure/provenance.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/infrastructure/rate_limiter.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/infrastructure/resource_guards.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/infrastructure/scheme_registry.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/infrastructure/state_encoding.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/infrastructure/telemetry.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/infrastructure/tome_parser.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/infrastructure/verifiable_credential.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/infrastructure/zig_bridge.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/mcp_server/__init__.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/mcp_server/__main__.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/mcp_server/errors.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/merkle_sidecar/__init__.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/merkle_sidecar/tree.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/render_receipt/__init__.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/render_receipt/verifier.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/trust_root/__init__.py +0 -0
- {sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/trust_root/verifier.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sum-engine
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: SUM — bidirectional knowledge distillation with optional cryptographic attestation. Pipe prose, get a CanonicalBundle (HMAC / Ed25519 / W3C VC 2.0), verify anywhere.
|
|
5
5
|
Author: ototao
|
|
6
6
|
License: Apache-2.0
|
|
@@ -35,6 +35,9 @@ Provides-Extra: receipt-verify
|
|
|
35
35
|
Requires-Dist: joserfc>=1.0.0; extra == "receipt-verify"
|
|
36
36
|
Provides-Extra: mcp
|
|
37
37
|
Requires-Dist: mcp>=1.0.0; extra == "mcp"
|
|
38
|
+
Provides-Extra: research
|
|
39
|
+
Requires-Dist: numpy>=1.24.0; extra == "research"
|
|
40
|
+
Requires-Dist: scipy>=1.10.0; extra == "research"
|
|
38
41
|
Provides-Extra: omni-format
|
|
39
42
|
Requires-Dist: markitdown==0.1.5; extra == "omni-format"
|
|
40
43
|
Provides-Extra: dev
|
|
@@ -106,7 +109,7 @@ A minimal Node verifier using `jose` + `canonicalize` is in [`docs/RENDER_RECEIP
|
|
|
106
109
|
|
|
107
110
|
| Surface | Status | Verifies |
|
|
108
111
|
|---|---|---|
|
|
109
|
-
| `pip install 'sum-engine[sieve]'` — `sum attest` / `sum verify` / `sum render` / `sum resolve` / `sum ledger` / `sum inspect` / `sum schema` | shipped on
|
|
112
|
+
| `pip install 'sum-engine[sieve]'` — `sum attest` / `sum verify` / `sum render` / `sum resolve` / `sum ledger` / `sum inspect` / `sum schema` | shipped on PyPI ≥ 0.4.1 | structural reconstruction; HMAC-SHA256 + Ed25519 signatures (W3C VC 2.0 `eddsa-jcs-2022`); bidirectional `sum attest` ↔ `sum render` symmetry from the shell |
|
|
110
113
|
| Cloudflare Worker at `sum-demo.ototao.workers.dev` | shipped | `/api/render` → tome + `render_receipt`; `/.well-known/jwks.json` → JWKS; `/api/qid` → Wikidata resolver |
|
|
111
114
|
| Single-file browser demo (`single_file_demo/index.html`) | shipped | paste prose → in-browser attest → CanonicalBundle JSON; same bytes verify under `node standalone_verifier/verify.js` (Chrome / Firefox / Safari with WebCrypto Ed25519 support) |
|
|
112
115
|
| Cross-runtime trust triangle | locked by CI (`make xruntime`) | K1 / K1-mw / K2 / K3 / K4 — Python ↔ Node ↔ Browser agree byte-for-byte on valid bundles. `make xruntime-adversarial` adds A1–A6 rejection-class equivalence. |
|
|
@@ -48,7 +48,7 @@ A minimal Node verifier using `jose` + `canonicalize` is in [`docs/RENDER_RECEIP
|
|
|
48
48
|
|
|
49
49
|
| Surface | Status | Verifies |
|
|
50
50
|
|---|---|---|
|
|
51
|
-
| `pip install 'sum-engine[sieve]'` — `sum attest` / `sum verify` / `sum render` / `sum resolve` / `sum ledger` / `sum inspect` / `sum schema` | shipped on
|
|
51
|
+
| `pip install 'sum-engine[sieve]'` — `sum attest` / `sum verify` / `sum render` / `sum resolve` / `sum ledger` / `sum inspect` / `sum schema` | shipped on PyPI ≥ 0.4.1 | structural reconstruction; HMAC-SHA256 + Ed25519 signatures (W3C VC 2.0 `eddsa-jcs-2022`); bidirectional `sum attest` ↔ `sum render` symmetry from the shell |
|
|
52
52
|
| Cloudflare Worker at `sum-demo.ototao.workers.dev` | shipped | `/api/render` → tome + `render_receipt`; `/.well-known/jwks.json` → JWKS; `/api/qid` → Wikidata resolver |
|
|
53
53
|
| Single-file browser demo (`single_file_demo/index.html`) | shipped | paste prose → in-browser attest → CanonicalBundle JSON; same bytes verify under `node standalone_verifier/verify.js` (Chrome / Firefox / Safari with WebCrypto Ed25519 support) |
|
|
54
54
|
| Cross-runtime trust triangle | locked by CI (`make xruntime`) | K1 / K1-mw / K2 / K3 / K4 — Python ↔ Node ↔ Browser agree byte-for-byte on valid bundles. `make xruntime-adversarial` adds A1–A6 rejection-class equivalence. |
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "sum-engine"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.5.0"
|
|
8
8
|
description = "SUM — bidirectional knowledge distillation with optional cryptographic attestation. Pipe prose, get a CanonicalBundle (HMAC / Ed25519 / W3C VC 2.0), verify anywhere."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "Apache-2.0" }
|
|
@@ -60,6 +60,16 @@ receipt-verify = ["joserfc>=1.0.0"]
|
|
|
60
60
|
# `mcp` package is the official Python SDK; FastMCP is its
|
|
61
61
|
# decorator-style high-level API. See docs/MCP_INTEGRATION.md.
|
|
62
62
|
mcp = ["mcp>=1.0.0"]
|
|
63
|
+
# Research-grade modules under sum_engine_internal/research/. NOT on
|
|
64
|
+
# the production install path; APIs may change between minor releases
|
|
65
|
+
# without backwards-compatibility guarantees. Currently provides the
|
|
66
|
+
# v1 sheaf-Laplacian hallucination detector grounded in Gebhart,
|
|
67
|
+
# Hansen & Schrater (2023, AISTATS, arXiv:2110.03789) and the
|
|
68
|
+
# sheaf-Laplacian theory of Hansen & Ghrist (2019). See
|
|
69
|
+
# docs/SHEAF_HALLUCINATION_DETECTOR.md for the spec, including
|
|
70
|
+
# verified blindspots (predicate-flip, off-graph fact-fabrication,
|
|
71
|
+
# empty-render false negative).
|
|
72
|
+
research = ["numpy>=1.24.0", "scipy>=1.10.0"]
|
|
63
73
|
# Omni-format adapter. Markdown is the canonical pivot for the
|
|
64
74
|
# attest pipeline: any input format -> markdown -> existing
|
|
65
75
|
# extract/state/bundle path. Source URI anchors to the original
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sum-engine
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: SUM — bidirectional knowledge distillation with optional cryptographic attestation. Pipe prose, get a CanonicalBundle (HMAC / Ed25519 / W3C VC 2.0), verify anywhere.
|
|
5
5
|
Author: ototao
|
|
6
6
|
License: Apache-2.0
|
|
@@ -35,6 +35,9 @@ Provides-Extra: receipt-verify
|
|
|
35
35
|
Requires-Dist: joserfc>=1.0.0; extra == "receipt-verify"
|
|
36
36
|
Provides-Extra: mcp
|
|
37
37
|
Requires-Dist: mcp>=1.0.0; extra == "mcp"
|
|
38
|
+
Provides-Extra: research
|
|
39
|
+
Requires-Dist: numpy>=1.24.0; extra == "research"
|
|
40
|
+
Requires-Dist: scipy>=1.10.0; extra == "research"
|
|
38
41
|
Provides-Extra: omni-format
|
|
39
42
|
Requires-Dist: markitdown==0.1.5; extra == "omni-format"
|
|
40
43
|
Provides-Extra: dev
|
|
@@ -106,7 +109,7 @@ A minimal Node verifier using `jose` + `canonicalize` is in [`docs/RENDER_RECEIP
|
|
|
106
109
|
|
|
107
110
|
| Surface | Status | Verifies |
|
|
108
111
|
|---|---|---|
|
|
109
|
-
| `pip install 'sum-engine[sieve]'` — `sum attest` / `sum verify` / `sum render` / `sum resolve` / `sum ledger` / `sum inspect` / `sum schema` | shipped on
|
|
112
|
+
| `pip install 'sum-engine[sieve]'` — `sum attest` / `sum verify` / `sum render` / `sum resolve` / `sum ledger` / `sum inspect` / `sum schema` | shipped on PyPI ≥ 0.4.1 | structural reconstruction; HMAC-SHA256 + Ed25519 signatures (W3C VC 2.0 `eddsa-jcs-2022`); bidirectional `sum attest` ↔ `sum render` symmetry from the shell |
|
|
110
113
|
| Cloudflare Worker at `sum-demo.ototao.workers.dev` | shipped | `/api/render` → tome + `render_receipt`; `/.well-known/jwks.json` → JWKS; `/api/qid` → Wikidata resolver |
|
|
111
114
|
| Single-file browser demo (`single_file_demo/index.html`) | shipped | paste prose → in-browser attest → CanonicalBundle JSON; same bytes verify under `node standalone_verifier/verify.js` (Chrome / Firefox / Safari with WebCrypto Ed25519 support) |
|
|
112
115
|
| Cross-runtime trust triangle | locked by CI (`make xruntime`) | K1 / K1-mw / K2 / K3 / K4 — Python ↔ Node ↔ Browser agree byte-for-byte on valid bundles. `make xruntime-adversarial` adds A1–A6 rejection-class equivalence. |
|
|
@@ -69,5 +69,7 @@ sum_engine_internal/merkle_sidecar/__init__.py
|
|
|
69
69
|
sum_engine_internal/merkle_sidecar/tree.py
|
|
70
70
|
sum_engine_internal/render_receipt/__init__.py
|
|
71
71
|
sum_engine_internal/render_receipt/verifier.py
|
|
72
|
+
sum_engine_internal/research/__init__.py
|
|
73
|
+
sum_engine_internal/research/sheaf_laplacian.py
|
|
72
74
|
sum_engine_internal/trust_root/__init__.py
|
|
73
75
|
sum_engine_internal/trust_root/verifier.py
|
|
@@ -92,7 +92,7 @@ def build_server() -> FastMCP:
|
|
|
92
92
|
name="sum",
|
|
93
93
|
instructions=(
|
|
94
94
|
"SUM verifiable knowledge distillation engine (v2 hardened). "
|
|
95
|
-
"Tools: extract / attest / verify / inspect / schema. "
|
|
95
|
+
"Tools: extract / attest / verify / inspect / render / schema. "
|
|
96
96
|
"Default extractor is offline-only (sieve). The LLM extractor "
|
|
97
97
|
"is disabled unless SUM_MCP_ALLOW_NETWORK=1 was set when the "
|
|
98
98
|
"server started. Every tool returns either a tool-specific "
|
|
@@ -472,6 +472,155 @@ def build_server() -> FastMCP:
|
|
|
472
472
|
"inspect", t0, ErrorClass.INTERNAL, type(exc).__name__
|
|
473
473
|
)
|
|
474
474
|
|
|
475
|
+
# ------------------------------------------------------------------
|
|
476
|
+
# render
|
|
477
|
+
# ------------------------------------------------------------------
|
|
478
|
+
|
|
479
|
+
@mcp.tool()
|
|
480
|
+
async def render(
|
|
481
|
+
bundle: dict,
|
|
482
|
+
density: float = 1.0,
|
|
483
|
+
length: float = 0.5,
|
|
484
|
+
formality: float = 0.5,
|
|
485
|
+
audience: float = 0.5,
|
|
486
|
+
perspective: float = 0.5,
|
|
487
|
+
title: str = "Rendered Tome",
|
|
488
|
+
) -> dict:
|
|
489
|
+
"""Render a CanonicalBundle's axioms back into prose under
|
|
490
|
+
explicit slider control. The MCP analogue of ``sum render``.
|
|
491
|
+
|
|
492
|
+
Local-only path: actions the density slider deterministically
|
|
493
|
+
(lex-prefix subsetting); non-neutral length / formality /
|
|
494
|
+
audience / perspective return ``error_class="schema"`` because
|
|
495
|
+
the LLM-conditioned axes require a Worker, which the MCP
|
|
496
|
+
server does not currently broker (see
|
|
497
|
+
``docs/MCP_INTEGRATION.md`` for the rationale — keeping the
|
|
498
|
+
MCP server fully offline by default preserves the
|
|
499
|
+
``SUM_MCP_ALLOW_NETWORK`` opt-in property).
|
|
500
|
+
|
|
501
|
+
Args:
|
|
502
|
+
bundle: CanonicalBundle dict (same shape ``verify`` accepts).
|
|
503
|
+
density: Axiom-coverage slider in [0, 1]. 1.0 keeps all
|
|
504
|
+
axioms (default); 0.0 keeps none.
|
|
505
|
+
length / formality / audience / perspective: 0.5 = neutral
|
|
506
|
+
(default). Non-0.5 rejected with a SCHEMA error
|
|
507
|
+
pointing at the local-only constraint.
|
|
508
|
+
title: Tome title. Default: "Rendered Tome".
|
|
509
|
+
|
|
510
|
+
Returns:
|
|
511
|
+
Success: ``{tome, sliders, mode, axiom_count_input, title}``.
|
|
512
|
+
Failure: ``{error_class, errors}``.
|
|
513
|
+
"""
|
|
514
|
+
t0 = time.perf_counter()
|
|
515
|
+
try:
|
|
516
|
+
if not isinstance(bundle, dict):
|
|
517
|
+
return error_result(
|
|
518
|
+
"render", t0, ErrorClass.SCHEMA,
|
|
519
|
+
f"bundle must be a dict, got {type(bundle).__name__}",
|
|
520
|
+
)
|
|
521
|
+
|
|
522
|
+
for field in ("canonical_tome", "canonical_format_version"):
|
|
523
|
+
if field not in bundle:
|
|
524
|
+
return error_result(
|
|
525
|
+
"render", t0, ErrorClass.SCHEMA,
|
|
526
|
+
f"bundle missing required field: {field}",
|
|
527
|
+
)
|
|
528
|
+
|
|
529
|
+
ver = str(bundle["canonical_format_version"])
|
|
530
|
+
if not ver.startswith("1."):
|
|
531
|
+
return error_result(
|
|
532
|
+
"render", t0, ErrorClass.SCHEMA,
|
|
533
|
+
f"unsupported canonical_format_version {ver!r} "
|
|
534
|
+
f"(this server speaks {_SUPPORTED_CANONICAL_FORMAT})",
|
|
535
|
+
)
|
|
536
|
+
|
|
537
|
+
tome_str = bundle["canonical_tome"]
|
|
538
|
+
if not isinstance(tome_str, str) or len(tome_str) > MAX_TOME_CHARS:
|
|
539
|
+
return error_result(
|
|
540
|
+
"render", t0, ErrorClass.INPUT_TOO_LARGE,
|
|
541
|
+
f"canonical_tome exceeds {MAX_TOME_CHARS} chars",
|
|
542
|
+
)
|
|
543
|
+
|
|
544
|
+
from sum_engine_internal.ensemble.tome_sliders import TomeSliders
|
|
545
|
+
|
|
546
|
+
try:
|
|
547
|
+
sliders = TomeSliders(
|
|
548
|
+
density=density, length=length,
|
|
549
|
+
formality=formality, audience=audience,
|
|
550
|
+
perspective=perspective,
|
|
551
|
+
)
|
|
552
|
+
except (ValueError, TypeError) as e:
|
|
553
|
+
return error_result(
|
|
554
|
+
"render", t0, ErrorClass.SCHEMA,
|
|
555
|
+
f"invalid slider value: {e}",
|
|
556
|
+
)
|
|
557
|
+
|
|
558
|
+
if sliders.requires_extrapolator():
|
|
559
|
+
non_neutral = [
|
|
560
|
+
f"{name}={getattr(sliders, name)}"
|
|
561
|
+
for name in ("length", "formality", "audience", "perspective")
|
|
562
|
+
if abs(getattr(sliders, name) - 0.5) > 1e-9
|
|
563
|
+
]
|
|
564
|
+
return error_result(
|
|
565
|
+
"render", t0, ErrorClass.SCHEMA,
|
|
566
|
+
"non-neutral LLM-conditioned axes ("
|
|
567
|
+
+ ", ".join(non_neutral)
|
|
568
|
+
+ ") require an LLM extrapolator. The MCP server's "
|
|
569
|
+
"render tool is local-only (deterministic density "
|
|
570
|
+
"slider) — drop the affected sliders to 0.5, or "
|
|
571
|
+
"use the Worker's POST /api/render endpoint for "
|
|
572
|
+
"LLM-conditioned rendering.",
|
|
573
|
+
)
|
|
574
|
+
|
|
575
|
+
triples: list[tuple[str, str, str]] = []
|
|
576
|
+
for line in tome_str.splitlines():
|
|
577
|
+
m = _TOME_LINE_PATTERN.match(line.strip())
|
|
578
|
+
if m:
|
|
579
|
+
if len(triples) >= MAX_AXIOM_COUNT:
|
|
580
|
+
return error_result(
|
|
581
|
+
"render", t0, ErrorClass.INPUT_TOO_LARGE,
|
|
582
|
+
f"axiom count exceeds {MAX_AXIOM_COUNT}",
|
|
583
|
+
)
|
|
584
|
+
triples.append((m.group(1), m.group(2), m.group(3)))
|
|
585
|
+
|
|
586
|
+
if not triples:
|
|
587
|
+
return error_result(
|
|
588
|
+
"render", t0, ErrorClass.STRUCTURAL,
|
|
589
|
+
"bundle's canonical_tome contains zero parseable "
|
|
590
|
+
"axiom lines — nothing to render.",
|
|
591
|
+
)
|
|
592
|
+
|
|
593
|
+
from sum_engine_internal.algorithms.semantic_arithmetic import GodelStateAlgebra
|
|
594
|
+
from sum_engine_internal.ensemble.tome_generator import AutoregressiveTomeGenerator
|
|
595
|
+
|
|
596
|
+
algebra = GodelStateAlgebra()
|
|
597
|
+
state = 1
|
|
598
|
+
for s, p, o in triples:
|
|
599
|
+
state = math.lcm(state, algebra.get_or_mint_prime(s, p, o))
|
|
600
|
+
|
|
601
|
+
tome_gen = AutoregressiveTomeGenerator(algebra)
|
|
602
|
+
tome_text = tome_gen.generate_controlled(state, sliders=sliders, title=title)
|
|
603
|
+
|
|
604
|
+
return success_result(
|
|
605
|
+
"render",
|
|
606
|
+
t0,
|
|
607
|
+
tome=tome_text,
|
|
608
|
+
sliders={
|
|
609
|
+
"density": sliders.density,
|
|
610
|
+
"length": sliders.length,
|
|
611
|
+
"formality": sliders.formality,
|
|
612
|
+
"audience": sliders.audience,
|
|
613
|
+
"perspective": sliders.perspective,
|
|
614
|
+
},
|
|
615
|
+
mode="local-deterministic",
|
|
616
|
+
axiom_count_input=len(triples),
|
|
617
|
+
title=title,
|
|
618
|
+
)
|
|
619
|
+
except Exception as exc:
|
|
620
|
+
return error_result(
|
|
621
|
+
"render", t0, ErrorClass.INTERNAL, type(exc).__name__
|
|
622
|
+
)
|
|
623
|
+
|
|
475
624
|
# ------------------------------------------------------------------
|
|
476
625
|
# schema
|
|
477
626
|
# ------------------------------------------------------------------
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""sum_engine_internal.research — research-grade modules.
|
|
2
|
+
|
|
3
|
+
Modules in this package are NOT part of the production install path.
|
|
4
|
+
They live behind the ``[research]`` extras flag in pyproject.toml so
|
|
5
|
+
that ``pip install sum-engine`` does not pull research dependencies
|
|
6
|
+
(numpy, scipy) by default. Use ``pip install 'sum-engine[research]'``.
|
|
7
|
+
|
|
8
|
+
Modules:
|
|
9
|
+
|
|
10
|
+
sheaf_laplacian
|
|
11
|
+
v1 sheaf-Laplacian hallucination detector. Implements the
|
|
12
|
+
primitives specified in docs/SHEAF_HALLUCINATION_DETECTOR.md
|
|
13
|
+
§3.2 (1-dim presence stalks). Math is grounded in Gebhart,
|
|
14
|
+
Hansen & Schrater (2023, AISTATS, arXiv:2110.03789) Eq. 1
|
|
15
|
+
and the sheaf-Laplacian theory of Hansen & Ghrist (2019).
|
|
16
|
+
|
|
17
|
+
Stability: research-grade. APIs may change between minor releases
|
|
18
|
+
without backwards-compatibility guarantees. Production-stable
|
|
19
|
+
counterparts will live elsewhere if/when the research artifacts
|
|
20
|
+
benchmark sufficiently.
|
|
21
|
+
"""
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
"""v1 sheaf-Laplacian hallucination detector.
|
|
2
|
+
|
|
3
|
+
Faithful to docs/SHEAF_HALLUCINATION_DETECTOR.md §3.2 (v1, 1-dim
|
|
4
|
+
presence stalks). Math grounded in Gebhart, Hansen & Schrater
|
|
5
|
+
(2023, AISTATS, arXiv:2110.03789) Equation 1 and the sheaf-Laplacian
|
|
6
|
+
theory of Hansen & Ghrist (2019).
|
|
7
|
+
|
|
8
|
+
Every function below references the spec equation it implements.
|
|
9
|
+
The v1 detector lives behind the ``[research]`` extras flag in
|
|
10
|
+
``pyproject.toml`` — it is not on the production install path.
|
|
11
|
+
|
|
12
|
+
v1 known blindspots (verified empirically by the synthetic
|
|
13
|
+
micro-benchmark in scripts/research/sheaf_microbench.py and pinned
|
|
14
|
+
by Tests/research/test_sheaf_laplacian.py):
|
|
15
|
+
|
|
16
|
+
- Predicate-flip perturbations (A2): invisible. Presence stalks
|
|
17
|
+
do not carry predicate information. v2 (learned-embedding stalks)
|
|
18
|
+
is required for predicate-sensitive detection.
|
|
19
|
+
- Off-graph fact-fabrication (A3): invisible. Entities not in the
|
|
20
|
+
source vertex set are silently ignored by ``cochain_from_extracted``.
|
|
21
|
+
v2 is required to flag fabricated entities.
|
|
22
|
+
- Empty-render false negative: a render that extracts zero triples
|
|
23
|
+
yields x = 0, hence x^T L x = 0 — the same score as a perfectly
|
|
24
|
+
consistent render. Callers should treat n_extracted == 0 as a
|
|
25
|
+
separate signal, not rely on the Laplacian alone.
|
|
26
|
+
|
|
27
|
+
v1 verified-positive detection classes (6/6 detect rate, 100%
|
|
28
|
+
top-1 localization accuracy on the synthetic micro-benchmark):
|
|
29
|
+
|
|
30
|
+
- Entity-swap (A1): one source entity replaced.
|
|
31
|
+
- Triple-drop (A4): one triple omitted; isolated endpoints vanish.
|
|
32
|
+
- Consistent-entity-swap (A5): the SAME swap applied across the
|
|
33
|
+
full render manifold. Caught by the *mean* Laplacian even though
|
|
34
|
+
per-render variance is zero. (The spec originally
|
|
35
|
+
mischaracterized this as a v1 blindspot; corrected in §6 to
|
|
36
|
+
distinguish A5-via-swap (caught) from A5-via-predicate-flip
|
|
37
|
+
(missed).)
|
|
38
|
+
"""
|
|
39
|
+
from __future__ import annotations
|
|
40
|
+
|
|
41
|
+
from dataclasses import dataclass
|
|
42
|
+
import numpy as np
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
Triple = tuple[str, str, str]
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@dataclass(frozen=True)
|
|
49
|
+
class KnowledgeSheaf:
|
|
50
|
+
"""A cellular sheaf on a knowledge graph (Gebhart et al. 2023, Def. 4).
|
|
51
|
+
|
|
52
|
+
For v1 (1-dim presence stalks):
|
|
53
|
+
F(v) = R for every vertex v
|
|
54
|
+
F(e) = R for every edge e
|
|
55
|
+
F_h⊵_h r = F_t⊵_t r = 1 (identity on R)
|
|
56
|
+
|
|
57
|
+
The vertex order is fixed at construction so cochains are
|
|
58
|
+
indexable as plain numpy arrays.
|
|
59
|
+
|
|
60
|
+
Note on ``stalk_dim``: v1 only supports ``stalk_dim=1``.
|
|
61
|
+
Construction with any other value is rejected at
|
|
62
|
+
``__post_init__`` time so callers cannot build a sheaf they
|
|
63
|
+
can't use. v2 (text-embedding stalks) will lift this constraint;
|
|
64
|
+
until then, attempting to use higher-dimensional stalks should
|
|
65
|
+
fail loudly at the boundary — not silently surface as a
|
|
66
|
+
NotImplementedError mid-pipeline.
|
|
67
|
+
"""
|
|
68
|
+
vertices: tuple[str, ...]
|
|
69
|
+
edges: tuple[Triple, ...] # (subject, predicate, object)
|
|
70
|
+
vertex_index: dict[str, int] # name → index into cochain vector
|
|
71
|
+
stalk_dim: int # = 1 for v1
|
|
72
|
+
|
|
73
|
+
def __post_init__(self) -> None:
|
|
74
|
+
if self.stalk_dim != 1:
|
|
75
|
+
raise ValueError(
|
|
76
|
+
f"v1 KnowledgeSheaf supports stalk_dim=1 only "
|
|
77
|
+
f"(got stalk_dim={self.stalk_dim}). v2 with text-"
|
|
78
|
+
f"embedding stalks (1536-dim) is the planned "
|
|
79
|
+
f"successor; see docs/SHEAF_HALLUCINATION_DETECTOR.md "
|
|
80
|
+
f"§5.3 for the v1 → v2 plan."
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
@classmethod
|
|
84
|
+
def from_triples(cls, triples: list[Triple], stalk_dim: int = 1) -> "KnowledgeSheaf":
|
|
85
|
+
seen: dict[str, None] = {}
|
|
86
|
+
for s, _, o in triples:
|
|
87
|
+
seen.setdefault(s, None)
|
|
88
|
+
seen.setdefault(o, None)
|
|
89
|
+
vertices = tuple(seen)
|
|
90
|
+
return cls(
|
|
91
|
+
vertices=vertices,
|
|
92
|
+
edges=tuple(triples),
|
|
93
|
+
vertex_index={v: i for i, v in enumerate(vertices)},
|
|
94
|
+
stalk_dim=stalk_dim,
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def coboundary_matrix(sheaf: KnowledgeSheaf) -> np.ndarray:
|
|
99
|
+
"""δ : C^0 → C^1 as a matrix.
|
|
100
|
+
|
|
101
|
+
Spec §2.1 / Gebhart Def. 4: for an edge e: u → v with identity
|
|
102
|
+
restriction maps, (δx)_e = x_v - x_u. Each row of δ has
|
|
103
|
+
exactly two non-zeros: -1 at u's column, +1 at v's column.
|
|
104
|
+
|
|
105
|
+
Shape: (|E|, |V|) for stalk_dim=1; (|E|*d, |V|*d) when d>1
|
|
106
|
+
using a Kronecker product. v1 uses d=1, enforced at sheaf
|
|
107
|
+
construction time (see ``KnowledgeSheaf.__post_init__``).
|
|
108
|
+
"""
|
|
109
|
+
# Defensive — should be unreachable since KnowledgeSheaf rejects
|
|
110
|
+
# non-1 stalk_dim at construction. Kept as an invariant so a
|
|
111
|
+
# future v2 KnowledgeSheaf subclass that lifts the restriction
|
|
112
|
+
# but forgets to override this function fails loudly here.
|
|
113
|
+
assert sheaf.stalk_dim == 1, (
|
|
114
|
+
f"coboundary_matrix v1 requires stalk_dim=1, got {sheaf.stalk_dim}"
|
|
115
|
+
)
|
|
116
|
+
n_v = len(sheaf.vertices)
|
|
117
|
+
n_e = len(sheaf.edges)
|
|
118
|
+
delta = np.zeros((n_e, n_v), dtype=np.float64)
|
|
119
|
+
for i, (s, _, o) in enumerate(sheaf.edges):
|
|
120
|
+
delta[i, sheaf.vertex_index[s]] = -1.0 # F_u⊵e applied to head
|
|
121
|
+
delta[i, sheaf.vertex_index[o]] = +1.0 # F_v⊵e applied to tail
|
|
122
|
+
return delta
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def sheaf_laplacian(sheaf: KnowledgeSheaf) -> np.ndarray:
|
|
126
|
+
"""L_F = δ^T δ (Gebhart Eq. 1; Hansen-Ghrist 2019)."""
|
|
127
|
+
delta = coboundary_matrix(sheaf)
|
|
128
|
+
return delta.T @ delta
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def laplacian_quadratic_form(sheaf: KnowledgeSheaf, x: np.ndarray) -> float:
|
|
132
|
+
"""x^T L_F x. Zero iff x is a global section.
|
|
133
|
+
|
|
134
|
+
For v1 1-dim stalks, x ∈ R^|V|; this measures sum over edges of
|
|
135
|
+
(x_v - x_u)^2.
|
|
136
|
+
"""
|
|
137
|
+
L = sheaf_laplacian(sheaf)
|
|
138
|
+
return float(x @ L @ x)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def per_edge_discrepancy(sheaf: KnowledgeSheaf, x: np.ndarray) -> list[tuple[Triple, float]]:
|
|
142
|
+
"""Per-edge contribution to the Laplacian quadratic form.
|
|
143
|
+
|
|
144
|
+
Used for the localization claim (P2 in the spec). Returns
|
|
145
|
+
[(edge, |F_v⊵e x_v - F_u⊵e x_u|^2), ...] sorted descending.
|
|
146
|
+
"""
|
|
147
|
+
delta = coboundary_matrix(sheaf)
|
|
148
|
+
edge_residual = delta @ x # shape (|E|,)
|
|
149
|
+
contribs = [
|
|
150
|
+
(sheaf.edges[i], float(edge_residual[i] ** 2))
|
|
151
|
+
for i in range(len(sheaf.edges))
|
|
152
|
+
]
|
|
153
|
+
contribs.sort(key=lambda kv: kv[1], reverse=True)
|
|
154
|
+
return contribs
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def cochain_from_extracted(
|
|
158
|
+
sheaf: KnowledgeSheaf,
|
|
159
|
+
extracted_triples: list[Triple],
|
|
160
|
+
) -> np.ndarray:
|
|
161
|
+
"""Build the 0-cochain x ∈ C^0(G; F_1d) from a render's
|
|
162
|
+
re-extracted triples (spec §3.2 step 3b).
|
|
163
|
+
|
|
164
|
+
x_v = 1 if v appears as subject or object in extracted_triples,
|
|
165
|
+
else 0. This is the 1-dim presence indicator.
|
|
166
|
+
"""
|
|
167
|
+
mentioned: set[str] = set()
|
|
168
|
+
for s, _, o in extracted_triples:
|
|
169
|
+
mentioned.add(s)
|
|
170
|
+
mentioned.add(o)
|
|
171
|
+
x = np.zeros(len(sheaf.vertices), dtype=np.float64)
|
|
172
|
+
for v in mentioned:
|
|
173
|
+
if v in sheaf.vertex_index:
|
|
174
|
+
x[sheaf.vertex_index[v]] = 1.0
|
|
175
|
+
return x
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def consistency_profile(
|
|
179
|
+
source_triples: list[Triple],
|
|
180
|
+
rendered_extractions: list[list[Triple]],
|
|
181
|
+
) -> dict:
|
|
182
|
+
"""Mean & std of the Laplacian quadratic form across a render
|
|
183
|
+
manifold. Spec §3.2 step 5.
|
|
184
|
+
|
|
185
|
+
rendered_extractions: a list, one entry per rendering, each a
|
|
186
|
+
list of (s, p, o) triples extracted from that rendering.
|
|
187
|
+
|
|
188
|
+
Returns the consistency profile envelope shape from spec §3.5
|
|
189
|
+
(without the receipt-binding parts, which are v3). When the
|
|
190
|
+
render manifold is empty, returns a profile with explicit
|
|
191
|
+
null fields rather than a misleading zero score.
|
|
192
|
+
"""
|
|
193
|
+
sheaf = KnowledgeSheaf.from_triples(source_triples, stalk_dim=1)
|
|
194
|
+
|
|
195
|
+
# Empty manifold has no signal to report; return explicit nulls
|
|
196
|
+
# so callers can branch on render_count == 0 without having to
|
|
197
|
+
# interpret a fabricated all-zero profile.
|
|
198
|
+
if not rendered_extractions:
|
|
199
|
+
return {
|
|
200
|
+
"render_count": 0,
|
|
201
|
+
"stalk_dim": sheaf.stalk_dim,
|
|
202
|
+
"version": "v1-presence-stalks",
|
|
203
|
+
"mean_laplacian": None,
|
|
204
|
+
"std_laplacian": None,
|
|
205
|
+
"max_per_render": None,
|
|
206
|
+
"argmax_render_idx": None,
|
|
207
|
+
"per_render_v": [],
|
|
208
|
+
"per_edge_top3_argmax_render": [],
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
per_render_v: list[float] = []
|
|
212
|
+
per_render_localization: list[list[tuple[Triple, float]]] = []
|
|
213
|
+
for triples_n in rendered_extractions:
|
|
214
|
+
x_n = cochain_from_extracted(sheaf, triples_n)
|
|
215
|
+
v_n = laplacian_quadratic_form(sheaf, x_n)
|
|
216
|
+
per_render_v.append(v_n)
|
|
217
|
+
per_render_localization.append(per_edge_discrepancy(sheaf, x_n))
|
|
218
|
+
|
|
219
|
+
arr = np.array(per_render_v)
|
|
220
|
+
argmax_idx = int(arr.argmax())
|
|
221
|
+
return {
|
|
222
|
+
"render_count": len(rendered_extractions),
|
|
223
|
+
"stalk_dim": sheaf.stalk_dim,
|
|
224
|
+
"version": "v1-presence-stalks",
|
|
225
|
+
"mean_laplacian": float(arr.mean()),
|
|
226
|
+
"std_laplacian": float(arr.std()),
|
|
227
|
+
"max_per_render": float(arr.max()),
|
|
228
|
+
"argmax_render_idx": argmax_idx,
|
|
229
|
+
"per_render_v": per_render_v,
|
|
230
|
+
"per_edge_top3_argmax_render": per_render_localization[argmax_idx][:3],
|
|
231
|
+
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/ensemble/data/common_english_2000.txt
RENAMED
|
File without changes
|
{sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/ensemble/data/common_english_5000.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sum_engine-0.4.1 → sum_engine-0.5.0}/sum_engine_internal/infrastructure/verifiable_credential.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|