Two fixes to fox feedback ("rarely like stuff collapsed · why does it
need to be a different screen than the other node types?"):
1. <details open> on answer + metadata panels in sessions_tree.jinja2.
Expanded by default — fox rarely wants stuff collapsed; clicks to
collapse cost nothing and discoverability of the field is what
matters on first read.
2. /proof/{hash} is now THE dispatcher — drop ANY hash here and the
page resolves the right view:
- corpus document_root / leaf / merkle interior → proof.jinja2
(existing 3D Merkle lattice + inclusion proof + leaf-list)
- providence cache_key with session references → cache_key.jinja2
(every session node that hit this cache entry)
- session node_hash / subtree_hash → sessions_tree.jinja2
(the session's conversation tree)
- session_root (= seq=0 node's subtree_hash) → sessions_tree.jinja2
Aligns with ticket #000069 §13 discipline: "never mint new
kind-named URLs." /sessions/{sid} and /cache/{cache_key} stay as
working aliases — but the resolver, the metadata-panel links, and
the hash-drop bar all route through /proof/{hash} now.
Sessions are still tree-shaped (parent/child) where corpus roots are
flat leaf lists, so the IN-PAGE view differs. That's a topology fact,
not a URL choice — sessions and documents live in the same hash
universe under one route. A future six.js tree widget could share
the proof.jinja2 3D stage; not in this commit.
Resolver:
- /api/resolve/{hash} → "url": "/proof/{hash}" for cache_keys and
session node hashes (was /cache/<key> and /sessions/<sid>).
Templates:
- sessions_tree node-card cache_key + node_hash + subtree_hash are
now clickable → each opens /proof/<hash>.
- <details> on answer + hash panels default-open.
Smoke verified all four dispatch paths:
/proof/<cache_key> → cache_key.jinja2
/proof/<session_root> → sessions_tree.jinja2
/proof/<node_hash> → sessions_tree.jinja2
/proof/<unknown> → proof.jinja2 (corpus fallback)
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
arborist-viz — Merkle Command Center
====================================
A configurable, proof-native browser dashboard for inspecting arborist's
content-addressed state — Merkle roots, proof paths, claim warrants,
audit trails, run-DAGs, claim graveyards, and (gated) 3D state geometry
and circuit/activation traces.
This is the **sibling repo** for ticket #000069 (arborist VIZ / Merkle
Command Center). The §3-corrected unturf-native stack:
* **Backend** — Pyramid + Jinja2 + SQLAlchemy + waitress (Python 3.10+).
* **Streaming** — SSE (``text/event-stream``) directly off arborist's
audit chain. No NATS, no WebSockets, no Node.
* **Frontend** — vanilla JS, no build step. ``six.js`` (fox's
CWE-407-patched three.js fork, vendored from ``~/git/cupPCB/cdn/six``)
drives the 3D widgets in later phases.
* **Storage** — SQLite for dashboard metadata. arborist shards stay the
source of truth and are imported read-only via ``arborist.embed``.
Hard constraints (from the ticket)
----------------------------------
1. **Projects state, never asserts it.** Every widget exposes the query
and source roots it derived from (§19.3).
2. **Soft signals never enter the proof path** (CLAUDE.md soft/hard-hash
rule). Activation/circuit traces inherit #000049's cage verbatim.
3. **Private-leaf default-deny.** ``privacy.reveal_private_leaves`` is
``false`` by default; commitments and selective-disclosure objects
only.
4. **Pyramid stays the truth.** Browser-side proof verification is a
v1 non-goal — the Pyramid view computes the proof and returns
PASS/FAIL + receipt.
Quick start
-----------
::
git clone https://git.unturf.com/engineering/arborist-viz
cd arborist-viz
make all # creates venv, installs, vendors six.js, inits DB, serves
Then open http://127.0.0.1:6543/.
Layout
------
::
arborist_viz/
__init__.py # Pyramid main() factory
routes.py # add_route() declarations
schemas.py # VizNode / VizEdge / GraphPatch / ProofPath /
# AuditEvent / ActivationTrace / CircuitTrace /
# DashboardConfig / WidgetSpec (Phase 0)
views/
home.py # GET /, GET /version
dashboards.py # GET/POST/PUT /api/dashboards[/:id]
roots.py # GET /api/root/:hash[/leaves]
proofs.py # GET /api/proof/:root/:leaf_index
claims.py # GET /api/claim/:id[/neighborhood]
audit.py # GET /api/audit/:event_hash[/chain]
sse.py # SSE: /sse/audit/live, /sse/run/:id, /sse/root/:hash
models/ # SQLAlchemy: Dashboard, Widget, Layout
templates/ # Jinja2 server-rendered HTML
base.jinja2
dashboard.jinja2
widgets/
root_explorer.jinja2
claim_warrant.jinja2
audit_timeline.jinja2
run_dag.jinja2
static/
six/ # vendored six.js bundles (run `make six`)
viz/ # vanilla JS: dashboard.js, sse-client.js
css/ # viz.css (command-center dark theme)
scripts/
init_db.py
alembic/
env.py
versions/
tests/
Phase status
------------
Phase 0 (schema + dashboard shell + proof/root/claim/audit/run widgets,
ticket §17 phases 0–3) is the default scope. Later phases:
* Phase 4 — SSE live streaming (this scaffold ships the endpoint surface;
arborist→SSE bridge follows).
* Phase 5 — 3D Merkle lattice via six.js.
* Phase 6 — large-graph widgets (vanilla canvas + six.js;
Cosmograph/sigma.js only if a measured need surfaces).
* Phase 7 — circuit/activation tracing, **gated on arborist #000062**
producing a ``MechanisticWitnessRoot``.
* Phase 8 — embeddable web-components.
License
-------
AGPL-3.0-only — matches the arborist parent.