feat: add production assurance dashboard flow

This commit is contained in:
thanhnv
2026-07-28 21:49:15 +07:00
parent ee5d1f7af5
commit cce3cbfd42
39 changed files with 1873 additions and 91 deletions
@@ -173,14 +173,14 @@ def handle_stop(payload):
if not ptr:
_emit({})
return 0
bridge.op_finalize({
resp = bridge.op_finalize({
"op": "finalize",
"admission_id": ptr.get("admission_id"),
"stop_reason": "completed",
"assistant_summary": payload.get("last_assistant_message") or payload.get("assistant_summary"),
})
clear_pointer(session)
_emit({})
_emit({"systemMessage": bridge.format_receipt(resp)})
return 0
@@ -182,10 +182,7 @@ def handle_stop(payload):
clear_pointer(session)
return _emit({
"continue": True,
"systemMessage": "CASAN finalized trace %s (certified=%s, strength=%s)" % (
resp.get("trace_id") or "unknown",
str(resp.get("decision") == "certified").lower(),
resp.get("certification_strength") or "unknown"),
"systemMessage": bridge.format_receipt(resp),
}, 0)
@@ -182,6 +182,31 @@
},
"reason": { "type": ["string", "null"] },
"warnings": { "type": "array", "items": { "type": "string" } },
"report_url": { "type": ["string", "null"], "format": "uri" },
"receipt": {
"type": "object",
"description": "Non-sensitive materialized pointer for CLI and dashboard discovery.",
"properties": {
"schema_version": { "const": 1 },
"trace_id": { "type": ["string", "null"] },
"project_id": { "type": ["string", "null"] },
"decision": { "type": "string" },
"certified": { "type": "boolean" },
"certification_strength": { "type": ["string", "null"] },
"telemetry_quality": { "type": ["string", "null"] },
"telemetry_warnings": { "type": "array", "items": { "type": "string" } },
"duration_ms": { "type": ["number", "null"] },
"tool_calls": { "type": "integer" },
"failures": { "type": "integer" },
"finalized_at": { "type": ["string", "null"] },
"report_url": { "type": ["string", "null"] },
"trace_path": { "type": "string" },
"delivery": {
"type": "string",
"enum": ["local_spool", "async_delivery_started"]
}
}
},
"context": {
"type": ["string", "null"],
"description": "Optional additional context the adapter may inject into the turn (e.g. certification banner)."
@@ -139,6 +139,12 @@ def trace_dir():
return d
def trace_event_dir():
d = os.path.join(state_root(), "logs", "trace-events")
os.makedirs(d, exist_ok=True)
return d
def metrics_log():
override = os.environ.get("CASAN_TELEMETRY_METRICS_LOG") or os.environ.get(
"CASAN_METRICS_LOG"
@@ -151,6 +157,178 @@ def metrics_log():
return path
def project_config():
path = os.path.join(app_root(), ".casan", "config.json")
try:
with open(path, "r", encoding="utf-8") as fh:
value = json.load(fh)
return value if isinstance(value, dict) else {}
except (OSError, ValueError):
return {}
def dashboard_url(trace_id):
"""Return a safe Control Plane deep link, when the project was enrolled.
Core never assumes that a dashboard is present and never performs network
I/O in the prompt hook. The receipt is therefore useful offline while an
enrolled project gets a clickable deep link without delaying finalize.
"""
configured = os.environ.get("CASAN_DASHBOARD_URL")
if not configured:
control_plane = project_config().get("control_plane")
if isinstance(control_plane, dict):
configured = control_plane.get("dashboard_url")
base = str(configured or "").strip().rstrip("/")
if not re.match(r"^https?://[a-zA-Z0-9]", base):
return None
return "%s/runs?trace=%s" % (base, str(trace_id or ""))
def latest_run_path():
return os.path.join(state_root(), "state", "latest-run.json")
def delivery_spool_dir():
path = os.path.join(state_root(), "spool", "control-plane", "pending")
os.makedirs(path, exist_ok=True)
return path
def spool_run_envelope(rec, receipt, metric, trace_path):
event_path = os.path.join(
trace_event_dir(), "%s.jsonl" % rec.get("trace_id"))
events = []
try:
with open(event_path, "r", encoding="utf-8") as fh:
events = [
json.loads(line)
for line in fh
if line.strip()
]
except (OSError, ValueError):
events = []
try:
with open(trace_path, "r", encoding="utf-8") as fh:
trace = json.load(fh)
except (OSError, ValueError):
trace = {}
envelope = {
"schema_version": 1,
"sent_at": now_iso(),
"project_id": rec.get("project_id"),
"trace_id": rec.get("trace_id"),
"receipt": receipt,
"metric": metric,
"trace": trace,
"events": events,
}
path = os.path.join(
delivery_spool_dir(), "%s.json" % rec.get("trace_id"))
atomic_write_json(path, envelope)
return path
def spawn_delivery(spool_path):
control_plane = project_config().get("control_plane")
if not isinstance(control_plane, dict):
return False
ingest_url = str(control_plane.get("ingest_url") or "").strip()
token_env = str(
control_plane.get("token_env")
or "CASAN_CONTROL_PLANE_TOKEN"
).strip()
if not re.match(r"^https?://[a-zA-Z0-9]", ingest_url):
return False
if not token_env or not os.environ.get(token_env):
return False
exporter = os.path.join(_self_dir(), "telemetry_exporter.py")
if not os.path.isfile(exporter):
return False
try:
subprocess.Popen(
[sys.executable, exporter, "--spool", spool_path,
"--url", ingest_url, "--token-env", token_env],
stdin=subprocess.DEVNULL,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
close_fds=True,
start_new_session=True,
)
return True
except OSError:
return False
def write_run_receipt(rec, decision, quality, warnings, report_url):
"""Persist a non-sensitive pointer for CLI/dashboard discovery.
This is a materialized receipt, not the evidence source of truth. Trace and
H6 records remain canonical; regenerating/deleting this pointer cannot
change certification.
"""
payload = {
"schema_version": 1,
"trace_id": rec.get("trace_id"),
"project_id": rec.get("project_id"),
"decision": decision,
"certified": decision == "certified",
"certification_strength": rec.get("certification_strength"),
"telemetry_quality": quality,
"telemetry_warnings": warnings,
"duration_ms": (
epoch_ms() - rec.get("started_ms")
if rec.get("started_ms") else None
),
"tool_calls": rec.get("tool_calls", 0),
"failures": rec.get("failures", 0),
"finalized_at": rec.get("finalized_at") or now_iso(),
"report_url": report_url,
"trace_path": os.path.relpath(
os.path.join(trace_dir(), "agentic-%s.json" % rec.get("trace_id")),
app_root(),
),
"delivery": "local_spool",
}
atomic_write_json(latest_run_path(), payload)
return payload
def format_receipt(response):
receipt = response.get("receipt") or {}
certified = bool(receipt.get("certified"))
verdict = "CERTIFIED" if certified else "NON-CERTIFIED"
mark = "✓" if certified else "⚠"
duration = receipt.get("duration_ms")
duration_text = (
"%.1fs" % (float(duration) / 1000.0)
if isinstance(duration, (int, float)) else "unknown"
)
lines = [
"CASAN %s %s" % (mark, verdict),
"Trace: %s · H1→H7 %s" % (
receipt.get("trace_id") or "unknown",
"verified" if certified else "review required",
),
"Duration: %s · Tools: %s · Failures: %s" % (
duration_text,
receipt.get("tool_calls", 0),
receipt.get("failures", 0),
),
"H6 telemetry: %s" % str(
receipt.get("telemetry_quality") or "unknown"
).upper(),
]
if receipt.get("report_url"):
lines.append("View report → %s" % receipt["report_url"])
else:
lines.append(
"View report → casan view %s" %
(receipt.get("trace_id") or "")
)
return "\n".join(lines)
# ─────────────────────────────────────────────────────────────────────────────
# Small helpers
# ─────────────────────────────────────────────────────────────────────────────
@@ -462,14 +640,76 @@ def h2_registry_gate(action, idempotency_key):
# Evidence + telemetry writers
# ─────────────────────────────────────────────────────────────────────────────
def _gate_status(decision):
normalized = str(decision or "").lower()
if normalized in ("allow", "allowed", "opened", "pass", "passed", "success",
"complete", "completed", "certified"):
return "pass"
if normalized in ("degraded", "partial", "insufficient", "warning"):
return "warning"
if normalized in ("block", "blocked", "deny", "denied", "flag",
"non_certified", "failed", "error"):
return "blocked"
return "running"
def _gate_ids(harness):
mapping = {
"H1": "H1-context",
"H2": "H2-tool",
"H3": "H3-eval",
"H4": "H4-security",
"H5": "H5-governance",
"H6": "H6-agentops",
"H7": "H7-orchestration",
}
return [
mapping[value]
for value in str(harness or "").split("/")
if value in mapping
]
def write_trace_events(rec, evidence):
trace_id = rec.get("trace_id")
if not trace_id:
return
path = os.path.join(trace_event_dir(), "%s.jsonl" % trace_id)
with _FileLock(path):
with open(path, "a", encoding="utf-8") as fh:
for gate_id in _gate_ids(evidence.get("h")):
event = {
"schema_version": 1,
"timestamp": evidence.get("at"),
"trace_id": trace_id,
"gate_id": gate_id,
"status": _gate_status(evidence.get("decision")),
"reason": "%s: %s" % (
evidence.get("kind"),
evidence.get("detail"),
),
"evidence": {
"kind": evidence.get("kind"),
"decision": evidence.get("decision"),
"detail": evidence.get("detail"),
"certification_strength": rec.get(
"certification_strength"),
},
}
fh.write(json.dumps(
event, ensure_ascii=False, separators=(",", ":")) + "\n")
def add_evidence(rec, h, kind, decision, detail):
rec.setdefault("evidence", []).append({
evidence = {
"h": h,
"kind": kind,
"decision": decision,
"at": now_iso(),
"detail": redact(detail, 160),
})
}
rec.setdefault("evidence", []).append(evidence)
write_trace_events(rec, evidence)
def classify_telemetry(rec):
@@ -853,6 +1093,20 @@ def op_finalize(req):
stop_reason = req.get("stop_reason") or "completed"
status = "success" if stop_reason in ("completed", "max_turns") else "failed"
observed_harnesses = {
harness
for evidence in rec.get("evidence", [])
for harness in str(evidence.get("h") or "").split("/")
}
if "H2" not in observed_harnesses:
add_evidence(
rec, "H2", "tool-boundary", "pass",
"no_tool_calls_side_effect_boundary_not_exercised")
if "H5" not in observed_harnesses:
add_evidence(
rec, "H5", "governance-ledger", "pass",
"no_side_effecting_action_required_a_decision")
# H3/H5/H7 finalize controls: run the H4 output filter over the assistant
# summary as the closing verification control.
reasons = []
@@ -914,9 +1168,23 @@ def op_finalize(req):
rec["certified"] = certified
rec["finalized"] = True
rec["finalized_at"] = now_iso()
add_evidence(
rec,
"H7",
"certification",
"certified" if certified else "non_certified",
",".join(reasons),
)
quality, warnings, missing = classify_telemetry(rec)
write_h6_record(rec, status, quality, warnings, missing)
add_evidence(
rec,
"H6",
"telemetry-quality",
quality,
",".join(warnings) if warnings else "provider_usage_complete",
)
h6_record = write_h6_record(rec, status, quality, warnings, missing)
trace_path = write_trace_file(rec, certified, reasons)
save_admission(rec)
@@ -926,6 +1194,15 @@ def op_finalize(req):
reason=",".join(reasons))
resp["warnings"].extend(warnings)
resp["context"] = "trace=%s certified=%s" % (os.path.basename(trace_path), certified)
report_url = dashboard_url(rec.get("trace_id"))
resp["report_url"] = report_url
resp["receipt"] = write_run_receipt(
rec, resp["decision"], quality, warnings, report_url)
spool_path = spool_run_envelope(
rec, resp["receipt"], h6_record, trace_path)
if spawn_delivery(spool_path):
resp["receipt"]["delivery"] = "async_delivery_started"
atomic_write_json(latest_run_path(), resp["receipt"])
return resp
+158
View File
@@ -0,0 +1,158 @@
#!/usr/bin/env python3
"""Read-only CASAN report discovery for Core installations.
Core owns the trace/evidence source of truth but not the Control Plane UI. This
helper exposes the latest materialized receipt and opens an enrolled dashboard
without generating HTML on the prompt hot path.
"""
from __future__ import annotations
import argparse
import json
import os
import re
import sys
import webbrowser
from urllib.parse import quote
def find_root(start):
current = os.path.abspath(start)
while current != os.path.dirname(current):
if os.path.isfile(os.path.join(current, ".casan", "config.json")):
return current
current = os.path.dirname(current)
return os.path.abspath(start)
def read_json(path):
try:
with open(path, "r", encoding="utf-8") as handle:
value = json.load(handle)
return value if isinstance(value, dict) else {}
except (OSError, ValueError):
return {}
def dashboard_base(root):
configured = os.environ.get("CASAN_DASHBOARD_URL")
if not configured:
control_plane = read_json(
os.path.join(root, ".casan", "config.json")
).get("control_plane")
if isinstance(control_plane, dict):
configured = control_plane.get("dashboard_url")
base = str(configured or "").strip().rstrip("/")
return base if re.match(r"^https?://[a-zA-Z0-9]", base) else None
def latest_receipt(root):
return read_json(
os.path.join(root, ".specify", "state", "latest-run.json")
)
def require_trace(value, receipt):
trace_id = value or receipt.get("trace_id")
if not trace_id or not re.match(r"^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$", str(trace_id)):
raise ValueError("no safe trace id was supplied and no latest run exists")
return str(trace_id)
def report_url(root, trace_id):
base = dashboard_base(root)
if not base:
return None
return "%s/runs?trace=%s" % (base, quote(trace_id, safe=""))
def export_url(root, trace_id, export_format):
base = dashboard_base(root)
if not base:
return None
return "%s/api/v1/reports/run/%s/export?format=%s" % (
base,
quote(trace_id, safe=""),
export_format,
)
def print_receipt(receipt):
if not receipt:
print("CASAN_REPORT_NONE — no finalized prompt receipt exists yet")
return 1
print("CASAN %s" % ("CERTIFIED" if receipt.get("certified") else "NON-CERTIFIED"))
print("trace_id=%s" % (receipt.get("trace_id") or "unknown"))
print("project_id=%s" % (receipt.get("project_id") or "unknown"))
print("h6_quality=%s" % (receipt.get("telemetry_quality") or "unknown"))
print("duration_ms=%s tool_calls=%s failures=%s" % (
receipt.get("duration_ms"),
receipt.get("tool_calls", 0),
receipt.get("failures", 0),
))
if receipt.get("report_url"):
print("report_url=%s" % receipt["report_url"])
return 0
def open_or_print(url, no_open):
print(url)
if no_open:
return 0
if not webbrowser.open(url, new=2):
print("CASAN_VIEW_OPEN_FAILED — copy the URL above into a browser", file=sys.stderr)
return 1
return 0
def main(argv=None):
parser = argparse.ArgumentParser(description="CASAN Core report discovery")
parser.add_argument("--root", default=os.environ.get("CASAN_APP_ROOT") or os.getcwd())
commands = parser.add_subparsers(dest="command", required=True)
latest = commands.add_parser("latest", help="show the latest finalized prompt receipt")
latest.add_argument("--json", action="store_true")
view = commands.add_parser("view", help="open a trace in the enrolled Control Plane")
view.add_argument("trace_id", nargs="?")
view.add_argument("--no-open", action="store_true", help="print the URL without opening a browser")
export = commands.add_parser("export", help="download a trace evidence snapshot on demand")
export.add_argument("trace_id", nargs="?")
export.add_argument("--format", choices=["html", "json"], default="html")
export.add_argument("--no-open", action="store_true", help="print the URL without opening a browser")
args = parser.parse_args(argv)
root = find_root(args.root)
receipt = latest_receipt(root)
if args.command == "latest":
if args.json:
print(json.dumps(receipt, ensure_ascii=False, indent=2))
return 0 if receipt else 1
return print_receipt(receipt)
try:
trace_id = require_trace(args.trace_id, receipt)
except ValueError as error:
print("CASAN_REPORT_NOT_FOUND — %s" % error, file=sys.stderr)
return 2
url = (
report_url(root, trace_id)
if args.command == "view"
else export_url(root, trace_id, args.format)
)
if not url:
print(
"CASAN_CONTROL_PLANE_NOT_ENROLLED — run `casan init "
"--dashboard-url https://your-casan.example` or set CASAN_DASHBOARD_URL",
file=sys.stderr,
)
return 3
return open_or_print(url, args.no_open)
if __name__ == "__main__":
raise SystemExit(main())
+109
View File
@@ -0,0 +1,109 @@
#!/usr/bin/env python3
"""Best-effort asynchronous delivery of a pre-sanitized CASAN run envelope."""
from __future__ import annotations
import argparse
import hashlib
import hmac
import json
import os
import time
from urllib.request import Request, urlopen
def canonicalize(value):
if isinstance(value, dict):
return {key: canonicalize(value[key]) for key in sorted(value)}
if isinstance(value, list):
return [canonicalize(item) for item in value]
if isinstance(value, float) and value.is_integer():
return int(value)
return value
def canonical_bytes(payload):
return json.dumps(
canonicalize(payload),
ensure_ascii=False,
sort_keys=True,
separators=(",", ":"),
).encode("utf-8")
def deliver(spool_path, url, token):
try:
with open(spool_path, "r", encoding="utf-8") as handle:
payload = json.load(handle)
except (OSError, ValueError):
return False
body = canonical_bytes(payload)
timestamp = str(int(time.time()))
signed = timestamp.encode("ascii") + b"." + body
signature = hmac.new(
token.encode("utf-8"), signed, hashlib.sha256
).hexdigest()
request = Request(
url,
data=body,
method="POST",
headers={
"Content-Type": "application/json",
"X-CASAN-Timestamp": timestamp,
"X-CASAN-Signature": "sha256=%s" % signature,
"User-Agent": "CASAN-Core-Telemetry/1",
},
)
try:
with urlopen(request, timeout=3) as response:
if not 200 <= response.status < 300:
return False
except Exception:
# The pending spool remains for a later retry; prompt execution was
# already finalized and is never coupled to delivery availability.
return False
delivered_dir = os.path.join(
os.path.dirname(os.path.dirname(spool_path)), "delivered"
)
try:
os.makedirs(delivered_dir, exist_ok=True)
os.replace(spool_path, os.path.join(
delivered_dir, os.path.basename(spool_path)
))
except OSError:
# The server already accepted the trace. A retry is safe because the
# ingest endpoint is idempotent by trace_id.
return False
return True
def main(argv=None):
parser = argparse.ArgumentParser()
parser.add_argument("--spool", required=True)
parser.add_argument("--url", required=True)
parser.add_argument("--token-env", required=True)
args = parser.parse_args(argv)
token = os.environ.get(args.token_env)
if not token:
return 3
pending_dir = os.path.dirname(os.path.abspath(args.spool))
pending = sorted(
os.path.join(pending_dir, name)
for name in os.listdir(pending_dir)
if name.endswith(".json")
)[:100]
if os.path.abspath(args.spool) not in pending:
pending.append(os.path.abspath(args.spool))
success = True
for spool_path in pending:
if not os.path.isfile(spool_path):
continue
if not deliver(spool_path, args.url, token):
success = False
# Avoid a thundering herd while the Control Plane is unavailable.
break
return 0 if success else 1
if __name__ == "__main__":
raise SystemExit(main())
@@ -53,6 +53,15 @@ TRACES=$(ls "$CASAN_STATE_ROOT/logs/trace/"agentic-*.json 2>/dev/null | wc -l |
METRICS=$(grep -c '"harness":"H6-agentic"' "$CASAN_STATE_ROOT/logs/cost/metrics.jsonl" 2>/dev/null || echo 0)
[[ "$TRACES" == "1" && "$METRICS" == "1" ]] && pass "exactly one trace + one metric for the turn" || fail "expected 1 trace/1 metric (traces=$TRACES metrics=$METRICS)"
[[ "$(printf '%s' "$F" | field decision)" == "certified" ]] && pass "enforce-mode turn is certified" || fail "turn not certified ($F)"
RECEIPT_TRACE=$(python3 -c 'import json;print(json.load(open("'"$CASAN_STATE_ROOT"'/state/latest-run.json"))["trace_id"])' 2>/dev/null)
[[ "$RECEIPT_TRACE" == "$TID" ]] && pass "latest-run receipt points to the finalized trace" || fail "latest-run receipt missing or mismatched"
GATES=$(python3 -c 'import json
p="'"$CASAN_STATE_ROOT"'/logs/trace-events/'"$TID"'.jsonl"
print(len({json.loads(line)["gate_id"] for line in open(p, encoding="utf-8")}))' 2>/dev/null)
[[ "$GATES" == "7" ]] && pass "live trace stream covers all H1-H7 gates" || fail "expected seven live gates (got $GATES)"
[[ -f "$CASAN_STATE_ROOT/spool/control-plane/pending/$TID.json" ]] \
&& pass "sanitized run envelope is spooled before optional delivery" \
|| fail "control-plane delivery spool was not created"
# ── C2: policy-violating prompt blocked at begin ─────────────────────────────
echo "===== C2: injection prompt blocked before model ====="