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).
376 lines
10 KiB
Python
376 lines
10 KiB
Python
"""Phase 0 schemas — Arborist VIZ ticket §7, §8, §11.
|
|
|
|
These are the Python-side mirrors of the proposal's TypeScript shapes.
|
|
The TypeScript proposal was superseded by §3-corrected (Pyramid+Jinja2
|
|
+vanilla-JS), so the canonical shape now lives here.
|
|
|
|
Hard rules baked into the schema:
|
|
|
|
* Every widget exposes the query + source roots it derived from
|
|
(``WidgetSpec.source_roots`` — §19.3).
|
|
* Activation/circuit traces are never labeled causal unless intervention
|
|
or ablation evidence exists (``CausalStatus`` enum, ticket §11).
|
|
* Soft signals (correlational/attribution) live alongside hard hashes
|
|
but never enter the proof path (CLAUDE.md soft/hard convention).
|
|
* Private chunks/prompts/raw traces never appear here — only hashes,
|
|
commitments, and selective-disclosure objects (§14).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass, field
|
|
from enum import Enum
|
|
from typing import Any, Optional
|
|
|
|
|
|
# ---------- enums --------------------------------------------------------
|
|
|
|
|
|
class NodeKind(str, Enum):
|
|
DOCUMENT_ROOT = "document_root"
|
|
LEAF = "leaf"
|
|
CHUNK = "chunk"
|
|
CLAIM = "claim"
|
|
EVIDENCE = "evidence"
|
|
FALSIFIER = "falsifier"
|
|
GRAVEYARD_ENTRY = "graveyard_entry"
|
|
AUDIT_EVENT = "audit_event"
|
|
CACHE_KEY = "cache_key"
|
|
RUN = "run"
|
|
FORK = "fork"
|
|
BENCHMARK = "benchmark"
|
|
PEER = "peer"
|
|
ACTIVATION = "activation"
|
|
CIRCUIT = "circuit"
|
|
FEATURE = "feature"
|
|
INTERVENTION = "intervention"
|
|
|
|
|
|
class NodeStatus(str, Enum):
|
|
LIVE = "live"
|
|
FAILED = "failed"
|
|
STALE = "stale"
|
|
QUARANTINED = "quarantined"
|
|
SPECULATIVE = "speculative"
|
|
UNDERDETERMINED = "underdetermined"
|
|
SELF_PROVENANCE_QUARANTINED = "self_provenance_quarantined"
|
|
FORMALLY_PROVED = "formally_proved"
|
|
|
|
|
|
class WarrantLevel(str, Enum):
|
|
UNGROUNDED = "UNGROUNDED"
|
|
POINTER_LINKED = "POINTER_LINKED"
|
|
ANCHOR_WARRANTED = "ANCHOR_WARRANTED"
|
|
EVIDENCE_WARRANTED = "EVIDENCE_WARRANTED"
|
|
FORMALLY_PROVED = "FORMALLY_PROVED"
|
|
|
|
|
|
class EdgeKind(str, Enum):
|
|
CONTAINS = "contains"
|
|
SUPPORTS = "supports"
|
|
CONTRADICTS = "contradicts"
|
|
DEPENDS_ON = "depends_on"
|
|
DERIVED_FROM = "derived_from"
|
|
FALSIFIES = "falsifies"
|
|
COMMITTED_IN = "committed_in"
|
|
VERIFIED_BY = "verified_by"
|
|
REPLAYED_BY = "replayed_by"
|
|
SERVED_BY_CACHE = "served_by_cache"
|
|
INVALIDATED_BY = "invalidated_by"
|
|
DESCENDS_FROM = "descends_from"
|
|
ACTIVATES = "activates"
|
|
ATTRIBUTED_TO = "attributed_to"
|
|
CAUSALLY_AFFECTS = "causally_affects"
|
|
PATCHED_BY = "patched_by"
|
|
ABLATED_BY = "ablated_by"
|
|
|
|
|
|
class CausalStatus(str, Enum):
|
|
"""Ticket §11 — never causal without intervention or ablation evidence."""
|
|
|
|
CORRELATIONAL_TRACE = "CORRELATIONAL_TRACE"
|
|
ATTRIBUTION_ESTIMATE = "ATTRIBUTION_ESTIMATE"
|
|
INTERVENTION_SUPPORTED = "INTERVENTION_SUPPORTED"
|
|
ABLATION_SUPPORTED = "ABLATION_SUPPORTED"
|
|
CAUSALLY_UNDERDETERMINED = "CAUSALLY_UNDERDETERMINED"
|
|
|
|
|
|
class FailureClass(str, Enum):
|
|
FALSE = "false"
|
|
STALE = "stale"
|
|
POISONED = "poisoned"
|
|
UNSUPPORTED = "unsupported"
|
|
SELF_CONFIRMING = "self_confirming"
|
|
POLICY_BLOCKED = "policy_blocked"
|
|
BENCHMARK_REGRESSION = "benchmark_regression"
|
|
CANONICALIZATION_FAILED = "canonicalization_failed"
|
|
|
|
|
|
class WidgetType(str, Enum):
|
|
MERKLE_PROOF = "merkle-proof"
|
|
ROOT_EXPLORER = "root-explorer"
|
|
CLAIM_WARRANT = "claim-warrant"
|
|
CLAIM_GRAPH = "claim-graph"
|
|
RUN_DAG = "run-dag"
|
|
AUDIT_TIMELINE = "audit-timeline"
|
|
CACHE_KEY = "cache-key"
|
|
ROOT_DIFF = "root-diff"
|
|
CLAIM_GRAVEYARD = "claim-graveyard"
|
|
CIRCUIT_TRACE = "circuit-trace"
|
|
MERKLE_LATTICE_3D = "merkle-lattice-3d"
|
|
MESH_PEER = "mesh-peer"
|
|
|
|
|
|
# ---------- graph primitives --------------------------------------------
|
|
|
|
|
|
@dataclass(slots=True)
|
|
class VizNode:
|
|
"""Unified epistemic object node (ticket §8.1)."""
|
|
|
|
id: str
|
|
kind: NodeKind
|
|
status: NodeStatus
|
|
hash: Optional[str] = None
|
|
label: Optional[str] = None
|
|
warrant: Optional[WarrantLevel] = None
|
|
time: Optional[str] = None
|
|
roots: dict[str, str] = field(default_factory=dict)
|
|
metrics: dict[str, float] = field(default_factory=dict)
|
|
metadata: dict[str, Any] = field(default_factory=dict)
|
|
|
|
|
|
@dataclass(slots=True)
|
|
class VizEdge:
|
|
"""Unified epistemic object edge (ticket §8.2)."""
|
|
|
|
id: str
|
|
source: str
|
|
target: str
|
|
kind: EdgeKind
|
|
weight: Optional[float] = None
|
|
confidence: Optional[float] = None
|
|
timestamp: Optional[str] = None
|
|
metadata: dict[str, Any] = field(default_factory=dict)
|
|
|
|
|
|
@dataclass(slots=True)
|
|
class GraphPatch:
|
|
"""One audit-chain-derived patch applied to the live dashboard (ticket §8.3).
|
|
|
|
Patches are content-addressed by ``event_hash``; the dashboard treats
|
|
them as idempotent and ordered by ``seq``.
|
|
"""
|
|
|
|
seq: int
|
|
event_hash: str
|
|
timestamp: str
|
|
root_hash: Optional[str] = None
|
|
# Each patch op is a tuple-like dict:
|
|
# {"op": "node.upsert"|"node.status"|"edge.upsert"|
|
|
# "edge.delete"|"metric.update", ...}
|
|
patches: list[dict[str, Any]] = field(default_factory=list)
|
|
|
|
|
|
# ---------- proof + audit ------------------------------------------------
|
|
|
|
|
|
@dataclass(slots=True)
|
|
class ProofPath:
|
|
"""One Merkle inclusion proof (ticket §6.1, §13).
|
|
|
|
Inclusion is integrity, not semantic truth — DoD #10.
|
|
"""
|
|
|
|
root_hash: str
|
|
leaf_index: int
|
|
leaf_hash: str
|
|
canonical_bytes_hash: str
|
|
sibling_hashes: list[str]
|
|
left_right_flags: list[bool]
|
|
computed_root: str
|
|
expected_root: str
|
|
domain_separator: str
|
|
canonicalization_version: str
|
|
chunking_version: str
|
|
schema_version: str
|
|
verifier_policy_hash: str
|
|
|
|
@property
|
|
def passed(self) -> bool:
|
|
return self.computed_root == self.expected_root
|
|
|
|
|
|
@dataclass(slots=True)
|
|
class AuditEvent:
|
|
"""One audit-chain event (ticket §6.6, §13)."""
|
|
|
|
event_hash: str
|
|
prev_event_hash: Optional[str]
|
|
timestamp: str
|
|
actor: str
|
|
event_kind: str
|
|
root_hash: Optional[str] = None
|
|
claim_id: Optional[str] = None
|
|
run_id: Optional[str] = None
|
|
body_hash: Optional[str] = None
|
|
metadata: dict[str, Any] = field(default_factory=dict)
|
|
|
|
|
|
# ---------- activation / circuit (ticket §11) ---------------------------
|
|
|
|
|
|
@dataclass(slots=True)
|
|
class ActivationHookpoint:
|
|
layer: int
|
|
module: str # attention | mlp | residual | embedding | logits
|
|
activation_value: float
|
|
head_id: Optional[int] = None
|
|
neuron_id: Optional[int] = None
|
|
feature_id: Optional[str] = None
|
|
activation_rank: Optional[int] = None
|
|
tensor_hash: Optional[str] = None
|
|
|
|
|
|
@dataclass(slots=True)
|
|
class ActivationTrace:
|
|
"""Mechanistic/interp activation trace (ticket §11)."""
|
|
|
|
trace_id: str
|
|
run_id: str
|
|
model_id: str
|
|
model_profile_hash: str
|
|
prompt_hash: str
|
|
token_span: tuple[int, int]
|
|
hookpoints: list[ActivationHookpoint]
|
|
trace_root: str
|
|
linked_claim_ids: list[str] = field(default_factory=list)
|
|
output_span: Optional[tuple[int, int]] = None
|
|
causal_status: CausalStatus = CausalStatus.CORRELATIONAL_TRACE
|
|
|
|
|
|
@dataclass(slots=True)
|
|
class CircuitNode:
|
|
id: str
|
|
layer: int
|
|
module: str
|
|
activation_summary: float
|
|
feature_id: Optional[str] = None
|
|
|
|
|
|
@dataclass(slots=True)
|
|
class CircuitEdge:
|
|
source: str
|
|
target: str
|
|
attribution_weight: float
|
|
method: str # activation_patching | integrated_gradients | logit_lens | sae | manual
|
|
|
|
|
|
@dataclass(slots=True)
|
|
class CircuitTrace:
|
|
"""Mechanistic circuit (ticket §11)."""
|
|
|
|
circuit_id: str
|
|
model_id: str
|
|
trace_ids: list[str]
|
|
nodes: list[CircuitNode]
|
|
edges: list[CircuitEdge]
|
|
causal_status: CausalStatus = CausalStatus.CORRELATIONAL_TRACE
|
|
linked_claim_ids: list[str] = field(default_factory=list)
|
|
|
|
|
|
# ---------- dashboard composition (ticket §7) ---------------------------
|
|
|
|
|
|
@dataclass(slots=True)
|
|
class FilterSpec:
|
|
field: str
|
|
op: str # eq | neq | in | gte | lte | range | contains
|
|
value: Any
|
|
|
|
|
|
@dataclass(slots=True)
|
|
class QuerySpec:
|
|
"""Compiled at the Pyramid view layer to SQL against arborist shards."""
|
|
|
|
select: list[str] = field(default_factory=list)
|
|
from_: str = ""
|
|
where: dict[str, Any] = field(default_factory=dict)
|
|
join: list[str] = field(default_factory=list)
|
|
limit: int = 1000
|
|
graph: Optional[str] = None # graph query alternative form
|
|
root: Optional[str] = None
|
|
depth: Optional[int] = None
|
|
edge_kinds: list[str] = field(default_factory=list)
|
|
include_statuses: list[str] = field(default_factory=list)
|
|
|
|
|
|
@dataclass(slots=True)
|
|
class ViewSpec:
|
|
"""Renderer hints for a widget."""
|
|
|
|
renderer: str # table | dag | graph | three-d | timeline | card
|
|
options: dict[str, Any] = field(default_factory=dict)
|
|
|
|
|
|
@dataclass(slots=True)
|
|
class InteractionSpec:
|
|
"""Cross-widget linkage (ticket §4 interaction model)."""
|
|
|
|
on: str # select | hover | filter
|
|
target_widget_ids: list[str] = field(default_factory=list)
|
|
bind_field: str = ""
|
|
|
|
|
|
@dataclass(slots=True)
|
|
class DataSourceSpec:
|
|
id: str
|
|
kind: str # arborist_shard | proof_pack | audit_stream | trace_file | mesh_snapshot
|
|
locator: str
|
|
read_only: bool = True
|
|
|
|
|
|
@dataclass(slots=True)
|
|
class PanelLayout:
|
|
panel_id: str
|
|
x: int
|
|
y: int
|
|
w: int
|
|
h: int
|
|
min_w: Optional[int] = None
|
|
min_h: Optional[int] = None
|
|
dock: Optional[str] = None # left | right | bottom | floating | main
|
|
|
|
|
|
@dataclass(slots=True)
|
|
class WidgetSpec:
|
|
"""A single widget instance (ticket §7).
|
|
|
|
``source_roots`` is the §19.3 transparency contract — every widget
|
|
exposes the roots it derived from so the dashboard never asserts
|
|
state, only projects it.
|
|
"""
|
|
|
|
widget_id: str
|
|
type: WidgetType
|
|
title: str
|
|
data_source_id: str
|
|
query: QuerySpec
|
|
view: ViewSpec
|
|
source_roots: list[str] = field(default_factory=list)
|
|
interactions: list[InteractionSpec] = field(default_factory=list)
|
|
|
|
|
|
@dataclass(slots=True)
|
|
class DashboardConfig:
|
|
"""Top-level dashboard (ticket §7)."""
|
|
|
|
id: str
|
|
title: str
|
|
layout: list[PanelLayout]
|
|
widgets: list[WidgetSpec]
|
|
data_sources: list[DataSourceSpec] = field(default_factory=list)
|
|
global_filters: list[FilterSpec] = field(default_factory=list)
|
|
interactions: list[InteractionSpec] = field(default_factory=list)
|
|
description: Optional[str] = None
|
|
version: str = "dashboard-v1"
|