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)
The bare-tree layout fox flagged ("kinda sucks") showed one line per
node and a huge empty page. Each node is now a card with:
- bates + audit chip + branch/current pills in the header
- the question, full width
- cited-title pills row
- <details> "answer (N chars)" expandable to the full claim-lattice
pointer-line answer (monospace, scrollable, indented with a
cyan accent stripe)
- <details> "hashes / metadata" with cache_key (clickable to
/cache/<key>), node_hash, subtree_hash, created_at, parent_bates
cmd-panel-wide on the tree page so cards fill the screen instead of
leaving 70% empty.
New /cache/{cache_key} page lists every session node referencing a
providence cache_key — surfaces the "this answer reused across N
turns/sessions" structure. /api/cache-key/{cache_key} JSON twin.
/api/resolve/{hash} now dispatches a cache_key to /cache/<key> (was
/sessions/find?q=<hash> which FTS5 couldn't tokenize). Also
recognises a session node_hash or subtree_hash → /sessions/{sid}.
Routes: /cache/{cache_key}, /api/cache-key/{cache_key} (distinct
from the pre-existing /api/cache/{cache_key} which targets the
providence_cache row itself; the ticket-§13 surface stays unchanged).
CSS: cmd-node-card, cmd-answer-pre, cmd-meta-dl, cmd-current-pill,
cmd-branch-pill, cmd-panel-wide; dark-themed with status-coded
borders (cyan for current, amber for branch points).
Mounts the sessions shard (~/.arborist/sessions.db by default) as a
read-only data source alongside the corpus shards. Imports stay
behind the arborist.read seam — viz never touches the schema directly.
Wire:
- storage.py: get_sessions(path) — process-cached SessionsView,
parallel structure to get_shards(paths). close_all() now closes
both caches.
- __init__.py: ARBORIST_VIZ_SESSIONS_DB env (or arborist.sessions_db
ini) → request.sessions request property. Defaults to
~/.arborist/sessions.db.
- routes.py: /sessions (list), /sessions/{sid} (tree),
/sessions/find (FTS5 search) + matching /api/sessions/... JSON.
- views/sessions.py: HTML + JSON handlers.
- templates/sessions_{list,tree,find}.jinja2: minimal views — table
for list, recursive tree macro for tree, table for find results.
- static/css/viz.css: cmd-table / cmd-tree / cmd-audit-* styles.
Endpoint summary:
/sessions list every session
/sessions/{sid} one session's tree (synthetic root
collapsed, cross-session children show
[from <sid>] tag)
/sessions/find?q=...&limit= FTS5 across all sessions
/api/sessions JSON list
/api/sessions/{sid} JSON tree
/api/sessions/find?q=... JSON search
Audit_mode is rendered as a colored chip (strict/hybrid/ungrounded/
canonical_projection); cited titles surface as inline pills. Privacy
contract from base.jinja2 inherits unchanged — sessions shard is
local-private per ticket #000069 §14.
- Layout: drop viewport-locking (height:100%, overflow:auto, max-height
caps) so panels stack and the page scrolls as one document instead of
clipping content; lattice canvas gets an explicit 60vh height.
- Active leaf chip: bright outline + glow + bold instead of a teal fill
that blended into the leaf text. Highlight now syncs in loadProof so a
leaf click on the 3D canvas moves the strip selection too (data-leaf-idx).
- Leaf source header: show which source document a leaf's prose belongs to
(each context-root leaf maps to a different doc).
- Default selection lands on the chunk that fed the answer (used / primary)
rather than leaf 0, which surfaced unrelated background sources.
Clone the six.js fork (shallow, sparse build/ only) from
gumyum/six.js.git instead of copying from a local ~/git/cupPCB
checkout. The fork ships vanilla three.js build output, so make six
now also creates the six.* aliases consumers import. Makes arborist-viz
self-sufficient — no sibling cupPCB checkout required.
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).