docs: arborist-one-pager + arborist-two-pager — Dav1d/fox-signoff summaries with letterhead, license, and 2 strategic appendix diagrams

1-pager (docs/_source/arborist-one-pager.rst, 1 page) for AI-literate readers: the trichotomy, the 8-dim cache key, CTI synthetic-elision-impossible, soft-channel separation, real-traffic bench numbers (mis-cite 100% @ 0% FP, warrant 92/92, quote 0.54 STRICT-rate).

2-pager (docs/_source/arborist-two-pager.rst, 3 pages = 2 body + 1 appendix) for technical reviewers: letterhead, Permacomputer Preamble license box, six numbered sections, plus appendix figures (pager-arch-stack 3-layer architecture, pager-verifier-flow question→pointer→verifier→trichotomy).

Both pages live under docs/_source/ so the same RST renders into the Sphinx readthedocs site (toctree caption "Summary pages" added to docs/_source/index.rst) AND into standalone PDFs via rst2pdf (docs/pager.style, lazy install into .venv).

Makefile targets: docs-one-pager, docs-two-pager, docs-pagers, docs-pagers-clean. Diagrams render through the existing DOT pipeline.
This commit is contained in:
russell@unturf.com 2026-05-14 09:48:50 -04:00
parent 90d5c54c0a
commit 0aada29a8e
No known key found for this signature in database
11 changed files with 664 additions and 0 deletions

View file

@ -30,6 +30,7 @@ SEARCH_Q ?= computer
ingest-xml-attached ingest-abstract \
ingest-self ingest-self-providence ingest-git ingest-hg \
verify search stats test test-ci test-live docs docs-api docs-api-clean \
docs-one-pager docs-two-pager docs-pagers docs-pagers-clean \
chain-check chain-check-shards \
falsify burn burn-kindergarten inspect bootstrap-crawler test-crawler crawl-ingest \
recrawl-check bench-qa bench-qa-smoke bench-qa-progressive-and \
@ -1120,6 +1121,36 @@ docs-api: ## generate Sphinx API reference from docstrings (output: docs/_source
docs-api-clean: ## remove Sphinx build artifacts
rm -rf docs/_source/_build/
# 1-pager / 2-pager standalone PDFs. Source RST lives at
# docs/_source/arborist-*-pager.rst (so the same files render on the
# Sphinx site AND as standalone PDFs). Style sheet at docs/pager.style.
# rst2pdf is installed lazily into $(VENV) on first build.
RST2PDF := $(VENV)/bin/rst2pdf
DOCS_BUILD := docs/_build
PAGER_STYLE := docs/pager.style
PAGER_FIGURES := docs/diagrams/pager-arch-stack.png docs/diagrams/pager-verifier-flow.png
$(RST2PDF): $(VENV)/bin/activate
$(PIP) install rst2pdf
$(DOCS_BUILD):
mkdir -p $(DOCS_BUILD)
$(DOCS_BUILD)/arborist-one-pager.pdf: docs/_source/arborist-one-pager.rst $(PAGER_STYLE) | $(DOCS_BUILD) $(RST2PDF)
$(RST2PDF) docs/_source/arborist-one-pager.rst -s $(PAGER_STYLE) -o $@
$(DOCS_BUILD)/arborist-two-pager.pdf: docs/_source/arborist-two-pager.rst $(PAGER_STYLE) $(PAGER_FIGURES) | $(DOCS_BUILD) $(RST2PDF)
$(RST2PDF) docs/_source/arborist-two-pager.rst -s $(PAGER_STYLE) -o $@
docs-one-pager: $(DOCS_BUILD)/arborist-one-pager.pdf ## render docs/_build/arborist-one-pager.pdf
docs-two-pager: $(DOCS_BUILD)/arborist-two-pager.pdf ## render docs/_build/arborist-two-pager.pdf
docs-pagers: docs-one-pager docs-two-pager ## render both 1-pager and 2-pager PDFs
docs-pagers-clean: ## remove generated pager PDFs
rm -f $(DOCS_BUILD)/arborist-one-pager.pdf $(DOCS_BUILD)/arborist-two-pager.pdf
# Reproducible micro-benchmark over a fixed slice of cur. Lets you compare
# ETL throughput across configs and catches regressions on optimization
# work. Override BENCH_DOCS=N (default 5000).

View file

