docs: 3 concepts diagrams + Python-library cookbook recipes
Address Grok's two minor-improvement flags on the docs.
New docs/diagrams/{three-layer-stack,cache-key-8dim,falsification-states}.{dot,svg,png}
embedded into docs/_source/concepts.rst — visual scaffolding for the
3-layer stack, 8-dim cache_key composition, and falsification state
machine (previously prose+tables only).
docs/_source/cookbook.rst gains a "Use arborist as a Python library"
section: open_store + ingest_documents, custom Source subclass,
audit-chain walk + verify, Merkle proof round-trip, programmatic
arborist.qa.query() with OpenAICompatibleClient + StubClient swap.
Every Python recipe smoke-tested against a scratch DB before publish.
make docs-api: 0 new warnings. make test: 2557 passed.
This commit is contained in:
parent
b6bb31a836
commit
06e6c7a918
11 changed files with 1045 additions and 0 deletions
|
|
@ -26,6 +26,19 @@ Three layers stacked on one SQLite file (per shard):
|
|||
- **Providence cache** — Q&A records keyed on the v9.8 8-dimension
|
||||
invariant; every record carries an audit_mode and a Merkle proof.
|
||||
|
||||
.. figure:: diagrams/three-layer-stack.svg
|
||||
:alt: Three-layer stack (surface, core, providence cache)
|
||||
:width: 100%
|
||||
|
||||
How the three layers compose. Surface document_roots flow into both
|
||||
core derivations (with per-chunk inclusion proofs in
|
||||
``derivations.proof_blob``) and providence-cache records (as the
|
||||
``source_root`` dimension of the 8-dim ``cache_key``). Cores reuse
|
||||
the surface proof structure, so the Merkle binding survives
|
||||
compression. Providence rows then carry their own ``merkle_proof``
|
||||
that ties an answer back to the chunks the verifier ran against —
|
||||
verifiable offline by any peer that holds the same surface roots.
|
||||
|
||||
.. figure:: diagrams/arborist-modules.svg
|
||||
:alt: Arborist module graph
|
||||
:width: 100%
|
||||
|
|
@ -84,6 +97,20 @@ lookup. This is how the system stays honest across model changes,
|
|||
schema migrations, prompt edits, etc. — old answers don't silently
|
||||
serve under new conditions.
|
||||
|
||||
.. figure:: diagrams/cache-key-8dim.svg
|
||||
:alt: 8-dim cache_key composition
|
||||
:width: 100%
|
||||
|
||||
The eight mandatory dimensions split across two groups: the top row
|
||||
(corpus, question, model, conversation) is the dynamic input
|
||||
surface; the bottom row (policy + three pinned versions) is the
|
||||
admissibility scaffold. The optional 9th dimension
|
||||
(``verifier_policy_hash``) exists for audit *legibility* under
|
||||
ticket #000058 — it does not add correctness coverage, because the
|
||||
verifier-policy fields are already a subset of
|
||||
``governance_policy_hash``. 8-dim is the default write form; 9-dim
|
||||
is opt-in.
|
||||
|
||||
The audit chain
|
||||
---------------
|
||||
|
||||
|
|
@ -172,6 +199,18 @@ Two ways to remove a wrong answer:
|
|||
record has children unless ``FORCE=1``. Use during scratch corpus
|
||||
building.
|
||||
|
||||
.. figure:: diagrams/falsification-states.svg
|
||||
:alt: Falsification state machine
|
||||
:width: 100%
|
||||
|
||||
State machine for ``falsification_state``. Every transition writes
|
||||
one ``audit_event`` so the chain stays intact — the schema column
|
||||
is the lookup gate, the audit chain is the history. ``stale →
|
||||
live`` is the rarely-trodden path where a corpus was rolled back to
|
||||
a prior state; cleanest in single-shard test setups. ``burn``
|
||||
actually deletes the row and is refused if the record has
|
||||
children unless ``FORCE=1``.
|
||||
|
||||
Sidecar diagnostics
|
||||
-------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -141,3 +141,236 @@ keywords without changing what the LLM sees as the question:
|
|||
|
||||
Provenance gap on this is tracked in
|
||||
:doc:`api/qa` (``arborist.qa.query``).
|
||||
|
||||
Use arborist as a Python library
|
||||
================================
|
||||
|
||||
Everything below uses the supported embedding surface,
|
||||
:mod:`arborist.embed`. Import from there, not from internal modules —
|
||||
internal refactors are free to move things around behind that seam.
|
||||
See :doc:`api/storage` for the full ``arborist.store`` reference and
|
||||
:doc:`api/substrate` for the Merkle primitives the recipes call into.
|
||||
|
||||
Open a store and ingest documents you already hold
|
||||
---------------------------------------------------
|
||||
|
||||
The minimum useful contact surface: pass in your own
|
||||
:class:`~arborist.document.Document` objects, get back content-addressed
|
||||
storage with an audit chain. Idempotent — re-running with the same
|
||||
``content`` yields the same ``document_root`` and skips the insert.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pathlib import Path
|
||||
from arborist.embed import (
|
||||
open_store, ingest_documents, search, Document, Edge,
|
||||
)
|
||||
|
||||
conn = open_store(Path("data/arborist.db")) # creates + migrates
|
||||
|
||||
stats = ingest_documents(conn, [
|
||||
Document(
|
||||
uri="https://example.com/post-a",
|
||||
content="anarcho-capitalism describes a stateless society "
|
||||
"where private property and free markets coordinate "
|
||||
"without coercion.",
|
||||
source_type="my_app",
|
||||
title="Anarcho-Capitalism Primer",
|
||||
edges=[Edge(edge_type="references",
|
||||
dst_uri="https://example.com/post-b")],
|
||||
extra={"md5": "deadbeef"}, # your provenance, carried along
|
||||
),
|
||||
])
|
||||
print(stats) # IngestStats(seen=1, inserted=1, ...)
|
||||
|
||||
for hit in search(conn, "free markets", limit=5):
|
||||
print(hit.document_uri, round(hit.score, 3))
|
||||
|
||||
conn.close()
|
||||
|
||||
Define a custom :class:`~arborist.source.Source` for stateful corpora
|
||||
---------------------------------------------------------------------
|
||||
|
||||
When you have a corpus (a directory tree, a paginated API, a database
|
||||
table) it's cleaner to express it as a :class:`Source`. The ABC has one
|
||||
required method, :meth:`iter_documents`, which must be deterministic
|
||||
and idempotent. That's exactly the contract every built-in source under
|
||||
``arborist/sources/`` already implements.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from arborist.embed import Source, Document
|
||||
from arborist.ingest import ingest_source
|
||||
from arborist.embed import open_store
|
||||
|
||||
class TaggedDocs(Source):
|
||||
"""Ingest a list of (uri, body) pairs under a shared tag."""
|
||||
|
||||
source_type = "tagged_example"
|
||||
|
||||
def __init__(self, tag, items):
|
||||
self.tag = tag
|
||||
self._items = items
|
||||
|
||||
def iter_documents(self):
|
||||
for uri, body in self._items:
|
||||
yield Document(
|
||||
uri=uri,
|
||||
content=body,
|
||||
source_type=self.source_type,
|
||||
extra={"tag": self.tag},
|
||||
)
|
||||
|
||||
conn = open_store("data/arborist.db")
|
||||
stats = ingest_source(conn, TaggedDocs("research", [
|
||||
("https://example.com/c", "third doc body about content-addressing."),
|
||||
]))
|
||||
print(stats)
|
||||
conn.close()
|
||||
|
||||
Walk and verify the audit chain
|
||||
-------------------------------
|
||||
|
||||
Every state-changing op writes one row in ``audit_events`` with
|
||||
``event_hash = sha256(prev_event_hash || canonical(body))``. Verifying
|
||||
the chain is just re-running that hash for every row and checking the
|
||||
linkage. (``make chain-check-shards`` does this at scale; the recipe
|
||||
below is the same logic, inlined.)
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import hashlib
|
||||
from arborist.embed import open_store
|
||||
from arborist.store import latest_event_hash
|
||||
|
||||
conn = open_store("data/arborist.db")
|
||||
print("head:", latest_event_hash(conn))
|
||||
|
||||
prev = None
|
||||
bad = 0
|
||||
for seq, eh, ph, body in conn.execute(
|
||||
"SELECT seq, event_hash, prev_event_hash, body "
|
||||
"FROM audit_events ORDER BY seq"
|
||||
):
|
||||
h = hashlib.sha256()
|
||||
if ph is not None:
|
||||
h.update(bytes.fromhex(ph))
|
||||
h.update(body.encode("utf-8", errors="surrogatepass"))
|
||||
if h.hexdigest() != eh or (prev is not None and ph != prev):
|
||||
bad += 1
|
||||
prev = eh
|
||||
|
||||
print(f"chain breaks: {bad}") # 0 = intact
|
||||
conn.close()
|
||||
|
||||
Round-trip a Merkle inclusion proof
|
||||
-----------------------------------
|
||||
|
||||
The proof primitives from :mod:`arborist.merkle` are the Python port of
|
||||
``proxy.unturf.com``'s Go conventions. Use them to re-derive a
|
||||
``document_root`` from its leaves, build a proof for any chunk, and
|
||||
serialize the proof for over-the-wire delivery to another peer.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import json
|
||||
from arborist.embed import open_store
|
||||
from arborist.merkle import (
|
||||
MerkleTree, verify_proof, proof_to_dict, proof_from_dict,
|
||||
)
|
||||
|
||||
conn = open_store("data/arborist.db")
|
||||
|
||||
doc_root_hex, = conn.execute(
|
||||
"SELECT document_root FROM documents LIMIT 1"
|
||||
).fetchone()
|
||||
leaves = [
|
||||
bytes.fromhex(r[0]) for r in conn.execute(
|
||||
"SELECT leaf_hash FROM chunks WHERE document_root=? ORDER BY idx",
|
||||
(doc_root_hex,),
|
||||
)
|
||||
]
|
||||
|
||||
tree = MerkleTree.build(leaves)
|
||||
assert tree.root.hex() == doc_root_hex # bit-identical re-derivation
|
||||
|
||||
proof = tree.proof(0)
|
||||
assert verify_proof(proof) # local round-trip
|
||||
|
||||
blob = json.dumps(proof_to_dict(proof)) # serialize for wire
|
||||
proof_received = proof_from_dict(json.loads(blob))
|
||||
assert verify_proof(proof_received) # any peer can verify
|
||||
|
||||
conn.close()
|
||||
|
||||
Two peers that ingested the same source with the same chunker and
|
||||
canonicalization will compute byte-identical ``document_root`` hashes
|
||||
and accept each other's proofs — see :doc:`api/mesh` for the
|
||||
federation primitives built on top of this property.
|
||||
|
||||
Run a Q&A from Python and read the result programmatically
|
||||
-----------------------------------------------------------
|
||||
|
||||
The CLI (``arborist query`` / ``make query``) is one entry point to
|
||||
the multi-route retrieval + LLM + verifier pipeline. The same surface
|
||||
is callable directly from Python via :func:`arborist.qa.query.query` —
|
||||
useful when you want to drive a batch sweep, integrate into a notebook,
|
||||
or wrap the result in your own application logic. Cache lookups, the
|
||||
8-dim cache_key, the verifier, the run-DAG, and the falsification gate
|
||||
all behave identically to the CLI path.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pathlib import Path
|
||||
from arborist.qa.query import query
|
||||
from arborist.qa.client import OpenAICompatibleClient
|
||||
|
||||
client = OpenAICompatibleClient(
|
||||
base_url="https://hermes.ai.unturf.com/v1", # any OpenAI-compat
|
||||
)
|
||||
|
||||
result = query(
|
||||
question="What is anarcho-capitalism?",
|
||||
qa_db=Path.home() / ".arborist" / "qa.db", # cache lives here
|
||||
chat_client=client,
|
||||
model_id="adamo1139/Hermes-3-Llama-3.1-8B-FP8-Dynamic",
|
||||
shards_dir=Path.home() / ".arborist" / "shards", # OR single_db=...
|
||||
)
|
||||
|
||||
print(result["status"]) # cache_hit | cache_miss_then_written
|
||||
print(result["audit_mode"]) # STRICT | HYBRID | UNGROUNDED
|
||||
print(result["cache_key"]) # 64-char hex
|
||||
print(result["answer_text"])
|
||||
for src in result["sources"]:
|
||||
print(" ->", src["document_uri"], src["document_root"][:12],
|
||||
"role:", src["source_role"])
|
||||
|
||||
The first call writes one providence-cache row + one audit event;
|
||||
the second call with the same question replays from cache in ~100 ms
|
||||
(``status == "cache_hit"``). To exercise the pipeline deterministically
|
||||
in tests, swap the live client for :class:`~arborist.qa.client.StubClient`:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from arborist.qa.client import StubClient
|
||||
|
||||
stub = StubClient(answer='Anarcho-capitalism is "a political '
|
||||
'philosophy that advocates the elimination '
|
||||
'of centralized state dictums".')
|
||||
result = query(
|
||||
question="What is anarcho-capitalism?",
|
||||
qa_db=Path("/tmp/qa.db"),
|
||||
chat_client=stub,
|
||||
model_id="stub/test",
|
||||
single_db=Path("/tmp/arborist.db"),
|
||||
)
|
||||
assert result["audit_mode"] in {"STRICT", "HYBRID", "UNGROUNDED"}
|
||||
|
||||
That stubbed shape is exactly how the test suite drives the runner —
|
||||
the verifier still runs lexically against the assembled context, so
|
||||
the audit_mode classification is real even though the model output
|
||||
is canned.
|
||||
|
||||
For the single-document path (``arborist ask`` / one ``document_root``
|
||||
in hand), use :func:`arborist.qa.runner.ask` instead — same return
|
||||
shape, same cache_key invariants, scoped to one document.
|
||||
|
|
|
|||
71
docs/diagrams/cache-key-8dim.dot
Normal file
71
docs/diagrams/cache-key-8dim.dot
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
// 8-dim cache_key composition for v9.8 admissibility.
|
||||
//
|
||||
// Every providence_cache record is keyed on a SHA-256 over eight
|
||||
// concatenated bytes — the 8-dim invariant. Bumping any one of the
|
||||
// dimensions invalidates prior records on lookup (this is the honesty
|
||||
// property: old answers do not silently serve under new conditions).
|
||||
//
|
||||
// An optional 9th dimension — verifier_policy_hash — exists for *audit
|
||||
// legibility* (#000058). It does NOT add correctness coverage; the
|
||||
// verifier-policy fields are already a subset of governance_policy_hash.
|
||||
// 8-dim is the default write form; 9-dim is opt-in for one-hash-diff
|
||||
// answerability of "did the *verifier* rules change?"
|
||||
//
|
||||
// Render: dot -Tsvg cache-key-8dim.dot -o cache-key-8dim.svg
|
||||
|
||||
digraph cache_key_8dim {
|
||||
rankdir=TB
|
||||
node [shape=box, style="rounded,filled", fontname="Helvetica", fontsize=10]
|
||||
edge [fontname="Helvetica", fontsize=9]
|
||||
bgcolor="white"
|
||||
ranksep=0.6
|
||||
nodesep=0.3
|
||||
|
||||
subgraph cluster_dims {
|
||||
label="EIGHT MANDATORY DIMENSIONS (concat in fixed order)"
|
||||
labeljust="l"
|
||||
fontname="Helvetica-Bold"
|
||||
style="rounded,filled"
|
||||
fillcolor="#f5faff"
|
||||
margin=14
|
||||
|
||||
// Top row: corpus / question / model state
|
||||
d1 [label="1. source_root\nMerkle root over\ningested source(s)", fillcolor="#e6f0ff"]
|
||||
d2 [label="2. question_hash\ndedup-mode aware\n(strict | equiv. class)", fillcolor="#e6f0ff"]
|
||||
d3 [label="3. model_profile_hash\nmodel id + sampling +\nsystem prompt + tools", fillcolor="#e6f0ff"]
|
||||
d4 [label="4. conversation_hash\nprior turns committed\ninto the cache_key", fillcolor="#e6f0ff"]
|
||||
|
||||
// Bottom row: policy / pinned versions
|
||||
d5 [label="5. governance_policy_hash\nverifier + answer_mode +\nquantifier guard + …\n(superset of #9)", fillcolor="#e6f0ff"]
|
||||
d6 [label="6. schema_version\nv9.8.0\nschema-level compat", fillcolor="#e6f0ff"]
|
||||
d7 [label="7. canonicalization_version\nnorm-v1\npinned preprocessing", fillcolor="#e6f0ff"]
|
||||
d8 [label="8. chunking_version\ntok-512-v1\npinned leaf boundaries", fillcolor="#e6f0ff"]
|
||||
|
||||
{rank=same; d1; d2; d3; d4}
|
||||
{rank=same; d5; d6; d7; d8}
|
||||
|
||||
// Invisible spine to enforce the 2-row layout
|
||||
d1 -> d5 [style=invis]
|
||||
d2 -> d6 [style=invis]
|
||||
d3 -> d7 [style=invis]
|
||||
d4 -> d8 [style=invis]
|
||||
}
|
||||
|
||||
// Optional 9th — render as sibling-of-cluster
|
||||
d9 [label="9. verifier_policy_hash\n(opt-in, #000058)\nsubset of #5; exists for\none-hash-diff legibility,\nNOT new coverage", fillcolor="#fff0e0", style="rounded,filled,dashed"]
|
||||
|
||||
sha [label="sha256(d1 ‖ d2 ‖ d3 ‖ d4 ‖ d5 ‖ d6 ‖ d7 ‖ d8 [ ‖ d9 ])", fillcolor="#999999", fontcolor="white", shape=cds, fontsize=11]
|
||||
|
||||
key [label="cache_key (32 bytes, hex)\nkeys one providence_cache row", fillcolor="#28a745", fontcolor="white", shape=note]
|
||||
|
||||
invariant [label="HONESTY PROPERTY\nbumping ANY dimension invalidates prior\nrecords on lookup — no silent reuse\nunder new conditions", fillcolor="#fff0e0", shape=note]
|
||||
|
||||
// Cluster -> sha (one collapsed edge by anchoring on d8)
|
||||
d5 -> sha
|
||||
d6 -> sha
|
||||
d7 -> sha
|
||||
d8 -> sha
|
||||
d9 -> sha [style=dashed, label="opt-in"]
|
||||
|
||||
sha -> key -> invariant [style=dotted, color="#666666"]
|
||||
}
|
||||
BIN
docs/diagrams/cache-key-8dim.png
Normal file
BIN
docs/diagrams/cache-key-8dim.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 97 KiB |
166
docs/diagrams/cache-key-8dim.svg
Normal file
166
docs/diagrams/cache-key-8dim.svg
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Generated by graphviz version 2.43.0 (0)
|
||||
-->
|
||||
<!-- Title: cache_key_8dim Pages: 1 -->
|
||||
<svg width="805pt" height="470pt"
|
||||
viewBox="0.00 0.00 804.50 470.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 466)">
|
||||
<title>cache_key_8dim</title>
|
||||
<polygon fill="white" stroke="transparent" points="-4,4 -4,-466 800.5,-466 800.5,4 -4,4"/>
|
||||
<g id="clust1" class="cluster">
|
||||
<title>cluster_dims</title>
|
||||
<path fill="#f5faff" stroke="black" d="M20,-259.5C20,-259.5 639,-259.5 639,-259.5 645,-259.5 651,-265.5 651,-271.5 651,-271.5 651,-442 651,-442 651,-448 645,-454 639,-454 639,-454 20,-454 20,-454 14,-454 8,-448 8,-442 8,-442 8,-271.5 8,-271.5 8,-265.5 14,-259.5 20,-259.5"/>
|
||||
<text text-anchor="middle" x="237.5" y="-438.8" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="14.00">EIGHT MANDATORY DIMENSIONS  (concat in fixed order)</text>
|
||||
</g>
|
||||
<!-- d1 -->
|
||||
<g id="node1" class="node">
|
||||
<title>d1</title>
|
||||
<path fill="#e6f0ff" stroke="black" d="M137.5,-417C137.5,-417 54.5,-417 54.5,-417 48.5,-417 42.5,-411 42.5,-405 42.5,-405 42.5,-388 42.5,-388 42.5,-382 48.5,-376 54.5,-376 54.5,-376 137.5,-376 137.5,-376 143.5,-376 149.5,-382 149.5,-388 149.5,-388 149.5,-405 149.5,-405 149.5,-411 143.5,-417 137.5,-417"/>
|
||||
<text text-anchor="middle" x="96" y="-405" font-family="Helvetica,sans-Serif" font-size="10.00">1. source_root</text>
|
||||
<text text-anchor="middle" x="96" y="-394" font-family="Helvetica,sans-Serif" font-size="10.00">Merkle root over</text>
|
||||
<text text-anchor="middle" x="96" y="-383" font-family="Helvetica,sans-Serif" font-size="10.00">ingested source(s)</text>
|
||||
</g>
|
||||
<!-- d5 -->
|
||||
<g id="node5" class="node">
|
||||
<title>d5</title>
|
||||
<path fill="#e6f0ff" stroke="black" d="M158.5,-325.5C158.5,-325.5 33.5,-325.5 33.5,-325.5 27.5,-325.5 21.5,-319.5 21.5,-313.5 21.5,-313.5 21.5,-285.5 21.5,-285.5 21.5,-279.5 27.5,-273.5 33.5,-273.5 33.5,-273.5 158.5,-273.5 158.5,-273.5 164.5,-273.5 170.5,-279.5 170.5,-285.5 170.5,-285.5 170.5,-313.5 170.5,-313.5 170.5,-319.5 164.5,-325.5 158.5,-325.5"/>
|
||||
<text text-anchor="middle" x="96" y="-313.5" font-family="Helvetica,sans-Serif" font-size="10.00">5. governance_policy_hash</text>
|
||||
<text text-anchor="middle" x="96" y="-302.5" font-family="Helvetica,sans-Serif" font-size="10.00">verifier + answer_mode +</text>
|
||||
<text text-anchor="middle" x="96" y="-291.5" font-family="Helvetica,sans-Serif" font-size="10.00">quantifier guard + …</text>
|
||||
<text text-anchor="middle" x="96" y="-280.5" font-family="Helvetica,sans-Serif" font-size="10.00">(superset of #9)</text>
|
||||
</g>
|
||||
<!-- d1->d5 -->
|
||||
<!-- d2 -->
|
||||
<g id="node2" class="node">
|
||||
<title>d2</title>
|
||||
<path fill="#e6f0ff" stroke="black" d="M299.5,-417C299.5,-417 208.5,-417 208.5,-417 202.5,-417 196.5,-411 196.5,-405 196.5,-405 196.5,-388 196.5,-388 196.5,-382 202.5,-376 208.5,-376 208.5,-376 299.5,-376 299.5,-376 305.5,-376 311.5,-382 311.5,-388 311.5,-388 311.5,-405 311.5,-405 311.5,-411 305.5,-417 299.5,-417"/>
|
||||
<text text-anchor="middle" x="254" y="-405" font-family="Helvetica,sans-Serif" font-size="10.00">2. question_hash</text>
|
||||
<text text-anchor="middle" x="254" y="-394" font-family="Helvetica,sans-Serif" font-size="10.00">dedup-mode aware</text>
|
||||
<text text-anchor="middle" x="254" y="-383" font-family="Helvetica,sans-Serif" font-size="10.00">(strict | equiv. class)</text>
|
||||
</g>
|
||||
<!-- d6 -->
|
||||
<g id="node6" class="node">
|
||||
<title>d6</title>
|
||||
<path fill="#e6f0ff" stroke="black" d="M303,-320C303,-320 205,-320 205,-320 199,-320 193,-314 193,-308 193,-308 193,-291 193,-291 193,-285 199,-279 205,-279 205,-279 303,-279 303,-279 309,-279 315,-285 315,-291 315,-291 315,-308 315,-308 315,-314 309,-320 303,-320"/>
|
||||
<text text-anchor="middle" x="254" y="-308" font-family="Helvetica,sans-Serif" font-size="10.00">6. schema_version</text>
|
||||
<text text-anchor="middle" x="254" y="-297" font-family="Helvetica,sans-Serif" font-size="10.00">v9.8.0</text>
|
||||
<text text-anchor="middle" x="254" y="-286" font-family="Helvetica,sans-Serif" font-size="10.00">schema-level compat</text>
|
||||
</g>
|
||||
<!-- d2->d6 -->
|
||||
<!-- d3 -->
|
||||
<g id="node3" class="node">
|
||||
<title>d3</title>
|
||||
<path fill="#e6f0ff" stroke="black" d="M465,-417C465,-417 359,-417 359,-417 353,-417 347,-411 347,-405 347,-405 347,-388 347,-388 347,-382 353,-376 359,-376 359,-376 465,-376 465,-376 471,-376 477,-382 477,-388 477,-388 477,-405 477,-405 477,-411 471,-417 465,-417"/>
|
||||
<text text-anchor="middle" x="412" y="-405" font-family="Helvetica,sans-Serif" font-size="10.00">3. model_profile_hash</text>
|
||||
<text text-anchor="middle" x="412" y="-394" font-family="Helvetica,sans-Serif" font-size="10.00">model id + sampling +</text>
|
||||
<text text-anchor="middle" x="412" y="-383" font-family="Helvetica,sans-Serif" font-size="10.00">system prompt + tools</text>
|
||||
</g>
|
||||
<!-- d7 -->
|
||||
<g id="node7" class="node">
|
||||
<title>d7</title>
|
||||
<path fill="#e6f0ff" stroke="black" d="M474.5,-320C474.5,-320 349.5,-320 349.5,-320 343.5,-320 337.5,-314 337.5,-308 337.5,-308 337.5,-291 337.5,-291 337.5,-285 343.5,-279 349.5,-279 349.5,-279 474.5,-279 474.5,-279 480.5,-279 486.5,-285 486.5,-291 486.5,-291 486.5,-308 486.5,-308 486.5,-314 480.5,-320 474.5,-320"/>
|
||||
<text text-anchor="middle" x="412" y="-308" font-family="Helvetica,sans-Serif" font-size="10.00">7. canonicalization_version</text>
|
||||
<text text-anchor="middle" x="412" y="-297" font-family="Helvetica,sans-Serif" font-size="10.00">norm-v1</text>
|
||||
<text text-anchor="middle" x="412" y="-286" font-family="Helvetica,sans-Serif" font-size="10.00">pinned preprocessing</text>
|
||||
</g>
|
||||
<!-- d3->d7 -->
|
||||
<!-- d4 -->
|
||||
<g id="node4" class="node">
|
||||
<title>d4</title>
|
||||
<path fill="#e6f0ff" stroke="black" d="M622.5,-417C622.5,-417 523.5,-417 523.5,-417 517.5,-417 511.5,-411 511.5,-405 511.5,-405 511.5,-388 511.5,-388 511.5,-382 517.5,-376 523.5,-376 523.5,-376 622.5,-376 622.5,-376 628.5,-376 634.5,-382 634.5,-388 634.5,-388 634.5,-405 634.5,-405 634.5,-411 628.5,-417 622.5,-417"/>
|
||||
<text text-anchor="middle" x="573" y="-405" font-family="Helvetica,sans-Serif" font-size="10.00">4. conversation_hash</text>
|
||||
<text text-anchor="middle" x="573" y="-394" font-family="Helvetica,sans-Serif" font-size="10.00">prior turns committed</text>
|
||||
<text text-anchor="middle" x="573" y="-383" font-family="Helvetica,sans-Serif" font-size="10.00">into the cache_key</text>
|
||||
</g>
|
||||
<!-- d8 -->
|
||||
<g id="node8" class="node">
|
||||
<title>d8</title>
|
||||
<path fill="#e6f0ff" stroke="black" d="M625,-320C625,-320 521,-320 521,-320 515,-320 509,-314 509,-308 509,-308 509,-291 509,-291 509,-285 515,-279 521,-279 521,-279 625,-279 625,-279 631,-279 637,-285 637,-291 637,-291 637,-308 637,-308 637,-314 631,-320 625,-320"/>
|
||||
<text text-anchor="middle" x="573" y="-308" font-family="Helvetica,sans-Serif" font-size="10.00">8. chunking_version</text>
|
||||
<text text-anchor="middle" x="573" y="-297" font-family="Helvetica,sans-Serif" font-size="10.00">tok-512-v1</text>
|
||||
<text text-anchor="middle" x="573" y="-286" font-family="Helvetica,sans-Serif" font-size="10.00">pinned leaf boundaries</text>
|
||||
</g>
|
||||
<!-- d4->d8 -->
|
||||
<!-- sha -->
|
||||
<g id="node10" class="node">
|
||||
<title>sha</title>
|
||||
<polygon fill="#999999" stroke="black" points="554.5,-208 257.5,-208 257.5,-184 554.5,-184 566.5,-196 554.5,-208"/>
|
||||
<text text-anchor="middle" x="412" y="-193.2" font-family="Helvetica,sans-Serif" font-size="11.00" fill="white">sha256(d1 ‖ d2 ‖ d3 ‖ d4 ‖ d5 ‖ d6 ‖ d7 ‖ d8  [ ‖ d9 ])</text>
|
||||
</g>
|
||||
<!-- d5->sha -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>d5->sha</title>
|
||||
<path fill="none" stroke="black" d="M147.75,-273.42C158.91,-268.47 170.74,-263.55 182,-259.5 229.42,-242.43 283.77,-227.46 327.73,-216.45"/>
|
||||
<polygon fill="black" stroke="black" points="328.66,-219.82 337.52,-214.02 326.97,-213.03 328.66,-219.82"/>
|
||||
</g>
|
||||
<!-- d6->sha -->
|
||||
<g id="edge6" class="edge">
|
||||
<title>d6->sha</title>
|
||||
<path fill="none" stroke="black" d="M284.46,-278.93C310.84,-261.98 349.01,-237.47 376.71,-219.67"/>
|
||||
<polygon fill="black" stroke="black" points="378.79,-222.5 385.31,-214.15 375,-216.61 378.79,-222.5"/>
|
||||
</g>
|
||||
<!-- d7->sha -->
|
||||
<g id="edge7" class="edge">
|
||||
<title>d7->sha</title>
|
||||
<path fill="none" stroke="black" d="M412,-278.93C412,-263.38 412,-241.45 412,-224.19"/>
|
||||
<polygon fill="black" stroke="black" points="415.5,-224.15 412,-214.15 408.5,-224.15 415.5,-224.15"/>
|
||||
</g>
|
||||
<!-- d8->sha -->
|
||||
<g id="edge8" class="edge">
|
||||
<title>d8->sha</title>
|
||||
<path fill="none" stroke="black" d="M541.96,-278.93C515.08,-261.98 476.19,-237.47 447.96,-219.67"/>
|
||||
<polygon fill="black" stroke="black" points="449.52,-216.52 439.2,-214.15 445.79,-222.44 449.52,-216.52"/>
|
||||
</g>
|
||||
<!-- d9 -->
|
||||
<g id="node9" class="node">
|
||||
<title>d9</title>
|
||||
<path fill="#fff0e0" stroke="black" stroke-dasharray="5,2" d="M784.5,-331C784.5,-331 677.5,-331 677.5,-331 671.5,-331 665.5,-325 665.5,-319 665.5,-319 665.5,-280 665.5,-280 665.5,-274 671.5,-268 677.5,-268 677.5,-268 784.5,-268 784.5,-268 790.5,-268 796.5,-274 796.5,-280 796.5,-280 796.5,-319 796.5,-319 796.5,-325 790.5,-331 784.5,-331"/>
|
||||
<text text-anchor="middle" x="731" y="-319" font-family="Helvetica,sans-Serif" font-size="10.00">9. verifier_policy_hash</text>
|
||||
<text text-anchor="middle" x="731" y="-308" font-family="Helvetica,sans-Serif" font-size="10.00">(opt-in, #000058)</text>
|
||||
<text text-anchor="middle" x="731" y="-297" font-family="Helvetica,sans-Serif" font-size="10.00">subset of #5; exists for</text>
|
||||
<text text-anchor="middle" x="731" y="-286" font-family="Helvetica,sans-Serif" font-size="10.00">one-hash-diff legibility,</text>
|
||||
<text text-anchor="middle" x="731" y="-275" font-family="Helvetica,sans-Serif" font-size="10.00">NOT new coverage</text>
|
||||
</g>
|
||||
<!-- d9->sha -->
|
||||
<g id="edge9" class="edge">
|
||||
<title>d9->sha</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M675.54,-267.89C669.05,-264.84 662.44,-261.96 656,-259.5 608.43,-241.32 553.65,-226.74 508.06,-216.26"/>
|
||||
<polygon fill="black" stroke="black" points="508.71,-212.82 498.18,-214.02 507.16,-219.64 508.71,-212.82"/>
|
||||
<text text-anchor="middle" x="630.5" y="-238.8" font-family="Helvetica,sans-Serif" font-size="9.00">opt-in</text>
|
||||
</g>
|
||||
<!-- key -->
|
||||
<g id="node11" class="node">
|
||||
<title>key</title>
|
||||
<polygon fill="#28a745" stroke="black" points="492,-133 326,-133 326,-97 498,-97 498,-127 492,-133"/>
|
||||
<polyline fill="none" stroke="black" points="492,-133 492,-127 "/>
|
||||
<polyline fill="none" stroke="black" points="498,-127 492,-127 "/>
|
||||
<text text-anchor="middle" x="412" y="-118" font-family="Helvetica,sans-Serif" font-size="10.00" fill="white">cache_key (32 bytes, hex)</text>
|
||||
<text text-anchor="middle" x="412" y="-107" font-family="Helvetica,sans-Serif" font-size="10.00" fill="white">keys one providence_cache row</text>
|
||||
</g>
|
||||
<!-- sha->key -->
|
||||
<g id="edge10" class="edge">
|
||||
<title>sha->key</title>
|
||||
<path fill="none" stroke="#666666" stroke-dasharray="1,5" d="M412,-177.86C412,-167.71 412,-154.63 412,-143.12"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="415.5,-143.11 412,-133.11 408.5,-143.11 415.5,-143.11"/>
|
||||
</g>
|
||||
<!-- invariant -->
|
||||
<g id="node12" class="node">
|
||||
<title>invariant</title>
|
||||
<polygon fill="#fff0e0" stroke="black" points="515.5,-52 302.5,-52 302.5,0 521.5,0 521.5,-46 515.5,-52"/>
|
||||
<polyline fill="none" stroke="black" points="515.5,-52 515.5,-46 "/>
|
||||
<polyline fill="none" stroke="black" points="521.5,-46 515.5,-46 "/>
|
||||
<text text-anchor="middle" x="412" y="-40" font-family="Helvetica,sans-Serif" font-size="10.00">HONESTY PROPERTY</text>
|
||||
<text text-anchor="middle" x="412" y="-29" font-family="Helvetica,sans-Serif" font-size="10.00">bumping ANY dimension invalidates prior</text>
|
||||
<text text-anchor="middle" x="412" y="-18" font-family="Helvetica,sans-Serif" font-size="10.00">records on lookup — no silent reuse</text>
|
||||
<text text-anchor="middle" x="412" y="-7" font-family="Helvetica,sans-Serif" font-size="10.00">under new conditions</text>
|
||||
</g>
|
||||
<!-- key->invariant -->
|
||||
<g id="edge11" class="edge">
|
||||
<title>key->invariant</title>
|
||||
<path fill="none" stroke="#666666" stroke-dasharray="1,5" d="M412,-96.81C412,-86.93 412,-74.15 412,-62.22"/>
|
||||
<polygon fill="#666666" stroke="#666666" points="415.5,-62.06 412,-52.06 408.5,-62.06 415.5,-62.06"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 12 KiB |
50
docs/diagrams/falsification-states.dot
Normal file
50
docs/diagrams/falsification-states.dot
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
// falsification_state state machine — the lifecycle of a providence
|
||||
// record after it lands in cache.
|
||||
//
|
||||
// Cache lookups filter on state='live'. Drift (re-ingest yielding a
|
||||
// different document_root than the one bound into the record) flips
|
||||
// the record to 'stale'. Explicit human/operator override flips to
|
||||
// 'failed' (audit-preserving) or removes the row entirely via burn
|
||||
// (which is refused if the record has children unless FORCE=1).
|
||||
//
|
||||
// Render: dot -Tsvg falsification-states.dot -o falsification-states.svg
|
||||
|
||||
digraph falsification_states {
|
||||
rankdir=LR
|
||||
node [shape=ellipse, style="filled", fontname="Helvetica", fontsize=10]
|
||||
edge [fontname="Helvetica", fontsize=9]
|
||||
bgcolor="white"
|
||||
|
||||
start [label="cache write\n(verifier sets audit_mode)", shape=note, fillcolor="#fff7e6"]
|
||||
|
||||
live [label="LIVE\ncache lookups\nreturn this row", fillcolor="#28a745", fontcolor="white"]
|
||||
stale [label="STALE\nsource drifted\n(document_root changed\non re-ingest)", fillcolor="#ffc107"]
|
||||
failed [label="FAILED\nhuman / operator\nfalsified", fillcolor="#dc3545", fontcolor="white"]
|
||||
quarantined [label="QUARANTINED\nverifier downgrade\npending review", fillcolor="#6c757d", fontcolor="white"]
|
||||
|
||||
gone [label="(burn — row deleted)\nrefused if record has children\nunless FORCE=1", shape=octagon, fillcolor="#888888", fontcolor="white"]
|
||||
|
||||
audit [label="every transition\nwrites one audit_event\nchain remains intact", shape=note, fillcolor="#fff0e0"]
|
||||
|
||||
start -> live [label="initial state\nif verifier produced\nany audit_mode"]
|
||||
|
||||
live -> stale [label="re-ingest produces\ndifferent document_root\n(drift detection)"]
|
||||
live -> failed [label="make falsify KEY=…\nREASON='…'\n(audit-preserving)"]
|
||||
live -> quarantined [label="verifier rule change\n+ promotion gate\n(rare)"]
|
||||
|
||||
stale -> live [label="re-ingest matches\nbound root again\n(corpus returned to\nprior state)", style=dotted]
|
||||
quarantined -> live [label="review passed", style=dotted]
|
||||
quarantined -> failed [label="review rejected", style=dotted]
|
||||
|
||||
failed -> gone [label="make burn KEY=…\nREASON='…'\n(kindergarten only)", color="#aa0000"]
|
||||
stale -> gone [label="make burn KEY=…", color="#aa0000", style=dashed]
|
||||
|
||||
// Audit-chain annotation
|
||||
live -> audit [style=dashed, color="#888888"]
|
||||
stale -> audit [style=dashed, color="#888888"]
|
||||
failed -> audit [style=dashed, color="#888888"]
|
||||
quarantined -> audit [style=dashed, color="#888888"]
|
||||
|
||||
{rank=same; live; stale}
|
||||
{rank=same; failed; quarantined}
|
||||
}
|
||||
BIN
docs/diagrams/falsification-states.png
Normal file
BIN
docs/diagrams/falsification-states.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 109 KiB |
173
docs/diagrams/falsification-states.svg
Normal file
173
docs/diagrams/falsification-states.svg
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Generated by graphviz version 2.43.0 (0)
|
||||
-->
|
||||
<!-- Title: falsification_states Pages: 1 -->
|
||||
<svg width="1116pt" height="253pt"
|
||||
viewBox="0.00 0.00 1116.28 253.46" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 249.46)">
|
||||
<title>falsification_states</title>
|
||||
<polygon fill="white" stroke="transparent" points="-4,4 -4,-249.46 1112.28,-249.46 1112.28,4 -4,4"/>
|
||||
<!-- start -->
|
||||
<g id="node1" class="node">
|
||||
<title>start</title>
|
||||
<polygon fill="#fff7e6" stroke="black" points="137,-103.69 0,-103.69 0,-67.69 143,-67.69 143,-97.69 137,-103.69"/>
|
||||
<polyline fill="none" stroke="black" points="137,-103.69 137,-97.69 "/>
|
||||
<polyline fill="none" stroke="black" points="143,-97.69 137,-97.69 "/>
|
||||
<text text-anchor="middle" x="71.5" y="-88.69" font-family="Helvetica,sans-Serif" font-size="10.00">cache write</text>
|
||||
<text text-anchor="middle" x="71.5" y="-77.69" font-family="Helvetica,sans-Serif" font-size="10.00">(verifier sets audit_mode)</text>
|
||||
</g>
|
||||
<!-- live -->
|
||||
<g id="node2" class="node">
|
||||
<title>live</title>
|
||||
<ellipse fill="#28a745" stroke="black" cx="363.58" cy="-85.69" rx="62.45" ry="28.98"/>
|
||||
<text text-anchor="middle" x="363.58" y="-94.19" font-family="Helvetica,sans-Serif" font-size="10.00" fill="white">LIVE</text>
|
||||
<text text-anchor="middle" x="363.58" y="-83.19" font-family="Helvetica,sans-Serif" font-size="10.00" fill="white">cache lookups</text>
|
||||
<text text-anchor="middle" x="363.58" y="-72.19" font-family="Helvetica,sans-Serif" font-size="10.00" fill="white">return this row</text>
|
||||
</g>
|
||||
<!-- start->live -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>start->live</title>
|
||||
<path fill="none" stroke="black" d="M143.09,-85.69C187.9,-85.69 245.71,-85.69 290.76,-85.69"/>
|
||||
<polygon fill="black" stroke="black" points="291.04,-89.19 301.04,-85.69 291.04,-82.19 291.04,-89.19"/>
|
||||
<text text-anchor="middle" x="204.5" y="-108.49" font-family="Helvetica,sans-Serif" font-size="9.00">initial state</text>
|
||||
<text text-anchor="middle" x="204.5" y="-98.49" font-family="Helvetica,sans-Serif" font-size="9.00">if verifier produced</text>
|
||||
<text text-anchor="middle" x="204.5" y="-88.49" font-family="Helvetica,sans-Serif" font-size="9.00">any audit_mode</text>
|
||||
</g>
|
||||
<!-- stale -->
|
||||
<g id="node3" class="node">
|
||||
<title>stale</title>
|
||||
<ellipse fill="#ffc107" stroke="black" cx="363.58" cy="-208.69" rx="97.66" ry="36.54"/>
|
||||
<text text-anchor="middle" x="363.58" y="-222.69" font-family="Helvetica,sans-Serif" font-size="10.00">STALE</text>
|
||||
<text text-anchor="middle" x="363.58" y="-211.69" font-family="Helvetica,sans-Serif" font-size="10.00">source drifted</text>
|
||||
<text text-anchor="middle" x="363.58" y="-200.69" font-family="Helvetica,sans-Serif" font-size="10.00">(document_root changed</text>
|
||||
<text text-anchor="middle" x="363.58" y="-189.69" font-family="Helvetica,sans-Serif" font-size="10.00">on re-ingest)</text>
|
||||
</g>
|
||||
<!-- live->stale -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>live->stale</title>
|
||||
<path fill="none" stroke="black" d="M363.58,-114.84C363.58,-128.83 363.58,-145.93 363.58,-161.69"/>
|
||||
<polygon fill="black" stroke="black" points="360.08,-161.81 363.58,-171.81 367.08,-161.81 360.08,-161.81"/>
|
||||
<text text-anchor="middle" x="345.58" y="-151.1" font-family="Helvetica,sans-Serif" font-size="9.00">re-ingest produces</text>
|
||||
<text text-anchor="middle" x="345.58" y="-141.1" font-family="Helvetica,sans-Serif" font-size="9.00">different document_root</text>
|
||||
<text text-anchor="middle" x="345.58" y="-131.1" font-family="Helvetica,sans-Serif" font-size="9.00">(drift detection)</text>
|
||||
</g>
|
||||
<!-- failed -->
|
||||
<g id="node4" class="node">
|
||||
<title>failed</title>
|
||||
<ellipse fill="#dc3545" stroke="black" cx="664.53" cy="-44.69" rx="71.34" ry="28.98"/>
|
||||
<text text-anchor="middle" x="664.53" y="-53.19" font-family="Helvetica,sans-Serif" font-size="10.00" fill="white">FAILED</text>
|
||||
<text text-anchor="middle" x="664.53" y="-42.19" font-family="Helvetica,sans-Serif" font-size="10.00" fill="white">human / operator</text>
|
||||
<text text-anchor="middle" x="664.53" y="-31.19" font-family="Helvetica,sans-Serif" font-size="10.00" fill="white">falsified</text>
|
||||
</g>
|
||||
<!-- live->failed -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>live->failed</title>
|
||||
<path fill="none" stroke="black" d="M410.87,-66.78C431.42,-59.32 456.12,-51.6 479.16,-47.69 512.91,-41.96 550.63,-40.49 583.12,-40.73"/>
|
||||
<polygon fill="black" stroke="black" points="583.42,-44.23 593.47,-40.86 583.51,-37.23 583.42,-44.23"/>
|
||||
<text text-anchor="middle" x="524.66" y="-70.49" font-family="Helvetica,sans-Serif" font-size="9.00">make falsify KEY=…</text>
|
||||
<text text-anchor="middle" x="524.66" y="-60.49" font-family="Helvetica,sans-Serif" font-size="9.00">REASON='…'</text>
|
||||
<text text-anchor="middle" x="524.66" y="-50.49" font-family="Helvetica,sans-Serif" font-size="9.00">(audit-preserving)</text>
|
||||
</g>
|
||||
<!-- quarantined -->
|
||||
<g id="node5" class="node">
|
||||
<title>quarantined</title>
|
||||
<ellipse fill="#6c757d" stroke="black" cx="664.53" cy="-137.69" rx="76.24" ry="28.98"/>
|
||||
<text text-anchor="middle" x="664.53" y="-146.19" font-family="Helvetica,sans-Serif" font-size="10.00" fill="white">QUARANTINED</text>
|
||||
<text text-anchor="middle" x="664.53" y="-135.19" font-family="Helvetica,sans-Serif" font-size="10.00" fill="white">verifier downgrade</text>
|
||||
<text text-anchor="middle" x="664.53" y="-124.19" font-family="Helvetica,sans-Serif" font-size="10.00" fill="white">pending review</text>
|
||||
</g>
|
||||
<!-- live->quarantined -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>live->quarantined</title>
|
||||
<path fill="none" stroke="black" d="M418.56,-99.54C437.62,-104.13 459.27,-109.01 479.16,-112.69 512.26,-118.82 548.97,-124.1 580.86,-128.21"/>
|
||||
<polygon fill="black" stroke="black" points="580.67,-131.72 591.03,-129.5 581.55,-124.77 580.67,-131.72"/>
|
||||
<text text-anchor="middle" x="524.66" y="-150.49" font-family="Helvetica,sans-Serif" font-size="9.00">verifier rule change</text>
|
||||
<text text-anchor="middle" x="524.66" y="-140.49" font-family="Helvetica,sans-Serif" font-size="9.00">+ promotion gate</text>
|
||||
<text text-anchor="middle" x="524.66" y="-130.49" font-family="Helvetica,sans-Serif" font-size="9.00">(rare)</text>
|
||||
</g>
|
||||
<!-- audit -->
|
||||
<g id="node7" class="node">
|
||||
<title>audit</title>
|
||||
<polygon fill="#fff0e0" stroke="black" points="1044.59,-86.19 922.59,-86.19 922.59,-45.19 1050.59,-45.19 1050.59,-80.19 1044.59,-86.19"/>
|
||||
<polyline fill="none" stroke="black" points="1044.59,-86.19 1044.59,-80.19 "/>
|
||||
<polyline fill="none" stroke="black" points="1050.59,-80.19 1044.59,-80.19 "/>
|
||||
<text text-anchor="middle" x="986.59" y="-74.19" font-family="Helvetica,sans-Serif" font-size="10.00">every transition</text>
|
||||
<text text-anchor="middle" x="986.59" y="-63.19" font-family="Helvetica,sans-Serif" font-size="10.00">writes one audit_event</text>
|
||||
<text text-anchor="middle" x="986.59" y="-52.19" font-family="Helvetica,sans-Serif" font-size="10.00">chain remains intact</text>
|
||||
</g>
|
||||
<!-- live->audit -->
|
||||
<g id="edge10" class="edge">
|
||||
<title>live->audit</title>
|
||||
<path fill="none" stroke="#888888" stroke-dasharray="5,2" d="M406.98,-64.91C451.01,-44.73 522.52,-15.84 588.16,-6.69 655.39,2.68 673.49,1.32 740.9,-6.69 799.56,-13.66 864.5,-29.72 912.73,-43.33"/>
|
||||
<polygon fill="#888888" stroke="#888888" points="911.88,-46.73 922.45,-46.1 913.8,-40 911.88,-46.73"/>
|
||||
</g>
|
||||
<!-- stale->live -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>stale->live</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="1,5" d="M409.27,-175.91C411.04,-160.09 411.37,-133.48 409.96,-115.73"/>
|
||||
<polygon fill="black" stroke="black" points="413.43,-115.31 408.82,-105.77 406.48,-116.1 413.43,-115.31"/>
|
||||
<text text-anchor="middle" x="386.58" y="-156.1" font-family="Helvetica,sans-Serif" font-size="9.00">re-ingest matches</text>
|
||||
<text text-anchor="middle" x="386.58" y="-146.1" font-family="Helvetica,sans-Serif" font-size="9.00">bound root again</text>
|
||||
<text text-anchor="middle" x="386.58" y="-136.1" font-family="Helvetica,sans-Serif" font-size="9.00">(corpus returned to</text>
|
||||
<text text-anchor="middle" x="386.58" y="-126.1" font-family="Helvetica,sans-Serif" font-size="9.00">prior state)</text>
|
||||
</g>
|
||||
<!-- gone -->
|
||||
<g id="node6" class="node">
|
||||
<title>gone</title>
|
||||
<polygon fill="#888888" stroke="black" points="1108.48,-131.74 1108.48,-157.64 1037.08,-175.95 936.1,-175.95 864.7,-157.64 864.7,-131.74 936.1,-113.43 1037.08,-113.43 1108.48,-131.74"/>
|
||||
<text text-anchor="middle" x="986.59" y="-153.19" font-family="Helvetica,sans-Serif" font-size="10.00" fill="white">(burn — row deleted)</text>
|
||||
<text text-anchor="middle" x="986.59" y="-142.19" font-family="Helvetica,sans-Serif" font-size="10.00" fill="white">refused if record has children</text>
|
||||
<text text-anchor="middle" x="986.59" y="-131.19" font-family="Helvetica,sans-Serif" font-size="10.00" fill="white">unless FORCE=1</text>
|
||||
</g>
|
||||
<!-- stale->gone -->
|
||||
<g id="edge9" class="edge">
|
||||
<title>stale->gone</title>
|
||||
<path fill="none" stroke="#aa0000" stroke-dasharray="5,2" d="M456.51,-220.28C554.5,-229.96 713.58,-237.97 846.9,-208.69 873.31,-202.89 900.68,-191.56 924.06,-180.02"/>
|
||||
<polygon fill="#aa0000" stroke="#aa0000" points="925.8,-183.06 933.15,-175.43 922.65,-176.81 925.8,-183.06"/>
|
||||
<text text-anchor="middle" x="664.53" y="-231.49" font-family="Helvetica,sans-Serif" font-size="9.00">make burn KEY=…</text>
|
||||
</g>
|
||||
<!-- stale->audit -->
|
||||
<g id="edge11" class="edge">
|
||||
<title>stale->audit</title>
|
||||
<path fill="none" stroke="#888888" stroke-dasharray="5,2" d="M461.26,-207.66C537.97,-205.07 647.47,-197.4 740.9,-175.69 790.1,-164.26 808.25,-167.22 846.9,-134.69 858.79,-124.68 852.72,-114.36 864.9,-104.69 878.73,-93.7 895.75,-85.76 912.6,-80.05"/>
|
||||
<polygon fill="#888888" stroke="#888888" points="913.99,-83.28 922.48,-76.94 911.89,-76.61 913.99,-83.28"/>
|
||||
</g>
|
||||
<!-- failed->gone -->
|
||||
<g id="edge8" class="edge">
|
||||
<title>failed->gone</title>
|
||||
<path fill="none" stroke="#aa0000" d="M721.65,-62.22C770.54,-77.5 842.23,-99.9 898.57,-117.5"/>
|
||||
<polygon fill="#aa0000" stroke="#aa0000" points="897.59,-120.86 908.18,-120.5 899.68,-114.18 897.59,-120.86"/>
|
||||
<text text-anchor="middle" x="802.9" y="-123.49" font-family="Helvetica,sans-Serif" font-size="9.00">make burn KEY=…</text>
|
||||
<text text-anchor="middle" x="802.9" y="-113.49" font-family="Helvetica,sans-Serif" font-size="9.00">REASON='…'</text>
|
||||
<text text-anchor="middle" x="802.9" y="-103.49" font-family="Helvetica,sans-Serif" font-size="9.00">(kindergarten only)</text>
|
||||
</g>
|
||||
<!-- failed->audit -->
|
||||
<g id="edge12" class="edge">
|
||||
<title>failed->audit</title>
|
||||
<path fill="none" stroke="#888888" stroke-dasharray="5,2" d="M735.37,-49.27C787.73,-52.71 859.21,-57.4 912.37,-60.89"/>
|
||||
<polygon fill="#888888" stroke="#888888" points="912.2,-64.38 922.41,-61.54 912.66,-57.4 912.2,-64.38"/>
|
||||
</g>
|
||||
<!-- quarantined->live -->
|
||||
<g id="edge6" class="edge">
|
||||
<title>quarantined->live</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="1,5" d="M616.02,-114.95C601.6,-108.99 585.51,-103.24 570.16,-99.69 526.4,-89.57 476.1,-86.01 436.22,-85.01"/>
|
||||
<polygon fill="black" stroke="black" points="436.12,-81.51 426.05,-84.8 435.97,-88.5 436.12,-81.51"/>
|
||||
<text text-anchor="middle" x="524.66" y="-102.49" font-family="Helvetica,sans-Serif" font-size="9.00">review passed</text>
|
||||
</g>
|
||||
<!-- quarantined->failed -->
|
||||
<g id="edge7" class="edge">
|
||||
<title>quarantined->failed</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="1,5" d="M664.53,-108.62C664.53,-100.84 664.53,-92.29 664.53,-84.05"/>
|
||||
<polygon fill="black" stroke="black" points="668.03,-83.86 664.53,-73.86 661.03,-83.86 668.03,-83.86"/>
|
||||
<text text-anchor="middle" x="656.53" y="-88.99" font-family="Helvetica,sans-Serif" font-size="9.00">review rejected</text>
|
||||
</g>
|
||||
<!-- quarantined->audit -->
|
||||
<g id="edge13" class="edge">
|
||||
<title>quarantined->audit</title>
|
||||
<path fill="none" stroke="#888888" stroke-dasharray="5,2" d="M720.94,-117.86C733.33,-113.83 746.48,-109.86 758.9,-106.69 809.7,-93.73 867.91,-83.29 912.63,-76.19"/>
|
||||
<polygon fill="#888888" stroke="#888888" points="913.2,-79.65 922.53,-74.64 912.11,-72.73 913.2,-79.65"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 12 KiB |
87
docs/diagrams/three-layer-stack.dot
Normal file
87
docs/diagrams/three-layer-stack.dot
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
// Three-layer stack: how surface, core, and providence-cache compose
|
||||
// over one SQLite file per shard.
|
||||
//
|
||||
// Surface = ingested docs (Merkle-rooted, FTS5-indexed).
|
||||
// Core = distillates, bound back to surfaces via per-chunk inclusion
|
||||
// proofs in derivations.proof_blob. Recursive (depth-N → N+1).
|
||||
// Providence cache = Q&A records keyed on the v9.8 8-dim invariant,
|
||||
// each carrying audit_mode (STRICT / HYBRID / UNGROUNDED) +
|
||||
// a Merkle proof binding the answer to its source chunks.
|
||||
//
|
||||
// Render: dot -Tsvg three-layer-stack.dot -o three-layer-stack.svg
|
||||
|
||||
digraph three_layer_stack {
|
||||
rankdir=BT
|
||||
node [shape=box, style="rounded,filled", fontname="Helvetica", fontsize=10]
|
||||
edge [fontname="Helvetica", fontsize=9]
|
||||
bgcolor="white"
|
||||
|
||||
subgraph cluster_surface {
|
||||
label="SURFACE — ingested documents"
|
||||
labeljust="l"
|
||||
fontname="Helvetica-Bold"
|
||||
style="rounded,filled"
|
||||
fillcolor="#fff7e6"
|
||||
margin=12
|
||||
|
||||
s_wiki [label="Wikipedia\nXML / SQL dump", fillcolor="#fff0d0"]
|
||||
s_html [label="HTML page\n(crawler)", fillcolor="#fff0d0"]
|
||||
s_grok [label="Grok export\nconversation", fillcolor="#fff0d0"]
|
||||
s_vcs [label="git / hg\nrepo HEAD walk", fillcolor="#fff0d0"]
|
||||
s_tex [label="textbook_tex\nProject Gutenberg LaTeX", fillcolor="#fff0d0"]
|
||||
s_root [label="document_root (32 bytes)\nMerkle root over canonical chunks\nidentity = content, not URI", fillcolor="#ffe2a8", shape=note]
|
||||
}
|
||||
|
||||
subgraph cluster_core {
|
||||
label="CORE — distillates"
|
||||
labeljust="l"
|
||||
fontname="Helvetica-Bold"
|
||||
style="rounded,filled"
|
||||
fillcolor="#e7ffe7"
|
||||
margin=12
|
||||
|
||||
c_first [label="first_sentence\n(lead extraction)", fillcolor="#d0f0d0"]
|
||||
c_tfidf [label="tfidf\n(keyword core)", fillcolor="#d0f0d0"]
|
||||
c_recur [label="depth-N → depth-N+1\nrecursive distillation", fillcolor="#d0f0d0"]
|
||||
c_proof [label="derivations.proof_blob\nper contributing chunk:\n • leaf_hash\n • sibling path\n • verify_proof() ≡ True\nbinding survives compression", fillcolor="#b8e6b8", shape=note]
|
||||
}
|
||||
|
||||
subgraph cluster_prov {
|
||||
label="PROVIDENCE CACHE — Q&A records"
|
||||
labeljust="l"
|
||||
fontname="Helvetica-Bold"
|
||||
style="rounded,filled"
|
||||
fillcolor="#e6f0ff"
|
||||
margin=12
|
||||
|
||||
p_key [label="cache_key (8-dim)\nsource_root | question_hash |\nmodel_profile | conversation |\ngovernance_policy | schema_v |\ncanonicalization_v | chunking_v", fillcolor="#cfdfff", shape=note]
|
||||
p_audit [label="audit_mode ∈\n{STRICT, HYBRID, UNGROUNDED}\nset by verifier, never asserted", fillcolor="#cfdfff"]
|
||||
p_state [label="falsification_state ∈\n{live, failed, stale, quarantined}\ncache reads filter on state='live'", fillcolor="#cfdfff"]
|
||||
p_proof [label="merkle_proof\nbinds answer ↔ source chunks\nverifies offline, across peers", fillcolor="#a8c8ff", shape=note]
|
||||
}
|
||||
|
||||
// Surface composes into one document_root
|
||||
s_wiki -> s_root
|
||||
s_html -> s_root
|
||||
s_grok -> s_root
|
||||
s_vcs -> s_root
|
||||
s_tex -> s_root
|
||||
|
||||
// Core binds back to surface via per-chunk proofs
|
||||
s_root -> c_proof [label="ingested chunks\nbind cores back", color="#2d6a2d"]
|
||||
c_first -> c_proof
|
||||
c_tfidf -> c_proof
|
||||
c_recur -> c_proof
|
||||
c_recur -> c_recur [label="self-recursion", color="#2d6a2d"]
|
||||
|
||||
// Providence carries source_root from surface + Merkle proof
|
||||
s_root -> p_key [label="source_root", color="#1a3a8a"]
|
||||
c_proof -> p_proof [label="proof structure\nreused", color="#1a3a8a", style="dashed"]
|
||||
|
||||
p_key -> p_audit [style=invis]
|
||||
p_audit -> p_state [style=invis]
|
||||
p_state -> p_proof [style=invis]
|
||||
|
||||
// Layer separation hint at right edge
|
||||
{rank=same; s_root; c_proof; p_proof}
|
||||
}
|
||||
BIN
docs/diagrams/three-layer-stack.png
Normal file
BIN
docs/diagrams/three-layer-stack.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 137 KiB |
226
docs/diagrams/three-layer-stack.svg
Normal file
226
docs/diagrams/three-layer-stack.svg
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Generated by graphviz version 2.43.0 (0)
|
||||
-->
|
||||
<!-- Title: three_layer_stack Pages: 1 -->
|
||||
<svg width="1377pt" height="415pt"
|
||||
viewBox="0.00 0.00 1376.54 414.50" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 410.5)">
|
||||
<title>three_layer_stack</title>
|
||||
<polygon fill="white" stroke="transparent" points="-4,4 -4,-410.5 1372.54,-410.5 1372.54,4 -4,4"/>
|
||||
<g id="clust1" class="cluster">
|
||||
<title>cluster_surface</title>
|
||||
<path fill="#fff7e6" stroke="black" d="M34.54,-220C34.54,-220 586.54,-220 586.54,-220 592.54,-220 598.54,-226 598.54,-232 598.54,-232 598.54,-291 598.54,-291 598.54,-297 592.54,-303 586.54,-303 586.54,-303 34.54,-303 34.54,-303 28.54,-303 22.54,-297 22.54,-291 22.54,-291 22.54,-232 22.54,-232 22.54,-226 28.54,-220 34.54,-220"/>
|
||||
<text text-anchor="middle" x="157.04" y="-227.8" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="14.00">SURFACE — ingested documents</text>
|
||||
</g>
|
||||
<g id="clust2" class="cluster">
|
||||
<title>cluster_core</title>
|
||||
<path fill="#e7ffe7" stroke="black" d="M618.54,-220C618.54,-220 1043.54,-220 1043.54,-220 1049.54,-220 1055.54,-226 1055.54,-232 1055.54,-232 1055.54,-291 1055.54,-291 1055.54,-297 1049.54,-303 1043.54,-303 1043.54,-303 618.54,-303 618.54,-303 612.54,-303 606.54,-297 606.54,-291 606.54,-291 606.54,-232 606.54,-232 606.54,-226 612.54,-220 618.54,-220"/>
|
||||
<text text-anchor="middle" x="686.54" y="-227.8" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="14.00">CORE — distillates</text>
|
||||
</g>
|
||||
<g id="clust3" class="cluster">
|
||||
<title>cluster_prov</title>
|
||||
<path fill="#e6f0ff" stroke="black" d="M1075.54,-8C1075.54,-8 1348.54,-8 1348.54,-8 1354.54,-8 1360.54,-14 1360.54,-20 1360.54,-20 1360.54,-293.5 1360.54,-293.5 1360.54,-299.5 1354.54,-305.5 1348.54,-305.5 1348.54,-305.5 1075.54,-305.5 1075.54,-305.5 1069.54,-305.5 1063.54,-299.5 1063.54,-293.5 1063.54,-293.5 1063.54,-20 1063.54,-20 1063.54,-14 1069.54,-8 1075.54,-8"/>
|
||||
<text text-anchor="middle" x="1212.04" y="-15.8" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="14.00">PROVIDENCE CACHE — Q&A records</text>
|
||||
</g>
|
||||
<!-- s_wiki -->
|
||||
<g id="node1" class="node">
|
||||
<title>s_wiki</title>
|
||||
<path fill="#fff0d0" stroke="black" d="M272.54,-291C272.54,-291 200.54,-291 200.54,-291 194.54,-291 188.54,-285 188.54,-279 188.54,-279 188.54,-267 188.54,-267 188.54,-261 194.54,-255 200.54,-255 200.54,-255 272.54,-255 272.54,-255 278.54,-255 284.54,-261 284.54,-267 284.54,-267 284.54,-279 284.54,-279 284.54,-285 278.54,-291 272.54,-291"/>
|
||||
<text text-anchor="middle" x="236.54" y="-276" font-family="Helvetica,sans-Serif" font-size="10.00">Wikipedia</text>
|
||||
<text text-anchor="middle" x="236.54" y="-265" font-family="Helvetica,sans-Serif" font-size="10.00">XML / SQL dump</text>
|
||||
</g>
|
||||
<!-- s_root -->
|
||||
<g id="node6" class="node">
|
||||
<title>s_root</title>
|
||||
<polygon fill="#ffe2a8" stroke="black" points="425.04,-390 246.04,-390 246.04,-349 431.04,-349 431.04,-384 425.04,-390"/>
|
||||
<polyline fill="none" stroke="black" points="425.04,-390 425.04,-384 "/>
|
||||
<polyline fill="none" stroke="black" points="431.04,-384 425.04,-384 "/>
|
||||
<text text-anchor="middle" x="338.54" y="-378" font-family="Helvetica,sans-Serif" font-size="10.00">document_root (32 bytes)</text>
|
||||
<text text-anchor="middle" x="338.54" y="-367" font-family="Helvetica,sans-Serif" font-size="10.00">Merkle root over canonical chunks</text>
|
||||
<text text-anchor="middle" x="338.54" y="-356" font-family="Helvetica,sans-Serif" font-size="10.00">identity = content, not URI</text>
|
||||
</g>
|
||||
<!-- s_wiki->s_root -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>s_wiki->s_root</title>
|
||||
<path fill="none" stroke="black" d="M255.25,-291.33C270.51,-305.47 292.32,-325.68 309.8,-341.87"/>
|
||||
<polygon fill="black" stroke="black" points="307.77,-344.77 317.48,-348.99 312.53,-339.63 307.77,-344.77"/>
|
||||
</g>
|
||||
<!-- s_html -->
|
||||
<g id="node2" class="node">
|
||||
<title>s_html</title>
|
||||
<path fill="#fff0d0" stroke="black" d="M362.04,-291C362.04,-291 315.04,-291 315.04,-291 309.04,-291 303.04,-285 303.04,-279 303.04,-279 303.04,-267 303.04,-267 303.04,-261 309.04,-255 315.04,-255 315.04,-255 362.04,-255 362.04,-255 368.04,-255 374.04,-261 374.04,-267 374.04,-267 374.04,-279 374.04,-279 374.04,-285 368.04,-291 362.04,-291"/>
|
||||
<text text-anchor="middle" x="338.54" y="-276" font-family="Helvetica,sans-Serif" font-size="10.00">HTML page</text>
|
||||
<text text-anchor="middle" x="338.54" y="-265" font-family="Helvetica,sans-Serif" font-size="10.00">(crawler)</text>
|
||||
</g>
|
||||
<!-- s_html->s_root -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>s_html->s_root</title>
|
||||
<path fill="none" stroke="black" d="M338.54,-291.33C338.54,-304.58 338.54,-323.16 338.54,-338.77"/>
|
||||
<polygon fill="black" stroke="black" points="335.04,-338.99 338.54,-348.99 342.04,-338.99 335.04,-338.99"/>
|
||||
</g>
|
||||
<!-- s_grok -->
|
||||
<g id="node3" class="node">
|
||||
<title>s_grok</title>
|
||||
<path fill="#fff0d0" stroke="black" d="M460.54,-291C460.54,-291 404.54,-291 404.54,-291 398.54,-291 392.54,-285 392.54,-279 392.54,-279 392.54,-267 392.54,-267 392.54,-261 398.54,-255 404.54,-255 404.54,-255 460.54,-255 460.54,-255 466.54,-255 472.54,-261 472.54,-267 472.54,-267 472.54,-279 472.54,-279 472.54,-285 466.54,-291 460.54,-291"/>
|
||||
<text text-anchor="middle" x="432.54" y="-276" font-family="Helvetica,sans-Serif" font-size="10.00">Grok export</text>
|
||||
<text text-anchor="middle" x="432.54" y="-265" font-family="Helvetica,sans-Serif" font-size="10.00">conversation</text>
|
||||
</g>
|
||||
<!-- s_grok->s_root -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>s_grok->s_root</title>
|
||||
<path fill="none" stroke="black" d="M415.3,-291.33C401.23,-305.47 381.13,-325.68 365.02,-341.87"/>
|
||||
<polygon fill="black" stroke="black" points="362.51,-339.44 357.94,-348.99 367.47,-344.37 362.51,-339.44"/>
|
||||
</g>
|
||||
<!-- s_vcs -->
|
||||
<g id="node4" class="node">
|
||||
<title>s_vcs</title>
|
||||
<path fill="#fff0d0" stroke="black" d="M574.04,-291C574.04,-291 503.04,-291 503.04,-291 497.04,-291 491.04,-285 491.04,-279 491.04,-279 491.04,-267 491.04,-267 491.04,-261 497.04,-255 503.04,-255 503.04,-255 574.04,-255 574.04,-255 580.04,-255 586.04,-261 586.04,-267 586.04,-267 586.04,-279 586.04,-279 586.04,-285 580.04,-291 574.04,-291"/>
|
||||
<text text-anchor="middle" x="538.54" y="-276" font-family="Helvetica,sans-Serif" font-size="10.00">git / hg</text>
|
||||
<text text-anchor="middle" x="538.54" y="-265" font-family="Helvetica,sans-Serif" font-size="10.00">repo HEAD walk</text>
|
||||
</g>
|
||||
<!-- s_vcs->s_root -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>s_vcs->s_root</title>
|
||||
<path fill="none" stroke="black" d="M508.93,-291.02C500.19,-295.87 490.56,-301.03 481.54,-305.5 453.5,-319.39 421.7,-333.55 395.22,-344.92"/>
|
||||
<polygon fill="black" stroke="black" points="393.54,-341.83 385.72,-348.98 396.29,-348.27 393.54,-341.83"/>
|
||||
</g>
|
||||
<!-- s_tex -->
|
||||
<g id="node5" class="node">
|
||||
<title>s_tex</title>
|
||||
<path fill="#fff0d0" stroke="black" d="M158.54,-291C158.54,-291 46.54,-291 46.54,-291 40.54,-291 34.54,-285 34.54,-279 34.54,-279 34.54,-267 34.54,-267 34.54,-261 40.54,-255 46.54,-255 46.54,-255 158.54,-255 158.54,-255 164.54,-255 170.54,-261 170.54,-267 170.54,-267 170.54,-279 170.54,-279 170.54,-285 164.54,-291 158.54,-291"/>
|
||||
<text text-anchor="middle" x="102.54" y="-276" font-family="Helvetica,sans-Serif" font-size="10.00">textbook_tex</text>
|
||||
<text text-anchor="middle" x="102.54" y="-265" font-family="Helvetica,sans-Serif" font-size="10.00">Project Gutenberg LaTeX</text>
|
||||
</g>
|
||||
<!-- s_tex->s_root -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>s_tex->s_root</title>
|
||||
<path fill="none" stroke="black" d="M144.06,-291.09C155.55,-295.78 168.02,-300.86 179.54,-305.5 212.47,-318.76 249.32,-333.38 279.25,-345.19"/>
|
||||
<polygon fill="black" stroke="black" points="278.12,-348.51 288.71,-348.92 280.69,-341.99 278.12,-348.51"/>
|
||||
</g>
|
||||
<!-- c_proof -->
|
||||
<g id="node10" class="node">
|
||||
<title>c_proof</title>
|
||||
<polygon fill="#b8e6b8" stroke="black" points="861.54,-406.5 705.54,-406.5 705.54,-332.5 867.54,-332.5 867.54,-400.5 861.54,-406.5"/>
|
||||
<polyline fill="none" stroke="black" points="861.54,-406.5 861.54,-400.5 "/>
|
||||
<polyline fill="none" stroke="black" points="867.54,-400.5 861.54,-400.5 "/>
|
||||
<text text-anchor="middle" x="786.54" y="-394.5" font-family="Helvetica,sans-Serif" font-size="10.00">derivations.proof_blob</text>
|
||||
<text text-anchor="middle" x="786.54" y="-383.5" font-family="Helvetica,sans-Serif" font-size="10.00">per contributing chunk:</text>
|
||||
<text text-anchor="middle" x="786.54" y="-372.5" font-family="Helvetica,sans-Serif" font-size="10.00">  • leaf_hash</text>
|
||||
<text text-anchor="middle" x="786.54" y="-361.5" font-family="Helvetica,sans-Serif" font-size="10.00">  • sibling path</text>
|
||||
<text text-anchor="middle" x="786.54" y="-350.5" font-family="Helvetica,sans-Serif" font-size="10.00">  • verify_proof() ≡ True</text>
|
||||
<text text-anchor="middle" x="786.54" y="-339.5" font-family="Helvetica,sans-Serif" font-size="10.00">binding survives compression</text>
|
||||
</g>
|
||||
<!-- s_root->c_proof -->
|
||||
<g id="edge6" class="edge">
|
||||
<title>s_root->c_proof</title>
|
||||
<path fill="none" stroke="#2d6a2d" d="M431.09,-369.5C508.46,-369.5 618.19,-369.5 695.21,-369.5"/>
|
||||
<polygon fill="#2d6a2d" stroke="#2d6a2d" points="695.38,-373 705.38,-369.5 695.38,-366 695.38,-373"/>
|
||||
<text text-anchor="middle" x="568.29" y="-359.3" font-family="Helvetica,sans-Serif" font-size="9.00">ingested chunks</text>
|
||||
<text text-anchor="middle" x="568.29" y="-349.3" font-family="Helvetica,sans-Serif" font-size="9.00">bind cores back</text>
|
||||
</g>
|
||||
<!-- p_key -->
|
||||
<g id="node11" class="node">
|
||||
<title>p_key</title>
|
||||
<polygon fill="#cfdfff" stroke="black" points="1245.04,-106 1078.04,-106 1078.04,-43 1251.04,-43 1251.04,-100 1245.04,-106"/>
|
||||
<polyline fill="none" stroke="black" points="1245.04,-106 1245.04,-100 "/>
|
||||
<polyline fill="none" stroke="black" points="1251.04,-100 1245.04,-100 "/>
|
||||
<text text-anchor="middle" x="1164.54" y="-94" font-family="Helvetica,sans-Serif" font-size="10.00">cache_key (8-dim)</text>
|
||||
<text text-anchor="middle" x="1164.54" y="-83" font-family="Helvetica,sans-Serif" font-size="10.00">source_root | question_hash |</text>
|
||||
<text text-anchor="middle" x="1164.54" y="-72" font-family="Helvetica,sans-Serif" font-size="10.00">model_profile | conversation |</text>
|
||||
<text text-anchor="middle" x="1164.54" y="-61" font-family="Helvetica,sans-Serif" font-size="10.00">governance_policy | schema_v |</text>
|
||||
<text text-anchor="middle" x="1164.54" y="-50" font-family="Helvetica,sans-Serif" font-size="10.00">canonicalization_v | chunking_v</text>
|
||||
</g>
|
||||
<!-- s_root->p_key -->
|
||||
<g id="edge11" class="edge">
|
||||
<title>s_root->p_key</title>
|
||||
<path fill="none" stroke="#1a3a8a" d="M245.85,-363.03C161.82,-355.9 46.9,-340 18.54,-305.5 -5.6,-276.15 -6.6,-248.5 18.54,-220 87.62,-141.66 803.29,-95.13 1067.36,-80.51"/>
|
||||
<polygon fill="#1a3a8a" stroke="#1a3a8a" points="1067.9,-83.99 1077.7,-79.95 1067.52,-77 1067.9,-83.99"/>
|
||||
<text text-anchor="middle" x="71.04" y="-204.8" font-family="Helvetica,sans-Serif" font-size="9.00">source_root</text>
|
||||
</g>
|
||||
<!-- c_first -->
|
||||
<g id="node7" class="node">
|
||||
<title>c_first</title>
|
||||
<path fill="#d0f0d0" stroke="black" d="M1031.54,-291C1031.54,-291 957.54,-291 957.54,-291 951.54,-291 945.54,-285 945.54,-279 945.54,-279 945.54,-267 945.54,-267 945.54,-261 951.54,-255 957.54,-255 957.54,-255 1031.54,-255 1031.54,-255 1037.54,-255 1043.54,-261 1043.54,-267 1043.54,-267 1043.54,-279 1043.54,-279 1043.54,-285 1037.54,-291 1031.54,-291"/>
|
||||
<text text-anchor="middle" x="994.54" y="-276" font-family="Helvetica,sans-Serif" font-size="10.00">first_sentence</text>
|
||||
<text text-anchor="middle" x="994.54" y="-265" font-family="Helvetica,sans-Serif" font-size="10.00">(lead extraction)</text>
|
||||
</g>
|
||||
<!-- c_first->c_proof -->
|
||||
<g id="edge7" class="edge">
|
||||
<title>c_first->c_proof</title>
|
||||
<path fill="none" stroke="black" d="M964.43,-291.09C955.54,-295.93 945.73,-301.09 936.54,-305.5 917.52,-314.63 896.84,-323.79 877.08,-332.19"/>
|
||||
<polygon fill="black" stroke="black" points="875.62,-329.01 867.77,-336.12 878.34,-335.46 875.62,-329.01"/>
|
||||
</g>
|
||||
<!-- c_tfidf -->
|
||||
<g id="node8" class="node">
|
||||
<title>c_tfidf</title>
|
||||
<path fill="#d0f0d0" stroke="black" d="M695.04,-291C695.04,-291 630.04,-291 630.04,-291 624.04,-291 618.04,-285 618.04,-279 618.04,-279 618.04,-267 618.04,-267 618.04,-261 624.04,-255 630.04,-255 630.04,-255 695.04,-255 695.04,-255 701.04,-255 707.04,-261 707.04,-267 707.04,-267 707.04,-279 707.04,-279 707.04,-285 701.04,-291 695.04,-291"/>
|
||||
<text text-anchor="middle" x="662.54" y="-276" font-family="Helvetica,sans-Serif" font-size="10.00">tfidf</text>
|
||||
<text text-anchor="middle" x="662.54" y="-265" font-family="Helvetica,sans-Serif" font-size="10.00">(keyword core)</text>
|
||||
</g>
|
||||
<!-- c_tfidf->c_proof -->
|
||||
<g id="edge8" class="edge">
|
||||
<title>c_tfidf->c_proof</title>
|
||||
<path fill="none" stroke="black" d="M684.99,-291.11C697.83,-300.9 714.55,-313.64 730.71,-325.95"/>
|
||||
<polygon fill="black" stroke="black" points="729,-329.05 739.08,-332.33 733.25,-323.49 729,-329.05"/>
|
||||
</g>
|
||||
<!-- c_recur -->
|
||||
<g id="node9" class="node">
|
||||
<title>c_recur</title>
|
||||
<path fill="#d0f0d0" stroke="black" d="M836.04,-291C836.04,-291 737.04,-291 737.04,-291 731.04,-291 725.04,-285 725.04,-279 725.04,-279 725.04,-267 725.04,-267 725.04,-261 731.04,-255 737.04,-255 737.04,-255 836.04,-255 836.04,-255 842.04,-255 848.04,-261 848.04,-267 848.04,-267 848.04,-279 848.04,-279 848.04,-285 842.04,-291 836.04,-291"/>
|
||||
<text text-anchor="middle" x="786.54" y="-276" font-family="Helvetica,sans-Serif" font-size="10.00">depth-N → depth-N+1</text>
|
||||
<text text-anchor="middle" x="786.54" y="-265" font-family="Helvetica,sans-Serif" font-size="10.00">recursive distillation</text>
|
||||
</g>
|
||||
<!-- c_recur->c_recur -->
|
||||
<g id="edge10" class="edge">
|
||||
<title>c_recur->c_recur</title>
|
||||
<path fill="none" stroke="#2d6a2d" d="M848.2,-266C858.74,-266.96 866.04,-269.29 866.04,-273 866.04,-275.38 863.04,-277.19 858.12,-278.44"/>
|
||||
<polygon fill="#2d6a2d" stroke="#2d6a2d" points="857.54,-274.99 848.2,-280 858.63,-281.9 857.54,-274.99"/>
|
||||
<text text-anchor="middle" x="896.54" y="-270.8" font-family="Helvetica,sans-Serif" font-size="9.00">self-recursion</text>
|
||||
</g>
|
||||
<!-- c_recur->c_proof -->
|
||||
<g id="edge9" class="edge">
|
||||
<title>c_recur->c_proof</title>
|
||||
<path fill="none" stroke="black" d="M786.54,-291.33C786.54,-300.14 786.54,-311.31 786.54,-322.4"/>
|
||||
<polygon fill="black" stroke="black" points="783.04,-322.49 786.54,-332.49 790.04,-322.49 783.04,-322.49"/>
|
||||
</g>
|
||||
<!-- p_proof -->
|
||||
<g id="node14" class="node">
|
||||
<title>p_proof</title>
|
||||
<polygon fill="#a8c8ff" stroke="black" points="1176.04,-390 1017.04,-390 1017.04,-349 1182.04,-349 1182.04,-384 1176.04,-390"/>
|
||||
<polyline fill="none" stroke="black" points="1176.04,-390 1176.04,-384 "/>
|
||||
<polyline fill="none" stroke="black" points="1182.04,-384 1176.04,-384 "/>
|
||||
<text text-anchor="middle" x="1099.54" y="-378" font-family="Helvetica,sans-Serif" font-size="10.00">merkle_proof</text>
|
||||
<text text-anchor="middle" x="1099.54" y="-367" font-family="Helvetica,sans-Serif" font-size="10.00">binds answer ↔ source chunks</text>
|
||||
<text text-anchor="middle" x="1099.54" y="-356" font-family="Helvetica,sans-Serif" font-size="10.00">verifies offline, across peers</text>
|
||||
</g>
|
||||
<!-- c_proof->p_proof -->
|
||||
<g id="edge12" class="edge">
|
||||
<title>c_proof->p_proof</title>
|
||||
<path fill="none" stroke="#1a3a8a" stroke-dasharray="5,2" d="M867.55,-369.5C910.15,-369.5 962.56,-369.5 1006.78,-369.5"/>
|
||||
<polygon fill="#1a3a8a" stroke="#1a3a8a" points="1006.96,-373 1016.96,-369.5 1006.96,-366 1006.96,-373"/>
|
||||
<text text-anchor="middle" x="942.29" y="-359.3" font-family="Helvetica,sans-Serif" font-size="9.00">proof structure</text>
|
||||
<text text-anchor="middle" x="942.29" y="-349.3" font-family="Helvetica,sans-Serif" font-size="9.00">reused</text>
|
||||
</g>
|
||||
<!-- p_audit -->
|
||||
<g id="node12" class="node">
|
||||
<title>p_audit</title>
|
||||
<path fill="#cfdfff" stroke="black" d="M1248.04,-184C1248.04,-184 1087.04,-184 1087.04,-184 1081.04,-184 1075.04,-178 1075.04,-172 1075.04,-172 1075.04,-155 1075.04,-155 1075.04,-149 1081.04,-143 1087.04,-143 1087.04,-143 1248.04,-143 1248.04,-143 1254.04,-143 1260.04,-149 1260.04,-155 1260.04,-155 1260.04,-172 1260.04,-172 1260.04,-178 1254.04,-184 1248.04,-184"/>
|
||||
<text text-anchor="middle" x="1167.54" y="-172" font-family="Helvetica,sans-Serif" font-size="10.00">audit_mode ∈</text>
|
||||
<text text-anchor="middle" x="1167.54" y="-161" font-family="Helvetica,sans-Serif" font-size="10.00">{STRICT, HYBRID, UNGROUNDED}</text>
|
||||
<text text-anchor="middle" x="1167.54" y="-150" font-family="Helvetica,sans-Serif" font-size="10.00">set by verifier, never asserted</text>
|
||||
</g>
|
||||
<!-- p_key->p_audit -->
|
||||
<!-- p_state -->
|
||||
<g id="node13" class="node">
|
||||
<title>p_state</title>
|
||||
<path fill="#cfdfff" stroke="black" d="M1241.54,-293.5C1241.54,-293.5 1089.54,-293.5 1089.54,-293.5 1083.54,-293.5 1077.54,-287.5 1077.54,-281.5 1077.54,-281.5 1077.54,-264.5 1077.54,-264.5 1077.54,-258.5 1083.54,-252.5 1089.54,-252.5 1089.54,-252.5 1241.54,-252.5 1241.54,-252.5 1247.54,-252.5 1253.54,-258.5 1253.54,-264.5 1253.54,-264.5 1253.54,-281.5 1253.54,-281.5 1253.54,-287.5 1247.54,-293.5 1241.54,-293.5"/>
|
||||
<text text-anchor="middle" x="1165.54" y="-281.5" font-family="Helvetica,sans-Serif" font-size="10.00">falsification_state ∈</text>
|
||||
<text text-anchor="middle" x="1165.54" y="-270.5" font-family="Helvetica,sans-Serif" font-size="10.00">{live, failed, stale, quarantined}</text>
|
||||
<text text-anchor="middle" x="1165.54" y="-259.5" font-family="Helvetica,sans-Serif" font-size="10.00">cache reads filter on state='live'</text>
|
||||
</g>
|
||||
<!-- p_audit->p_state -->
|
||||
<!-- p_state->p_proof -->
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 18 KiB |
Loading…
Add table
Add a link
Reference in a new issue