arborist-viz/arborist_viz/templates/proof.jinja2
russell@unturf.com 0cd96ab1d7
Initial commit: arborist VIZ — Merkle command center
Pyramid web app for inspecting arborist Merkle trees over sharded SQLite:
document roots, inclusion proofs, an interactive 3D Merkle lattice
(six.js / WebGL with graceful fallback), audit-chain linkage, and a live
SSE event stream.

Generated artifacts (env/, vendored static/six/ bundles, demo databases)
are gitignored and rebuilt via the Makefile (venv, six, init-db, serve).
2026-05-28 09:22:59 -04:00

95 lines
3.8 KiB
Django/Jinja

{% extends "base.jinja2" %}
{% block body %}
<div class="proof"
data-root-hash="{{ root_hash }}"
data-leaf-index="{{ leaf_index or '' }}"
data-cache-key="{{ cache_key or '' }}">
<aside class="dash-side">
<h2 class="dash-h2">Root</h2>
<pre class="root-hash-block" id="root-hash">{{ root_hash | hex_chunk }}</pre>
<h2 class="dash-h2">Inclusion proof</h2>
<div id="proof-card" class="proof-card">
<p class="muted">select a leaf to compute its inclusion proof…</p>
</div>
<h2 class="dash-h2">Leaf content
<span class="muted" id="content-mode-label"></span>
</h2>
<div class="content-toggle" id="content-toggle" hidden>
<button type="button" data-mode="prose" class="active">prose</button>
<button type="button" data-mode="raw">raw</button>
<span class="muted" id="content-base-version"></span>
</div>
<div id="leaf-content" class="leaf-content muted">select a leaf to view its chunk text…</div>
<h2 class="dash-h2">Audit linkage</h2>
<div id="audit-link" class="muted">looking up…</div>
<h2 class="dash-h2">Live stream</h2>
<div class="dash-stream" id="sse-status">
<span class="dot dot-off"></span>
<span class="lbl">disconnected</span>
</div>
<pre class="dash-events" id="sse-events" aria-live="polite"></pre>
</aside>
<section class="proof-stage">
<div class="lattice-bar">
<span class="widget-type">[merkle-lattice-3d]</span>
<span id="lattice-status">loading…</span>
<button id="btn-pulse" disabled>pulse proof path</button>
<button id="btn-reset">reset</button>
<span class="lattice-legend muted">
<span class="legend-swatch swatch-leaf"></span>leaves
<span class="legend-swatch swatch-interior"></span>interior
<span class="legend-swatch swatch-root"></span>root
<span class="legend-swatch swatch-selected"></span>selected
</span>
</div>
<div id="lattice-canvas" class="lattice-canvas"></div>
<div id="node-inspect" class="node-inspect muted">click any node — leaves compute an inclusion proof, interior + root reveal their hash here.</div>
<div class="leaves-strip" id="leaves-strip">
<span class="muted">leaves load with the tree…</span>
</div>
<!-- Context-root variant: shown only when /api/root/{hash} returns
kind=context_root. The Merkle lattice + leaves strip still render
the tree; this panel adds the QA card + evidence manifest. Each
source is stamped with its 0-based context-tree leaf index so the
manifest, leaf chips, and inclusion proof all agree. -->
<article id="context-panel" class="widget" hidden>
<header class="widget-head">
<span class="widget-type">[context-root]</span>
<span class="widget-title">multi-source evidence</span>
</header>
<div class="widget-body">
<div id="qa-card" class="qa-card" hidden></div>
<ul id="sources-list" class="sources-list"></ul>
</div>
</article>
</section>
</div>
{% endblock %}
{% block scripts %}
<script type="module">
import { mountProofPage } from "{{ request.static_url('arborist_viz:static/viz/proof-page.js') }}?v={{ request.static_version }}";
import { connectSSE } from "{{ request.static_url('arborist_viz:static/viz/sse-client.js') }}?v={{ request.static_version }}";
const root = document.querySelector(".proof");
const rootHash = root.dataset.rootHash;
const leafIndex = root.dataset.leafIndex ? parseInt(root.dataset.leafIndex, 10) : null;
const cacheKey = root.dataset.cacheKey || null;
mountProofPage(rootHash, leafIndex, cacheKey);
connectSSE(`/sse/root/${encodeURIComponent(rootHash)}`, {
statusEl: document.getElementById("sse-status"),
eventsEl: document.getElementById("sse-events"),
});
</script>
{% endblock %}