@ -0,0 +1,64 @@
arborist — a Q&A store with cryptographically verified answers
================================================================
.. class:: center
*one-page summary · 2026-05-14 · AGPL-3.0-only · permacomputer.com*
----
Most retrieval-augmented systems hand a language model some context, ask
for an answer, and ship whatever comes back. There is no
machine-checkable claim about what the answer actually quotes from its
source. **arborist inverts that.** Every answer is verified against its
source *after* generation by a deterministic, lexical check that produces
three labels — **STRICT** (every claim verifies), **HYBRID** (mixed),
**UNGROUNDED** (none). The verifier is binary. It does not negotiate.
Answers and labels are written to a content-addressed SQLite cache, every
state change appends a SHA-256 audit-chain row, and a single tampered
record breaks the chain.
**Three Merkle-bound layers.** Surface (ingested documents — Wikipedia,
HTML, TeX, git, claim-packs), Core (distilled documents bound to their
surfaces by per-chunk inclusion proofs), Providence cache (verified Q&A
keyed on an 8-dimensional invariant that folds in the source-corpus root,
the question hash, the model identity, the governance policy, the schema
version, and three normalization-version dimensions). Bumping any one of
the eight dimensions invalidates prior records on lookup. Cores never
evict.
**Synthetic-elision-by-construction-impossible.** In claim-lattice-pointer
mode, the model never types the quote string. The runtime hands it
tokens — ``[E1]``, ``[E2]`` — and interpolates the literal source span at
render time. The model proposes pointer-tagged clauses, the runtime
composes the answer. A class of hallucinations (the frankenquote, the
recombined-token claim) becomes impossible because the model cannot type
a string it never sees.
**Soft signals never enter the proof path.** Deflection, coherence,
title-relevance, NLI vetoes, cross-encoder rerankers — all live as
advisory sidecars or as demote-only governance signals folded into the
cache key. They influence what the substrate caches; they do not
influence what it certifies. The hard channel (SHA-256 commitments,
audit chain, proof-of-inclusion) and the soft channel (embeddings,
similarity scores, lexical heuristics) evolve on independent timelines.
**What it measures on real traffic.**
- **100% mis-cite catch at 0% real-STRICT false positive** on the
808-cell pooled bench-qa run (relevance-reranker veto,
BAAI/bge-reranker-large, n=20 mis-cite fixtures; ticket #000052 §3.2).
- **92 / 92 (100%) warrant-chain coverage** on the claim-pack corpus —
18 public-domain or open-licensed textbook substrates plus curated
alias chains (ticket #000031).
- **0.54 STRICT-rate** on Hermes-3-Llama-3.1-8B quote mode (n=3 × 71
questions, real Wikipedia haystack); lattice modes carry 99%
directive-coverage on the seven-point program.
**What it runs on.** Python 3.12, SQLite (FTS5 + JSON), optional
cross-encoder rerankers for the soft channel. No GPU required for the
proof path. AGPL-3.0-only. Reference inference endpoint:
`hermes.ai.unturf.com <https://hermes.ai.unturf.com>`_. Source:
`git.unturf.com/engineering/unturf/arborist <https://git.unturf.com/engineering/unturf/arborist>`_.
Full whitepaper: `unfirehose.com/merkle-providence-reverse-rag.html
<https://unfirehose.com/merkle-providence-reverse-rag.html>`_.

View file

@ -0,0 +1,211 @@
.. This is free software for the public good of a permacomputer hosted at
.. permacomputer.com, an always-on computer by the people, for the people.
.. One which is durable, easy to repair, & distributed like tap water
.. for machine learning intelligence.
.. class:: center
**Unturf · permacomputer.com · uncloseai.com · unfirehose.com**
arborist — Merkle-Providence Reverse RAG, reference implementation
====================================================================
.. class:: center
**License: AGPL-3.0-only** · schema v9.8 · 2026-05-14
· *Russell Ballestrini <russell@unturf.com>*
----
Abstract
--------
**arborist** is a content-addressed Q&A store with cryptographically
verified answers, the reference runtime for the *Merkle Providence
Reverse RAG* whitepaper (`unfirehose.com/merkle-providence-reverse-rag.html
<https://unfirehose.com/merkle-providence-reverse-rag.html>`_,
Ballestrini · Wong · Morgan, April 2026). Every cached answer carries a Merkle
proof of source origin and a *binary, lexical, no-LLM-in-the-loop*
faithfulness label. The verifier never asks a model to grade itself.
Soft signals — embeddings, NLI vetoes, similarity rerankers — exist
as sidecars and demote-only governance signals; they never enter the
proof path. The reference inference endpoint is Hermes-3-Llama-3.1-8B
served freely at `hermes.ai.unturf.com <https://hermes.ai.unturf.com>`_;
arborist runs against any OpenAI-compatible alternative with a matching
``model_profile_hash``.
1. The system in one paragraph
-------------------------------
Three SQLite-backed layers, all Merkle-bound. **Surface** holds ingested
documents (Wikipedia dumps, HTML pages, TeX textbooks, git histories,
claim-packs), chunked, hash-rooted, and FTS5-indexed. **Core** holds
distillations bound to their surfaces by per-chunk inclusion proofs in
``derivations.proof_blob``. **Providence cache** holds verified Q&A
records keyed on an 8-dimensional invariant. Every state-changing
operation appends one row to ``audit_events`` carrying
``event_hash = sha256(prev || canonical(body))``; a single tampered row
breaks the chain. Re-ingest is idempotent (same content → same
``document_root`` → no-op); same URI with different content yields a new
doc plus a ``supersedes`` edge (lossless history).
2. What makes arborist different
---------------------------------
Eleven design rules govern the substrate. The four that matter most for
a reviewer:
**The verifier stays binary.** Each evidence unit verifies or does not.
No per-unit confidence scores, no fuzzy-match indicators, no soft
labels. Once a soft signal contaminates the chain, every prior
cryptographic claim becomes negotiable.
**The runtime owns quote text.** In ``claim_lattice_pointer`` mode the
model emits prose with bracketed pointer tags (``[E1]``, ``[E2]``); the
runtime interpolates the literal source span at render time. The model
never types the quote string. *Synthetic-elision-by-construction-impossible*
— a model cannot produce a frankenquote it cannot type.
**Soft hash never enters the proof path.** Embeddings, TF-IDF scores,
cross-encoder rerankers, NLI judgments shape ranking and retrieval and
inform demote-only governance. They never feed ``cache_key`` ,
``document_root``, or ``audit_event_hash``. The hard channel and the
soft channel evolve on independent timelines.
**Labels name properties, not vibes.** ``POINTER-LINKED``,
``ANCHOR-WARRANTED``, ``EVIDENCE-WARRANTED``, ``UNGROUNDED`` each name a
property the verifier could lexically confirm or could not. There are
no "high confidence" labels. A reviewer reads the label and immediately
knows what was checked.
3. The 8-dimensional cache key
-------------------------------
A cache hit returns a previously computed answer with a Merkle proof of
origin; a cache miss triggers fresh inference. The key folds together:
================================ ===================================================
``source_root`` Merkle root of the corpus the answer is about
``question_hash`` dedup-mode-aware hash of the question (strict | equivalence_class)
``model_profile_hash`` model identity (name + sampling profile)
``conversation_hash`` prior-turn dependency, if any
``governance_policy_hash`` every policy field that alters generation
``schema_version`` ``v9.8.0``
``canonicalization_version`` ``norm-v1``
``chunking_version`` ``tok-512-v1``
================================ ===================================================
Bumping any one dimension invalidates prior records on lookup —
governance evolves, the corpus does not get rewritten when governance
evolves. Every preflight policy decision is *bound twice*: once into
``governance_policy_hash`` (cache identity) and once into ``run_dag_root``
via the preflight stage (audit replay).
4. The layered verifier
------------------------
Four strategies are tried in order; first to find evidence classifies.
**quote** (sequential pair-matching, never regex — prevents phantom
inter-pair captures), **span** (verbatim line match), **entity**
(proximity-clustered proper nouns), **paraphrase** (token-coverage,
prose-shaped only). Trichotomy on the schema column: STRICT = every unit
verifies, HYBRID = mixed, UNGROUNDED = none. The renderer maps that
column to a four-rung claim-lattice ladder
(POINTER-LINKED → ANCHOR-WARRANTED → EVIDENCE-WARRANTED;
ENTAILMENT-VERIFIED reserved); programmatic callers see the trichotomy,
human-facing surfaces see the ladder. The ENTAILMENT-VERIFIED rung is
deliberately empty — committing NLI to the proof path would re-introduce
the soft/hard boundary leak the architecture is built to prevent.
Honesty about the ceiling is a feature.
----
5. What we measure on real traffic
-----------------------------------
The bench is the scoreboard; the live fixtures are the gates. Numbers
that survive the 5pp signal floor on real-shard, real-LLM runs:
- **Mis-cite catch (claim about X cited to source about Y).** The
``BAAI/bge-reranker-large`` veto at threshold ``θ ≤ -2.42`` catches
20/20 (100%) of mis-cite fixtures at strictly 0/808 (0%) real-STRICT
false positive on the pooled bench-qa, with a 1.4-point margin
between the worst mis-cite and the best STRICT (#000052 §3.2).
- **Deflection catch (off-topic answer to an on-topic question).** Same
reranker catches 11/20 (55%) of real-haystack deflection fixtures at
the same 0/808 FP threshold. The cost-pick alternate
(``ms-marco-MiniLM-L-6-v2``, 5× smaller) catches 13/20 (65%) at 0.4% FP.
- **Recombination catch (right tokens, wrong subject).** The NLI veto
(``facebook/bart-large-mnli``, top-k=12, θc=0.999) catches ~48% of
hand-crafted real-haystack recombination fixtures at 0/808 FP; the
ceiling is selector-bound, not entailment-bound (#000049 §7 #27).
- **Warrant-chain coverage.** 92/92 (100%) of the claim-pack corpus
resolves to a warrant chain (18 public-domain or open-licensed
textbook substrates + curated citation aliases + term aliases;
ticket #000031).
- **STRICT-rate, quote mode, real Wikipedia haystack.** 0.54 on
Hermes-3-Llama-3.1-8B (n=3 × 71 questions, sample-shuffled @ c=4;
see ``docs/qa-modes-bench.md``).
Sample sizes are stated. Synthetic shortcuts are not. The five-point
sweep-wide/sweep-deep discipline ("real-traffic-sized samples or it
didn't happen") lives in ``docs/bench-maxing.md``.
6. Closed substrate work
-------------------------
Recent substrate work that is *landed and pinned*: ticket #000005
(four-rung ladder display layer), #000008 (broad-quantifier preflight
guard with six-level disable hierarchy), #000010 (metacognition
preflight — false-premise, contradiction, stale-risk, out-of-corpus),
#000015 (π* canonical projections — arithmetic, logic-kernel,
algebra-symbolic), #000027 (canonical-projection persistence in
providence cache), #000031 (claim-pack warrant resolver, 100%
coverage), #000049 §3 (NLI veto, partial closure), #000052 §3.1
(coherence sidecar — circular, vacuous, phrase-component-reuse) and
§3.2 (relevance reranker, viable runtime soft-veto). The synthesis
brief for the independent review thread is
``docs/relevance-and-veto-synthesis-for-dav1d.md``.
----
License — Permacomputer Preamble
---------------------------------
::
AGPL-3.0-only · NO WARRANTY
Free software for the public good of a permacomputer at
permacomputer.com — an always-on computer by the people, for
the people. Durable, easy to repair, distributed like tap water
for machine learning intelligence.
Four values: TRUTH · FREEDOM · HARMONY · LOVE.
Copyright (C) 2025-2026 TimeHexOn & foxhop & russell@unturf.
Full text: `LICENSE` at the repository root.
----
Appendix A — Three-layer architecture
--------------------------------------
.. figure:: diagrams/pager-arch-stack.png
:width: 5.5in
:align: center
Surface, Core, Providence cache — each layer hash-binds to the next;
every state change appends a row to the audit chain.
Appendix B — Verifier flow
---------------------------
.. figure:: diagrams/pager-verifier-flow.png
:width: 6.5in
:align: center
Question → retrieval → pointer-tagged context → LLM → binary
verifier → trichotomy label → audit chain & providence cache. The
LLM never types the quote string.

View file

@ -5,6 +5,13 @@ Generated from docstrings. Replaces the static modules.md.
Contents:
.. toctree::
:maxdepth: 1
:caption: Summary pages
arborist-one-pager
arborist-two-pager
.. toctree::
:maxdepth: 2
:caption: Getting started

View file

@ -0,0 +1,23 @@
// Compact 3-layer architecture for the 2-pager appendix.
// Render: dot -Tsvg pager-arch-stack.dot -o pager-arch-stack.svg
digraph arch_stack {
rankdir=BT
ranksep=0.25
nodesep=0.20
node [shape=box, style="rounded,filled", fontname="Helvetica", fontsize=11]
edge [fontname="Helvetica", fontsize=9]
bgcolor="white"
surface [label="SURFACE — ingested documents\nWikipedia · HTML · TeX · git · claim-packs\nchunked → Merkle-rooted → FTS5-indexed", fillcolor="#e9f3ff"]
core [label="CORE — distilled documents\nMerkle-bound to surfaces by per-chunk\ninclusion proofs (derivations.proof_blob)", fillcolor="#dff5e7"]
cache [label="PROVIDENCE CACHE — verified Q&A\n8-dim cache_key · audit_mode label ∈\n{STRICT, HYBRID, UNGROUNDED}", fillcolor="#fff3d6"]
audit [label="AUDIT CHAIN — every state change\nappends sha256(prev || canonical(body))\nto audit_events (single SQLite file)", fillcolor="#fde7e9", shape=note]
surface -> core [label="distill", fontsize=9]
core -> cache [label="verify → cache", fontsize=9]
cache -> audit [style=dashed, color="#888888", label="every write", fontsize=9]
core -> audit [style=dashed, color="#888888"]
surface -> audit [style=dashed, color="#888888"]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

View file

@ -0,0 +1,80 @@
<?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: arch_stack Pages: 1 -->
<svg width="379pt" height="268pt"
viewBox="0.00 0.00 379.00 268.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 264)">
<title>arch_stack</title>
<polygon fill="white" stroke="transparent" points="-4,4 -4,-264 375,-264 375,4 -4,4"/>
<!-- surface -->
<g id="node1" class="node">
<title>surface</title>
<path fill="#e9f3ff" stroke="black" d="M319,-44C319,-44 98,-44 98,-44 92,-44 86,-38 86,-32 86,-32 86,-12 86,-12 86,-6 92,0 98,0 98,0 319,0 319,0 325,0 331,-6 331,-12 331,-12 331,-32 331,-32 331,-38 325,-44 319,-44"/>
<text text-anchor="middle" x="208.5" y="-31.2" font-family="Helvetica,sans-Serif" font-size="11.00">SURFACE — ingested documents</text>
<text text-anchor="middle" x="208.5" y="-19.2" font-family="Helvetica,sans-Serif" font-size="11.00">Wikipedia · HTML · TeX · git · claim&#45;packs</text>
<text text-anchor="middle" x="208.5" y="-7.2" font-family="Helvetica,sans-Serif" font-size="11.00">chunked → Merkle&#45;rooted → FTS5&#45;indexed</text>
</g>
<!-- core -->
<g id="node2" class="node">
<title>core</title>
<path fill="#dff5e7" stroke="black" d="M245.5,-116C245.5,-116 31.5,-116 31.5,-116 25.5,-116 19.5,-110 19.5,-104 19.5,-104 19.5,-84 19.5,-84 19.5,-78 25.5,-72 31.5,-72 31.5,-72 245.5,-72 245.5,-72 251.5,-72 257.5,-78 257.5,-84 257.5,-84 257.5,-104 257.5,-104 257.5,-110 251.5,-116 245.5,-116"/>
<text text-anchor="middle" x="138.5" y="-103.2" font-family="Helvetica,sans-Serif" font-size="11.00">CORE — distilled documents</text>
<text text-anchor="middle" x="138.5" y="-91.2" font-family="Helvetica,sans-Serif" font-size="11.00">Merkle&#45;bound to surfaces by per&#45;chunk</text>
<text text-anchor="middle" x="138.5" y="-79.2" font-family="Helvetica,sans-Serif" font-size="11.00">inclusion proofs (derivations.proof_blob)</text>
</g>
<!-- surface&#45;&gt;core -->
<g id="edge1" class="edge">
<title>surface&#45;&gt;core</title>
<path fill="none" stroke="black" d="M187.5,-44C181.11,-50.39 173.98,-57.52 167.17,-64.33"/>
<polygon fill="black" stroke="black" points="164.57,-61.98 159.97,-71.53 169.52,-66.93 164.57,-61.98"/>
<text text-anchor="middle" x="190.5" y="-55.8" font-family="Helvetica,sans-Serif" font-size="9.00">distill</text>
</g>
<!-- audit -->
<g id="node4" class="node">
<title>audit</title>
<polygon fill="#fde7e9" stroke="black" points="365,-260 128,-260 128,-216 371,-216 371,-254 365,-260"/>
<polyline fill="none" stroke="black" points="365,-260 365,-254 "/>
<polyline fill="none" stroke="black" points="371,-254 365,-254 "/>
<text text-anchor="middle" x="249.5" y="-247.2" font-family="Helvetica,sans-Serif" font-size="11.00">AUDIT CHAIN — every state change</text>
<text text-anchor="middle" x="249.5" y="-235.2" font-family="Helvetica,sans-Serif" font-size="11.00">appends sha256(prev || canonical(body))</text>
<text text-anchor="middle" x="249.5" y="-223.2" font-family="Helvetica,sans-Serif" font-size="11.00">to audit_events (single SQLite file)</text>
</g>
<!-- surface&#45;&gt;audit -->
<g id="edge5" class="edge">
<title>surface&#45;&gt;audit</title>
<path fill="none" stroke="#888888" stroke-dasharray="5,2" d="M241.95,-44.24C250.98,-51.8 259.59,-61.18 264.5,-72 270.08,-84.3 269.38,-158.79 260.95,-206.05"/>
<polygon fill="#888888" stroke="#888888" points="257.49,-205.49 258.96,-215.98 264.35,-206.86 257.49,-205.49"/>
</g>
<!-- cache -->
<g id="node3" class="node">
<title>cache</title>
<path fill="#fff3d6" stroke="black" d="M215,-188C215,-188 12,-188 12,-188 6,-188 0,-182 0,-176 0,-176 0,-156 0,-156 0,-150 6,-144 12,-144 12,-144 215,-144 215,-144 221,-144 227,-150 227,-156 227,-156 227,-176 227,-176 227,-182 221,-188 215,-188"/>
<text text-anchor="middle" x="113.5" y="-175.2" font-family="Helvetica,sans-Serif" font-size="11.00">PROVIDENCE CACHE — verified Q&amp;A</text>
<text text-anchor="middle" x="113.5" y="-163.2" font-family="Helvetica,sans-Serif" font-size="11.00">8&#45;dim cache_key · audit_mode label ∈</text>
<text text-anchor="middle" x="113.5" y="-151.2" font-family="Helvetica,sans-Serif" font-size="11.00">{STRICT, HYBRID, UNGROUNDED}</text>
</g>
<!-- core&#45;&gt;cache -->
<g id="edge2" class="edge">
<title>core&#45;&gt;cache</title>
<path fill="none" stroke="black" d="M131,-116C129.01,-121.57 126.82,-127.71 124.68,-133.71"/>
<polygon fill="black" stroke="black" points="121.24,-132.93 121.17,-143.53 127.83,-135.29 121.24,-132.93"/>
<text text-anchor="middle" x="160.5" y="-127.8" font-family="Helvetica,sans-Serif" font-size="9.00">verify → cache</text>
</g>
<!-- core&#45;&gt;audit -->
<g id="edge4" class="edge">
<title>core&#45;&gt;audit</title>
<path fill="none" stroke="#888888" stroke-dasharray="5,2" d="M200.73,-116.01C213.64,-123.04 225.91,-132.2 234.5,-144 247.33,-161.63 250.87,-186.11 251.31,-205.54"/>
<polygon fill="#888888" stroke="#888888" points="247.81,-205.72 251.28,-215.73 254.81,-205.74 247.81,-205.72"/>
</g>
<!-- cache&#45;&gt;audit -->
<g id="edge3" class="edge">
<title>cache&#45;&gt;audit</title>
<path fill="none" stroke="#888888" stroke-dasharray="5,2" d="M151.73,-188.09C163.18,-194.29 175.8,-201.01 187.5,-207 190.37,-208.47 193.33,-209.97 196.32,-211.46"/>
<polygon fill="#888888" stroke="#888888" points="194.83,-214.63 205.35,-215.94 197.94,-208.36 194.83,-214.63"/>
<text text-anchor="middle" x="213" y="-199.8" font-family="Helvetica,sans-Serif" font-size="9.00">every write</text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.6 KiB

View file

@ -0,0 +1,36 @@
// Compact verifier flow for the 2-pager appendix.
// (Question, source-chunks) → model → (text, pointers) → verifier → label.
// Render: dot -Tsvg pager-verifier-flow.dot -o pager-verifier-flow.svg
digraph verifier_flow {
rankdir=LR
ranksep=0.35
nodesep=0.25
node [shape=box, style="rounded,filled", fontname="Helvetica", fontsize=12]
edge [fontname="Helvetica", fontsize=11]
bgcolor="white"
question [label="QUESTION", fillcolor="#fff7e6", shape=note]
retrieval [label="retrieval\n(FTS5 + phrase route\n+ rivalry exclusion)", fillcolor="#e9f3ff"]
pointers [label="POINTER MAP\nE1 → span\nE2 → span\n…", fillcolor="#dff5e7", shape=note]
model [label="LLM\nsees: question +\npointer-tagged chunks\nemits: prose with [E1] [E2] tags\n(never types the quote string)", fillcolor="#f0e6ff"]
verifier [label="verifier\n(quote · span · entity\n· paraphrase — binary,\nno LLM call)", fillcolor="#fff3d6"]
label_strict [label="STRICT\nevery claim verifies", fillcolor="#28a745", fontcolor="white"]
label_hybrid [label="HYBRID\nsome verify, some don't", fillcolor="#ffc107"]
label_ungrounded [label="UNGROUNDED\nnone verify", fillcolor="#dc3545", fontcolor="white"]
audit [label="audit chain\n+ providence cache\n(8-dim key, governance-aware)", fillcolor="#fde7e9", shape=note]
question -> retrieval -> pointers
pointers -> model
model -> verifier [label="answer\n+ pointer IDs"]
verifier -> label_strict
verifier -> label_hybrid
verifier -> label_ungrounded
label_strict -> audit [style=dashed, color="#888888"]
label_hybrid -> audit [style=dashed, color="#888888"]
label_ungrounded -> audit [style=dashed, color="#888888"]
{rank=same; label_strict; label_hybrid; label_ungrounded}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

View file

@ -0,0 +1,152 @@
<?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: verifier_flow Pages: 1 -->
<svg width="1288pt" height="152pt"
viewBox="0.00 0.00 1288.00 152.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 148)">
<title>verifier_flow</title>
<polygon fill="white" stroke="transparent" points="-4,4 -4,-148 1284,-148 1284,4 -4,4"/>
<!-- question -->
<g id="node1" class="node">
<title>question</title>
<polygon fill="#fff7e6" stroke="black" points="74,-90 0,-90 0,-54 80,-54 80,-84 74,-90"/>
<polyline fill="none" stroke="black" points="74,-90 74,-84 "/>
<polyline fill="none" stroke="black" points="80,-84 74,-84 "/>
<text text-anchor="middle" x="40" y="-68.9" font-family="Helvetica,sans-Serif" font-size="12.00">QUESTION</text>
</g>
<!-- retrieval -->
<g id="node2" class="node">
<title>retrieval</title>
<path fill="#e9f3ff" stroke="black" d="M239,-95.5C239,-95.5 119,-95.5 119,-95.5 113,-95.5 107,-89.5 107,-83.5 107,-83.5 107,-60.5 107,-60.5 107,-54.5 113,-48.5 119,-48.5 119,-48.5 239,-48.5 239,-48.5 245,-48.5 251,-54.5 251,-60.5 251,-60.5 251,-83.5 251,-83.5 251,-89.5 245,-95.5 239,-95.5"/>
<text text-anchor="middle" x="179" y="-81.9" font-family="Helvetica,sans-Serif" font-size="12.00">retrieval</text>
<text text-anchor="middle" x="179" y="-68.9" font-family="Helvetica,sans-Serif" font-size="12.00">(FTS5 + phrase route</text>
<text text-anchor="middle" x="179" y="-55.9" font-family="Helvetica,sans-Serif" font-size="12.00">+ rivalry exclusion)</text>
</g>
<!-- question&#45;&gt;retrieval -->
<g id="edge1" class="edge">
<title>question&#45;&gt;retrieval</title>
<path fill="none" stroke="black" d="M80.26,-72C85.5,-72 91.02,-72 96.66,-72"/>
<polygon fill="black" stroke="black" points="96.9,-75.5 106.9,-72 96.9,-68.5 96.9,-75.5"/>
</g>
<!-- pointers -->
<g id="node3" class="node">
<title>pointers</title>
<polygon fill="#dff5e7" stroke="black" points="372,-102 278,-102 278,-42 378,-42 378,-96 372,-102"/>
<polyline fill="none" stroke="black" points="372,-102 372,-96 "/>
<polyline fill="none" stroke="black" points="378,-96 372,-96 "/>
<text text-anchor="middle" x="328" y="-88.4" font-family="Helvetica,sans-Serif" font-size="12.00">POINTER MAP</text>
<text text-anchor="middle" x="328" y="-75.4" font-family="Helvetica,sans-Serif" font-size="12.00">E1 → span</text>
<text text-anchor="middle" x="328" y="-62.4" font-family="Helvetica,sans-Serif" font-size="12.00">E2 → span</text>
<text text-anchor="middle" x="328" y="-49.4" font-family="Helvetica,sans-Serif" font-size="12.00"></text>
</g>
<!-- retrieval&#45;&gt;pointers -->
<g id="edge2" class="edge">
<title>retrieval&#45;&gt;pointers</title>
<path fill="none" stroke="black" d="M251.35,-72C256.79,-72 262.24,-72 267.59,-72"/>
<polygon fill="black" stroke="black" points="267.72,-75.5 277.72,-72 267.72,-68.5 267.72,-75.5"/>
</g>
<!-- model -->
<g id="node4" class="node">
<title>model</title>
<path fill="#f0e6ff" stroke="black" d="M596,-108.5C596,-108.5 417,-108.5 417,-108.5 411,-108.5 405,-102.5 405,-96.5 405,-96.5 405,-47.5 405,-47.5 405,-41.5 411,-35.5 417,-35.5 417,-35.5 596,-35.5 596,-35.5 602,-35.5 608,-41.5 608,-47.5 608,-47.5 608,-96.5 608,-96.5 608,-102.5 602,-108.5 596,-108.5"/>
<text text-anchor="middle" x="506.5" y="-94.9" font-family="Helvetica,sans-Serif" font-size="12.00">LLM</text>
<text text-anchor="middle" x="506.5" y="-81.9" font-family="Helvetica,sans-Serif" font-size="12.00">sees: question +</text>
<text text-anchor="middle" x="506.5" y="-68.9" font-family="Helvetica,sans-Serif" font-size="12.00">pointer&#45;tagged chunks</text>
<text text-anchor="middle" x="506.5" y="-55.9" font-family="Helvetica,sans-Serif" font-size="12.00">emits: prose with [E1] [E2] tags</text>
<text text-anchor="middle" x="506.5" y="-42.9" font-family="Helvetica,sans-Serif" font-size="12.00">(never types the quote string)</text>
</g>
<!-- pointers&#45;&gt;model -->
<g id="edge3" class="edge">
<title>pointers&#45;&gt;model</title>
<path fill="none" stroke="black" d="M378.17,-72C383.46,-72 388.98,-72 394.64,-72"/>
<polygon fill="black" stroke="black" points="394.95,-75.5 404.95,-72 394.95,-68.5 394.95,-75.5"/>
</g>
<!-- verifier -->
<g id="node5" class="node">
<title>verifier</title>
<path fill="#fff3d6" stroke="black" d="M849,-102C849,-102 719,-102 719,-102 713,-102 707,-96 707,-90 707,-90 707,-54 707,-54 707,-48 713,-42 719,-42 719,-42 849,-42 849,-42 855,-42 861,-48 861,-54 861,-54 861,-90 861,-90 861,-96 855,-102 849,-102"/>
<text text-anchor="middle" x="784" y="-88.4" font-family="Helvetica,sans-Serif" font-size="12.00">verifier</text>
<text text-anchor="middle" x="784" y="-75.4" font-family="Helvetica,sans-Serif" font-size="12.00">(quote · span · entity</text>
<text text-anchor="middle" x="784" y="-62.4" font-family="Helvetica,sans-Serif" font-size="12.00">· paraphrase — binary,</text>
<text text-anchor="middle" x="784" y="-49.4" font-family="Helvetica,sans-Serif" font-size="12.00">no LLM call)</text>
</g>
<!-- model&#45;&gt;verifier -->
<g id="edge4" class="edge">
<title>model&#45;&gt;verifier</title>
<path fill="none" stroke="black" d="M608.13,-72C637.15,-72 668.55,-72 696.63,-72"/>
<polygon fill="black" stroke="black" points="696.81,-75.5 706.81,-72 696.81,-68.5 696.81,-75.5"/>
<text text-anchor="middle" x="657.5" y="-87.2" font-family="Helvetica,sans-Serif" font-size="11.00">answer</text>
<text text-anchor="middle" x="657.5" y="-75.2" font-family="Helvetica,sans-Serif" font-size="11.00">+ pointer IDs</text>
</g>
<!-- label_strict -->
<g id="node6" class="node">
<title>label_strict</title>
<path fill="#28a745" stroke="black" d="M1023.5,-144C1023.5,-144 913.5,-144 913.5,-144 907.5,-144 901.5,-138 901.5,-132 901.5,-132 901.5,-120 901.5,-120 901.5,-114 907.5,-108 913.5,-108 913.5,-108 1023.5,-108 1023.5,-108 1029.5,-108 1035.5,-114 1035.5,-120 1035.5,-120 1035.5,-132 1035.5,-132 1035.5,-138 1029.5,-144 1023.5,-144"/>
<text text-anchor="middle" x="968.5" y="-129.4" font-family="Helvetica,sans-Serif" font-size="12.00" fill="white">STRICT</text>
<text text-anchor="middle" x="968.5" y="-116.4" font-family="Helvetica,sans-Serif" font-size="12.00" fill="white">every claim verifies</text>
</g>
<!-- verifier&#45;&gt;label_strict -->
<g id="edge5" class="edge">
<title>verifier&#45;&gt;label_strict</title>
<path fill="none" stroke="black" d="M861.07,-94.51C872.92,-98.01 885.11,-101.62 896.83,-105.09"/>
<polygon fill="black" stroke="black" points="895.96,-108.48 906.54,-107.96 897.95,-101.77 895.96,-108.48"/>
</g>
<!-- label_hybrid -->
<g id="node7" class="node">
<title>label_hybrid</title>
<path fill="#ffc107" stroke="black" d="M1037,-90C1037,-90 900,-90 900,-90 894,-90 888,-84 888,-78 888,-78 888,-66 888,-66 888,-60 894,-54 900,-54 900,-54 1037,-54 1037,-54 1043,-54 1049,-60 1049,-66 1049,-66 1049,-78 1049,-78 1049,-84 1043,-90 1037,-90"/>
<text text-anchor="middle" x="968.5" y="-75.4" font-family="Helvetica,sans-Serif" font-size="12.00">HYBRID</text>
<text text-anchor="middle" x="968.5" y="-62.4" font-family="Helvetica,sans-Serif" font-size="12.00">some verify, some don&#39;t</text>
</g>
<!-- verifier&#45;&gt;label_hybrid -->
<g id="edge6" class="edge">
<title>verifier&#45;&gt;label_hybrid</title>
<path fill="none" stroke="black" d="M861.07,-72C866.44,-72 871.87,-72 877.31,-72"/>
<polygon fill="black" stroke="black" points="877.72,-75.5 887.72,-72 877.72,-68.5 877.72,-75.5"/>
</g>
<!-- label_ungrounded -->
<g id="node8" class="node">
<title>label_ungrounded</title>
<path fill="#dc3545" stroke="black" d="M1009,-36C1009,-36 928,-36 928,-36 922,-36 916,-30 916,-24 916,-24 916,-12 916,-12 916,-6 922,0 928,0 928,0 1009,0 1009,0 1015,0 1021,-6 1021,-12 1021,-12 1021,-24 1021,-24 1021,-30 1015,-36 1009,-36"/>
<text text-anchor="middle" x="968.5" y="-21.4" font-family="Helvetica,sans-Serif" font-size="12.00" fill="white">UNGROUNDED</text>
<text text-anchor="middle" x="968.5" y="-8.4" font-family="Helvetica,sans-Serif" font-size="12.00" fill="white">none verify</text>
</g>
<!-- verifier&#45;&gt;label_ungrounded -->
<g id="edge7" class="edge">
<title>verifier&#45;&gt;label_ungrounded</title>
<path fill="none" stroke="black" d="M861.07,-49.49C876.09,-45.05 891.68,-40.44 906.14,-36.16"/>
<polygon fill="black" stroke="black" points="907.35,-39.45 915.94,-33.25 905.36,-32.74 907.35,-39.45"/>
</g>
<!-- audit -->
<g id="node9" class="node">
<title>audit</title>
<polygon fill="#fde7e9" stroke="black" points="1274,-95.5 1076,-95.5 1076,-48.5 1280,-48.5 1280,-89.5 1274,-95.5"/>
<polyline fill="none" stroke="black" points="1274,-95.5 1274,-89.5 "/>
<polyline fill="none" stroke="black" points="1280,-89.5 1274,-89.5 "/>
<text text-anchor="middle" x="1178" y="-81.9" font-family="Helvetica,sans-Serif" font-size="12.00">audit chain</text>
<text text-anchor="middle" x="1178" y="-68.9" font-family="Helvetica,sans-Serif" font-size="12.00">+ providence cache</text>
<text text-anchor="middle" x="1178" y="-55.9" font-family="Helvetica,sans-Serif" font-size="12.00">(8&#45;dim key, governance&#45;aware)</text>
</g>
<!-- label_strict&#45;&gt;audit -->
<g id="edge8" class="edge">
<title>label_strict&#45;&gt;audit</title>
<path fill="none" stroke="#888888" stroke-dasharray="5,2" d="M1035.72,-108.77C1048.7,-105.39 1062.59,-101.77 1076.4,-98.18"/>
<polygon fill="#888888" stroke="#888888" points="1077.63,-101.48 1086.43,-95.57 1075.87,-94.7 1077.63,-101.48"/>
</g>
<!-- label_hybrid&#45;&gt;audit -->
<g id="edge9" class="edge">
<title>label_hybrid&#45;&gt;audit</title>
<path fill="none" stroke="#888888" stroke-dasharray="5,2" d="M1049.13,-72C1054.63,-72 1060.23,-72 1065.85,-72"/>
<polygon fill="#888888" stroke="#888888" points="1065.99,-75.5 1075.99,-72 1065.99,-68.5 1065.99,-75.5"/>
</g>
<!-- label_ungrounded&#45;&gt;audit -->
<g id="edge10" class="edge">
<title>label_ungrounded&#45;&gt;audit</title>
<path fill="none" stroke="#888888" stroke-dasharray="5,2" d="M1021.06,-31.42C1038,-35.83 1057.45,-40.89 1076.75,-45.91"/>
<polygon fill="#888888" stroke="#888888" points="1075.94,-49.32 1086.5,-48.45 1077.7,-42.54 1075.94,-49.32"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB

60
docs/pager.style Normal file
View file

@ -0,0 +1,60 @@
# rst2pdf style sheet for arborist 1-pager and 2-pager.
# Mirrors ~/git/unfirehose-nextjs-logger/whitepaper/whitepaper.style with
# tighter margins, smaller body text, and compact spacing so a dense
# technical summary lands inside a single Letter page (1-pager) or two
# Letter pages + appendix figures (2-pager).
pageSetup:
size: LETTER
margin-top: 0.55in
margin-bottom: 0.55in
margin-left: 0.65in
margin-right: 0.65in
spacing-header: 4
spacing-footer: 4
styles:
base:
fontSize: 9.5
leading: 12
spaceAfter: 4
bodytext:
parent: base
spaceAfter: 5
title:
spaceBefore: 0
spaceAfter: 14
alignment: TA_CENTER
fontSize: 16
leading: 19
heading1:
parent: heading
fontSize: 13
spaceBefore: 12
spaceAfter: 6
leading: 16
heading2:
parent: heading
fontSize: 11
spaceBefore: 9
spaceAfter: 5
leading: 14
heading3:
parent: heading
fontSize: 10
spaceBefore: 8
spaceAfter: 4
leading: 13
code:
fontSize: 8
leading: 10
backColor: "#f4f4f4"
field-list:
colWidths: [20%,80%]
bullet-list:
spaceAfter: 6
figure:
spaceAfter: 6
spaceBefore: 6
center:
alignment: TA_CENTER